feat: implement new dialog and remove old one#1161
Conversation
WalkthroughThis update migrates all dialog and modal management across the application from a legacy display store ( Changes
Sequence Diagram(s)Centralized Dialog Flow (Old vs New)sequenceDiagram
participant User
participant VueComponent
participant DisplayStore
participant DialogV2Store
Note over User,VueComponent: Old Dialog Flow
User->>VueComponent: Triggers dialog action
VueComponent->>DisplayStore: Set dialogOption, showDialog = true
User->>DisplayStore: Interacts with dialog
DisplayStore-->>VueComponent: onDialogDismiss()
Note over User,VueComponent: New Dialog Flow
User->>VueComponent: Triggers dialog action
VueComponent->>DialogV2Store: openDialog(options)
User->>DialogV2Store: Interacts with dialog
DialogV2Store-->>VueComponent: onDialogDismiss()
Example: Multi-step Dialog with Teleport InputsequenceDiagram
participant User
participant VueComponent
participant DialogV2Store
User->>VueComponent: Initiates action (e.g., transfer ownership)
VueComponent->>DialogV2Store: openDialog(step 1)
User->>DialogV2Store: Confirms step 1
DialogV2Store-->>VueComponent: onDialogDismiss()
VueComponent->>DialogV2Store: openDialog(step 2, Teleport input rendered)
User->>DialogV2Store: Fills input, confirms
DialogV2Store-->>VueComponent: onDialogDismiss()
VueComponent->>VueComponent: Proceeds with action based on input
Poem
📜 Recent review detailsConfiguration used: CodeRabbit UI 📒 Files selected for processing (5)
✅ Files skipped from review due to trivial changes (1)
🚧 Files skipped from review as they are similar to previous changes (3)
🔇 Additional comments (5)
✨ Finishing Touches
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. 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 (
|
There was a problem hiding this comment.
Actionable comments posted: 15
🧹 Nitpick comments (11)
src/modules/auth.ts (2)
40-40: Remove leftover debug statement or switch to structured loggingA commented-out
console.logis typically just noise in the codebase.
Drop the line entirely or replace it with the project’s logger (e.g.logger.debug('set user', data)) behind an environment flag.- // console.log('set user', data)
68-72: Add error-handling for the asynchronous plan fetch
getPlans()is fired and silently ignored on failure. If the request rejects, the user store stays in an indeterminate state and the UI may render incorrectly.- getPlans().then((pls) => { - main.plans = pls - }) + getPlans() + .then(pls => { main.plans = pls }) + .catch(err => console.error('Failed to load plans', err))At a minimum, log the error; ideally surface a toast/notification and consider retry/back-off logic.
messages/zh-cn.json (1)
93-96: Minor placeholder mismatch riskThe English key
"available-versions"uses “bundles”, but the Chinese translation is"可用的捆绑包".
All good semantically, but double-check where this string is concatenated with counts; the plural noun “捆绑包” is correct only when a number follows.
No change required if UI already handles pluralisation.messages/it.json (1)
16-16: Consider using "account" instead of "conto"In Italian IT contexts, "account" is more commonly used than "conto". This would also maintain consistency with other technical terms that remain in English.
- "account": "conto", + "account": "account",src/pages/settings/Account.vue (1)
273-276: Consider adding verification code format validationWhile removing spaces is good, consider validating that the code is exactly 6 digits before attempting verification.
handler: async () => { // User has clicked the "verify button - let's check" const verifyCode = mfaVerificationCode.value.replace(' ', '') + + // Validate code format + if (!/^\d{6}$/.test(verifyCode.trim())) { + toast.error(t('mfa-invalid-code')) + return false + } const { data: challenge, error: challengeError } = await supabase.auth.mfa.challenge({ factorId: data.id })src/components/tables/BundleTable.vue (1)
128-145: Consider renamingdidCancelfunction for clarityThe function name
didCancelis misleading since it can return a deletion method string ('normal' or 'unsafe') when the user doesn't cancel. Consider a more descriptive name.-async function didCancel(name: string, isPlural = false, askForMethod = true): Promise<boolean | 'normal' | 'unsafe'> { +async function getDeletionMethodOrCancel(name: string, isPlural = false, askForMethod = true): Promise<boolean | 'normal' | 'unsafe'> {Also update all references to this function throughout the file.
messages/fr.json (1)
100-100: Remove trailing colons from label translations for consistency.These label translations have trailing colons which is inconsistent with other labels in the file. Labels should not include punctuation as it's typically added by the UI component.
Apply this diff to fix the inconsistency:
- "bandwith-usage": "Utilisation de la bande passante:", + "bandwith-usage": "Utilisation de la bande passante",- "mau-usage": "Utilisation des utilisateurs actifs mensuels:", + "mau-usage": "Utilisation des utilisateurs actifs mensuels",- "storage-usage": "Utilisation du stockage:", + "storage-usage": "Utilisation du stockage",- "your-ussage": "Votre utilisation:", + "your-ussage": "Votre utilisation",Also applies to: 404-404, 603-603, 688-688
src/pages/settings/organization/Members.vue (2)
43-43: Remove unnecessary reactivity for static environment variable.The
captchaKeydoesn't need to be a reactive ref sinceimport.meta.envvalues are static at build time.Apply this diff to simplify:
-const captchaKey = ref(import.meta.env.VITE_CAPTCHA_KEY) +const captchaKey = import.meta.env.VITE_CAPTCHA_KEYThen update the template usage:
-<VueTurnstile v-if="captchaKey" ref="captchaElement" v-model="captchaToken" size="flexible" :site-key="captchaKey" /> +<VueTurnstile v-if="captchaKey" ref="captchaElement" v-model="captchaToken" size="flexible" :site-key="captchaKey" />
572-587: Enhance error handling with specific error details.The Edge Function error handling could provide more specific error information to help diagnose issues.
Apply this diff to improve error handling:
const { error } = await supabase.functions.invoke('private/invite_new_user_to_org', { body: { email: inviteUserEmail.value, org_id: inviteUserOrgId.value, invite_type: inviteType, captcha_token: captchaToken.value, first_name: inviteUserFirstName.value, last_name: inviteUserLastName.value, }, }) if (error) { console.error('Invitation failed:', error) - toast.error(t('invitation-failed', 'Invitation failed')) + const errorMessage = error.message || t('invitation-failed', 'Invitation failed') + toast.error(errorMessage) return false }src/pages/app/p/[package].channel.[channel].vue (1)
630-632: Reduce debounce delay for better user experience.The 500ms debounce delay might feel sluggish to users when searching for bundles.
Apply this diff to improve search responsiveness:
const debouncedRefreshFilteredVersions = useDebounceFn(() => { refreshFilteredVersions() -}, 500) +}, 300)src/pages/app/p/[package].bundle.[bundle].vue (1)
256-259: Enhance error handling with specific error detailsConsider logging the actual error for debugging purposes.
catch (error) { console.error(error) - toast.error(t('cannot-test-app-some')) + toast.error(t('cannot-test-app-some')) + console.error('Failed to link channel:', error) }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (48)
.vscode/settings.json(1 hunks)messages/de.json(2 hunks)messages/en.json(25 hunks)messages/es.json(1 hunks)messages/fr.json(14 hunks)messages/id.json(3 hunks)messages/it.json(2 hunks)messages/ja.json(2 hunks)messages/ko.json(2 hunks)messages/pl.json(3 hunks)messages/pt-br.json(1 hunks)messages/ru.json(2 hunks)messages/tr.json(1 hunks)messages/vi.json(2 hunks)messages/zh-cn.json(23 hunks)src/App.vue(0 hunks)src/auto-imports.d.ts(0 hunks)src/components/BundleLinkDialog.vue(0 hunks)src/components/Dialog.vue(0 hunks)src/components/DialogV2.vue(1 hunks)src/components/InviteNewUserWithoutAccountDialog.vue(0 hunks)src/components/dashboard/AppSetting.vue(18 hunks)src/components/dashboard/DropdownOrganization.vue(8 hunks)src/components/dashboard/DropdownProfile.vue(6 hunks)src/components/dashboard/StepsApp.vue(3 hunks)src/components/dashboard/StepsBundle.vue(3 hunks)src/components/tables/BundleTable.vue(12 hunks)src/components/tables/ChannelTable.vue(8 hunks)src/components/tables/HistoryTable.vue(4 hunks)src/modules/auth.ts(1 hunks)src/pages/ApiKeys.vue(9 hunks)src/pages/app/p/[package].bundle.[bundle].vue(10 hunks)src/pages/app/p/[package].channel.[channel].vue(17 hunks)src/pages/app/p/[package].d.[device].vue(4 hunks)src/pages/delete_account.vue(2 hunks)src/pages/demo_dialog.vue(5 hunks)src/pages/forgot_password.vue(3 hunks)src/pages/settings/Account.vue(10 hunks)src/pages/settings/ChangePassword.vue(3 hunks)src/pages/settings/organization/Members.vue(13 hunks)src/pages/settings/organization/Plans.vue(4 hunks)src/pages/settings/organization/Usage.vue(3 hunks)src/pages/settings/organization/index.vue(8 hunks)src/services/stripe.ts(6 hunks)src/stores/display.ts(1 hunks)src/typed-router.d.ts(1 hunks)tests/cli-channel.test.ts(1 hunks)vitest.config.ts(1 hunks)
💤 Files with no reviewable changes (5)
- src/auto-imports.d.ts
- src/App.vue
- src/components/Dialog.vue
- src/components/BundleLinkDialog.vue
- src/components/InviteNewUserWithoutAccountDialog.vue
🧰 Additional context used
🪛 GitHub Check: Run tests
tests/cli-channel.test.ts
[failure] 500-500: tests/cli-channel.test.ts > tests CLI channel commands > channel deletion > should delete channel and associated channel_devices
AssertionError: expected '\u001b[90m┌\u001b[39m Delete channel…' to contain 'Done ✅'
- Expected
- Received
- Done ✅
- ┌ Delete channel
- │
- ● Using custom supabase instance from provided options
- │
- ● Deleting channel com.cli_channel_5ece92a3-8637-45cd-baf9-a54e045414ae#test-channel-24b5b480 from Capgo
- │
- ■ Cannot delete Channel 🙀
- │ code: 23503
- │ details: Key is still referenced from table "channel_devices".
- │ hint: null
- │ message: update or delete on table "channels" violates foreign key constraint "channel_devices_channel_id_fkey" on table "channel_devices"
❯ tests/cli-channel.test.ts:500:22
[failure] 500-500: tests/cli-channel.test.ts > tests CLI channel commands > channel deletion > should delete channel and associated channel_devices
AssertionError: expected '\u001b[90m┌\u001b[39m Delete channel…' to contain 'Done ✅'
- Expected
- Received
- Done ✅
- ┌ Delete channel
- │
- ● Using custom supabase instance from provided options
- │
- ● Deleting channel com.cli_channel_5ece92a3-8637-45cd-baf9-a54e045414ae#test-channel-8a9e5835 from Capgo
- │
- ■ Cannot delete Channel 🙀
- │ code: 23503
- │ details: Key is still referenced from table "channel_devices".
- │ hint: null
- │ message: update or delete on table "channels" violates foreign key constraint "channel_devices_channel_id_fkey" on table "channel_devices"
❯ tests/cli-channel.test.ts:500:22
[failure] 461-461: tests/cli-channel.test.ts > tests CLI channel commands > channel deletion > should delete channel and associated channel_devices
Error: Test timed out in 20000ms.
If this is a long-running test, pass a timeout value as the last argument or configure it globally with "testTimeout".
❯ tests/cli-channel.test.ts:461:8
🪛 GitHub Actions: Run tests
tests/cli-channel.test.ts
[error] 461-500: Test timed out in 20000ms. The test 'should delete channel and associated channel_devices' failed due to a foreign key constraint violation preventing deletion of a channel because it is still referenced from table 'channel_devices'. Expected output to contain 'Done ✅' but received an error indicating 'Cannot delete Channel' with code 23503.
🔇 Additional comments (67)
vitest.config.ts (1)
7-12: ```shell
#!/bin/bash
set -eLocate vitest.config.ts
CONFIG_FILE=$(fd vitest.config.ts | head -n 1)
echo "Config file path: $CONFIG_FILE"Show the first 50 lines to inspect commented sections
echo "----- First 50 lines of $CONFIG_FILE -----"
sed -n '1,50p' "$CONFIG_FILE"Search for commented-out reporters and coverage blocks
echo "----- Commented-out reporters -----"
rg -n "//\s*reporters" "$CONFIG_FILE" || echo "No commented-out 'reporters' found"echo "----- Commented-out coverage -----"
rg -n "//\s*coverage" "$CONFIG_FILE" || echo "No commented-out 'coverage' found"Search for active reporters and coverage settings
echo "----- Active reporters settings -----"
rg -n "reporters\s*:" "$CONFIG_FILE" || echo "No active 'reporters' setting found"echo "----- Active coverage settings -----"
rg -n "coverage\s*:" "$CONFIG_FILE" || echo "No active 'coverage' setting found"</details> <details> <summary>src/components/DialogV2.vue (1)</summary> `87-93`: **Style update LGTM – confirm visual contrast of new `btn-outline`** Switching the “cancel” role to `btn-outline` is fine; just verify it still meets WCAG contrast in both light & dark themes. No functional concerns. </details> <details> <summary>.vscode/settings.json (1)</summary> `4-7`: **Nice i18n-ally refinement** Setting the source language and restricting frameworks will cut down noise from the extension – looks good. </details> <details> <summary>src/typed-router.d.ts (1)</summary> `49-49`: **LGTM! Standard route addition for Webhooks functionality.** The new `/Webhooks` route entry follows the established patterns and is properly typed with no route parameters. </details> <details> <summary>src/components/dashboard/StepsBundle.vue (3)</summary> `9-12`: **LGTM! Proper imports for the dialog refactoring.** The addition of `useDialogV2Store` and `useOrganizationStore` imports aligns with the new dialog management system. --- `30-30`: **LGTM! Consistent store initialization.** The `dialogStore` initialization follows the established pattern. --- `95-106`: **LGTM! Proper dialog refactoring implementation.** The dialog configuration correctly uses the new API with: - `title` instead of `header` - `description` instead of `message` - Proper `buttons` array structure - Async dismissal handling with `await dialogStore.onDialogDismiss()` This follows the standardized dialog pattern used across the codebase. </details> <details> <summary>src/pages/settings/organization/Usage.vue (4)</summary> `7-7`: **LGTM! Added router imports for navigation.** The addition of `useRoute` and `useRouter` imports supports the existing navigation logic. --- `13-13`: **LGTM! Dialog store import for refactoring.** The `useDialogV2Store` import is correctly added for the new dialog system. --- `25-25`: **LGTM! Proper store initialization.** The `dialogStore` initialization follows the established pattern. --- `172-182`: **LGTM! Correct dialog refactoring with preserved logic.** The dialog configuration properly uses: - `title` and `description` instead of the old keys - Proper `buttons` array structure - Async dismissal handling The permission check and navigation logic is correctly preserved after the dialog refactoring. </details> <details> <summary>src/pages/app/p/[package].d.[device].vue (3)</summary> `17-17`: **LGTM! Dialog store import for refactoring.** The `useDialogV2Store` import is correctly added for the new dialog system. --- `35-35`: **LGTM! Proper store initialization.** The `dialogStore` initialization follows the established pattern. --- `232-248`: **LGTM! Correct dialog refactoring with preserved return behavior.** The `didCancel` function correctly: - Uses `dialogStore.openDialog()` with the new API structure - Maintains proper `title`, `description`, and `buttons` configuration - Returns the dismissal promise as expected by calling code - Preserves the original function's behavior while adopting the new dialog system </details> <details> <summary>src/components/tables/HistoryTable.vue (3)</summary> `10-10`: **LGTM! Dialog store import for refactoring.** The `useDialogV2Store` import is correctly added for the new dialog system. --- `48-48`: **LGTM! Proper store initialization.** The `dialogStore` initialization follows the established pattern. --- `240-277`: **LGTM! Comprehensive dialog refactoring with enhanced button handling.** The rollback dialog correctly implements the new dialog API with: - Proper `title` and `description` configuration - Well-structured `buttons` array with explicit roles (`primary` and `cancel`) - Inline handler function for the confirm button that preserves the rollback logic - Async dismissal handling The permission checks and rollback functionality are correctly preserved while adopting the new dialog system. </details> <details> <summary>src/pages/delete_account.vue (2)</summary> `12-12`: **LGTM: Clean migration to new dialog store** The migration from `useDisplayStore` to `useDialogV2Store` is implemented correctly with proper imports and initialization. Also applies to: 16-16 --- `24-25`: **LGTM: Proper dialog API migration** The dialog invocation correctly uses the new API pattern: - `header` → `title` property rename - `dialogStore.openDialog()` and `dialogStore.onDialogDismiss()` usage This aligns with the broader refactoring effort across the codebase. Also applies to: 84-85 </details> <details> <summary>src/components/dashboard/StepsApp.vue (2)</summary> `9-9`: **LGTM: Correct store imports and initialization** The migration includes proper imports for `useDialogV2Store` and `useOrganizationStore` with correct store initialization. Also applies to: 12-12, 29-29 --- `91-101`: **LGTM: Proper dialog API transformation** The dialog invocation correctly migrates to the new API: - `header` → `title` - `message` → `description` - Uses `dialogStore.openDialog()` and `dialogStore.onDialogDismiss()` The migration is consistent with the broader refactoring pattern. </details> <details> <summary>src/pages/demo_dialog.vue (3)</summary> `2-2`: **LGTM: Proper internationalization setup** The `useI18n` import and initialization correctly enables internationalization support for the demo dialog component. Also applies to: 7-7 --- `33-33`: **LGTM: Consistent internationalization implementation** Dialog titles and button texts are properly internationalized using the `t()` function with appropriate translation keys: - `'dialog-with-custom-input'` - `'user-registration'` - `'cancel'` - `'register'` Also applies to: 77-77, 81-81, 85-85 --- `170-170`: **LGTM: Improved teleport logic with optimization** The conditional checks for teleport content correctly use translated strings for comparison. The addition of the `defer` attribute on line 170 is a good optimization for rendering performance. Also applies to: 188-188 </details> <details> <summary>src/services/stripe.ts (2)</summary> `5-5`: **LGTM: Correct dialog store migration setup** The migration from `useDisplayStore` to `useDialogV2Store` is properly implemented with correct imports and store initialization in both functions. Also applies to: 10-10, 40-40 --- `12-28`: **LGTM: Enhanced dialog API implementation** Both functions correctly migrate to the new dialog API with: - `header` → `title` property rename - `message` → `description` property rename (in `openPortal`) - Addition of `role: 'primary'` for better button semantics - Proper use of `dialogStore.openDialog()` and `dialogStore.onDialogDismiss()` The migration maintains the original functionality while improving the dialog interface consistency. Also applies to: 54-76 </details> <details> <summary>messages/en.json (1)</summary> `17-17`: **LGTM! Comprehensive localization improvements.** The additions and updates to English localization strings properly support the new dialog system and UI improvements. The new keys cover dialogs, user management, bundle/channel operations, and error handling scenarios. Also applies to: 78-78, 93-96, 112-121, 125-125, 178-178, 201-201, 208-210, 216-217, 220-220, 241-242, 244-248, 262-262, 269-269, 275-275, 298-300, 303-304, 320-321, 338-339, 350-350, 356-356, 391-391, 469-469, 517-517, 526-526, 534-534, 538-540, 552-552, 558-559, 567-568, 570-572, 574-575, 580-583, 586-586, 599-599, 616-616, 622-625, 629-630, 632-635, 660-662, 664-664, 668-668 </details> <details> <summary>src/components/dashboard/DropdownProfile.vue (4)</summary> `9-9`: **LGTM! Proper migration to new dialog store.** The import and initialization of `useDialogV2Store` is correctly implemented, replacing the old `useDisplayStore` approach. Also applies to: 15-15, 28-28 --- `30-56`: **LGTM! Well-implemented dialog handling with reactive input.** The `openLogAsDialog` function correctly: - Resets the input value before opening the dialog - Uses the new dialog API with proper configuration - Handles user input through the reactive `logAsInput` variable - Awaits dialog dismissal before proceeding The dialog configuration properly includes title, buttons with roles, and a handler that captures the input value. --- `113-132`: **LGTM! Consistent dialog pattern for logout confirmation.** The logout dialog follows the same pattern as the log-as dialog, using the new dialog store API correctly with proper button configuration and handlers. --- `183-194`: **LGTM! Proper Teleport implementation for dialog content.** The Teleport block correctly: - Conditionally renders based on dialog state and title - Targets the correct dialog content container - Uses proper Vue input binding with `v-model` - Includes appropriate placeholder and styling - Prevents form submission on enter key The implementation follows Vue 3 best practices for teleporting content. </details> <details> <summary>messages/pt-br.json (2)</summary> `3-690`: **LGTM! Comprehensive Portuguese localization improvements.** The Brazilian Portuguese translations have been significantly improved with: - Better natural language phrasing - Consistent terminology usage - Proper punctuation and capitalization - Enhanced clarity in technical terms - Complete coverage of new UI elements The translations appear to maintain consistency with the application's tone and style while being more natural in Portuguese. --- `2-2`: **Verify the Portuguese schema URL.** The schema URL has been changed to a Portuguese-specific version. Please ensure this URL is valid and properly serves the Portuguese localization schema. ```web Does the URL https://inlang.com/schema/formato-de-mensagem-inlang exist and serve the correct Portuguese message format schema?src/components/tables/ChannelTable.vue (4)
5-5: LGTM! Proper imports and store initialization.The component correctly imports FormKit and migrates to the new
useDialogV2Store, with proper reactive variable setup for the new channel name input.Also applies to: 16-16, 41-41, 53-53
60-76: LGTM! Proper dialog confirmation implementation.The
didCancelfunction correctly uses the new dialog API with proper button configuration and role assignment. The function returns the dialog dismissal promise for proper async handling.
206-216: LGTM! Important data integrity improvement.The addition of deleting
channel_devicesbefore deleting the channel is a crucial data integrity improvement. This prevents orphaned records and maintains referential integrity. The error handling properly aborts the operation if device deletion fails.
352-360: LGTM! Well-implemented FormKit integration with Teleport.The Teleport implementation correctly:
- Conditionally renders based on dialog state and title
- Uses FormKit for consistent form styling
- Includes proper placeholder text
- Targets the correct dialog content container
The FormKit integration maintains consistency with the application's form styling.
src/pages/settings/organization/Plans.vue (2)
214-228: LGTM: Dialog migration implemented correctlyThe migration from
displayStoretodialogStoreis properly implemented. The dialog options correctly use the new structure withtitle,description, andbuttons, and the dismissal handling usesawait dialogStore.onDialogDismiss().
300-308: LGTM: Usage details dialog properly migratedThe information dialog for detailed usage plan follows the new dialog pattern correctly. The button structure and dialog dismissal are properly implemented.
src/stores/display.ts (1)
1-29: LGTM: Complete dialog cleanupThe removal of all dialog-related state and functionality from the display store is clean and complete. The store now focuses solely on toast notifications, navigation, and selection state, which is appropriate given the migration to the new dialog system.
src/pages/settings/ChangePassword.vue (2)
48-71: LGTM: Proper 2FA dialog implementationThe 2FA dialog implementation correctly uses the new dialog store pattern. The error handling properly returns
falseto prevent dialog closure on verification failure, which provides good UX.
147-165: LGTM: Well-implemented Teleport for 2FA inputThe Teleport component correctly renders the 2FA input only when the specific dialog is shown. The input includes proper attributes (maxlength, inputmode) and clear user instructions.
src/components/dashboard/DropdownOrganization.vue (2)
123-170: LGTM: Proper organization creation dialog with validationThe dialog implementation includes proper input validation that shows a user-friendly error message and prevents dialog closure when the organization name is empty. The error handling for duplicate names also correctly prevents dialog closure.
208-218: LGTM: Clean Teleport implementation for organization inputThe Teleport component properly conditionally renders the organization name input field with appropriate styling and prevents form submission on Enter key press.
messages/pl.json (1)
1-691: LGTM: Comprehensive Polish localization updatesThe extensive Polish localization updates appropriately support the new dialog system and UI improvements. The new translation keys for 2FA, user invitations, channel management, and error handling align well with the functionality described in the PR summary.
messages/ru.json (1)
1-690: Excellent localization improvements!The Russian translation updates are comprehensive and well-executed. The changes demonstrate:
- Consistent terminology usage throughout (e.g., consistently using "пакет" for bundle, "ключ API" for API key)
- Improved grammar and natural phrasing that makes the interface more user-friendly
- Proper schema URL localization
- Addition of new keys supporting expanded UI features like captcha handling, user invitations, and dialog management
The translations maintain professional quality while improving clarity and user experience for Russian-speaking users.
src/pages/forgot_password.vue (4)
12-21: Good refactor to centralized dialog management.The migration from
useDisplayStoretouseDialogV2Storeimproves dialog state management consistency across the application. The explicitmfaCodereactive variable provides better control over MFA input compared to implicit dialog input handling.
80-103: Improved MFA dialog implementation with good error handling.The refactored MFA dialog implementation has several improvements:
- Structured dialog options with clear title and description
- Proper error handling that keeps the dialog open on invalid codes (
return false)- Input sanitization with space removal for 6-digit codes
- Consistent button roles with the new dialog system
The explicit state management and error handling patterns provide better user experience compared to the previous implementation.
235-253: Well-implemented Teleport for dialog content.The Teleport implementation for the MFA input is well-executed:
- Proper conditional rendering based on dialog state and title matching
- Good UX attributes:
maxlength="6",inputmode="numeric"for 6-digit codes- Appropriate styling and accessibility considerations
- Proper reactive binding to
mfaCode- Internationalized placeholder text
This pattern provides explicit control over dialog content rendering while maintaining clean separation of concerns.
1-261: Successful dialog system migration maintaining security and improving UX.The migration from
useDisplayStoretouseDialogV2Storeis well-executed and maintains all security considerations while improving the user experience:
- MFA verification still uses proper validation and error handling
- Explicit reactive state management improves code clarity
- Dialog content rendering via Teleport provides better control
- Consistent patterns that align with the broader codebase refactor
This change is part of a systematic improvement to dialog management across the application.
messages/es.json (1)
1-691: Excellent Spanish localization enhancements!The Spanish translation updates demonstrate high localization quality:
- Consistent terminology throughout (e.g., "paquete" for bundle, "clave API" for API key)
- Natural Spanish phrasing that improves user experience
- Proper schema URL localization for Spanish
- Comprehensive addition of new keys supporting expanded UI features
- Professional grammar and clarity improvements
These updates significantly enhance the Spanish user experience while maintaining translation consistency across the application.
src/pages/settings/organization/index.vue (4)
12-21: Good architectural improvements for dialog management.The migration to
useDialogV2Storeand explicitdeleteInputreactive variable improves the organization settings implementation:
- Consistent dialog management patterns with the rest of the application
- Explicit state management for destructive operations enhances security
- Better separation of concerns between dialog presentation and business logic
45-71: Well-structured action sheet implementation.The photo selection action sheet dialog is properly implemented:
- Clear button hierarchy with appropriate roles (primary, secondary, cancel)
- Proper async handling with
dialogStore.onDialogDismiss()- Maintained functionality from the original implementation
- Clean separation between dialog presentation and photo handling logic
173-214: Excellent security implementation for destructive organization deletion.The organization deletion dialog demonstrates strong security practices:
- Input validation: Requires exact organization name match to prevent accidental deletions
- Error handling: Proper error feedback and dialog state management (
return falseon errors)- User feedback: Clear success/error messages with localized text
- Safe navigation: Only redirects after successful deletion and state updates
- Role-based security: Confirms user permissions before allowing deletion
The validation requiring the user to type the exact organization name is a critical safety measure for this destructive operation.
226-237: Good UX patterns for clipboard operations and dialog input.Both implementations demonstrate good user experience practices:
Copy functionality (226-237):
- Graceful fallback when clipboard API fails
- User-friendly error dialog displaying the organization ID
- Proper error logging for debugging
Deletion input Teleport (347-358):
- Consistent conditional rendering pattern
- Proper input attributes and styling
- Prevention of accidental form submission with Enter key
These patterns enhance the robustness and usability of the organization settings interface.
Also applies to: 347-358
src/pages/settings/Account.vue (3)
36-110: LGTM! Dialog refactoring implemented correctlyThe deleteAccount function properly uses the new dialogStore with appropriate title, button configuration, and awaits dialog dismissal.
238-307: Well-structured MFA dialog flowThe two-step MFA enablement process is cleanly implemented with proper state management and error handling. Good use of returning
falsefrom handlers to prevent dialog closure on validation failures.
533-550: Teleport implementation for MFA dialog is correctGood use of conditional rendering based on dialog title, proper v-model binding, and enter key prevention.
src/components/tables/BundleTable.vue (2)
56-170: Excellent modularization of dialog functionsThe separation of deletion workflow into distinct dialog functions (
showDeletionMethodDialog,showDeleteConfirmationDialog,showUnlinkDialog) improves code readability and maintainability. Each function has a clear purpose and proper return values.
584-602: Good implementation of deletion style dialog contentThe Teleport block properly renders additional context for the deletion style dialog, including recommendations and helpful documentation links.
src/pages/ApiKeys.vue (2)
282-344: Well-implemented API key creation with proper validationThe
createApiKeyfunction properly validates organization and app selections when limitations are enabled, with appropriate error messages and return values for dialog control.
577-584: Good UX logic for checkbox dependenciesThe watcher correctly resets app limitations when organization limitation is disabled, maintaining logical consistency in the UI.
src/components/dashboard/AppSetting.vue (1)
333-430: Well-implemented multi-step dialog flow!The app transfer ownership flow is excellently structured with:
- Clear step progression
- Proper permission checks
- 32-day cooldown validation
- App ID confirmation for safety
- Good error handling throughout
src/pages/app/p/[package].bundle.[bundle].vue (3)
532-656: Well-implemented bundle deletion logicThe function has excellent error handling, permission checking, and user feedback. The channel unlinking logic before deletion is particularly well thought out.
828-1048: Excellent use of Teleport for dialog contentThe teleport sections are well-organized and properly conditionally rendered based on dialog state. This is a clean implementation of the dialog system migration.
186-186: Fix reactive ref assignmentDirect assignment to ref should use
.value.- selectedChannelForLink.value = null + selectedChannelForLink.value = nullWait, I see the code already has
.value. Let me re-examine... Actually, the code is correct as written.messages/de.json (1)
1-690: High-quality German localization updatesThe German translations are well-written with proper grammar and consistent terminology. The new dialog-related keys are correctly added and the schema URL is properly formatted.
| @@ -1,181 +1,190 @@ | |||
| { | |||
| "$schema": "https://inlang.com/schema/inlang-message-format", | |||
| "$schema": "https://inlang.com/schema/format-pesan-inlang", | |||
There was a problem hiding this comment.
$schema URL deviates from canonical inlang schema – likely to break tooling
The value "https://inlang.com/schema/format-pesan-inlang" does not match the canonical URL (https://inlang.com/schema/inlang-message-format) used in every other locale file.
Editors / CI plugins relying on the schema will fail to validate this file.
-"$schema": "https://inlang.com/schema/format-pesan-inlang",
+"$schema": "https://inlang.com/schema/inlang-message-format",📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| "$schema": "https://inlang.com/schema/format-pesan-inlang", | |
| "$schema": "https://inlang.com/schema/inlang-message-format", |
🤖 Prompt for AI Agents
In messages/id.json at line 2, the $schema URL is incorrect and differs from the
canonical inlang schema URL. Replace the current value
"https://inlang.com/schema/format-pesan-inlang" with the correct canonical URL
"https://inlang.com/schema/inlang-message-format" to ensure proper validation by
editors and CI tools.
| "2fa-code": "2FA kimlik doğrulama kodu", | ||
| "2fa-disabled": "2FA devre dışı bırakıldı", | ||
| "6-characters-minimum": "Minimum 6 karakter, 1 büyük harf, 1 küçük harf, 1 özel karakter", | ||
| "$schema": "https://inlang.com/schema/inlang-message-format\n\nThis is a URL and it cannot be translated.", |
There was a problem hiding this comment.
$schema contains embedded text and line-breaks – JSON schema reference becomes invalid
The schema value currently is:
"https://inlang.com/schema/inlang-message-format\n\nThis is a URL and it cannot be translated."
This concatenates the URL with explanatory text, resulting in an invalid (and multi-line) URI.
Down-stream tooling that tries to fetch the schema will choke.
-"$schema": "https://inlang.com/schema/inlang-message-format\n\nThis is a URL and it cannot be translated.",
+"$schema": "https://inlang.com/schema/inlang-message-format",📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| "$schema": "https://inlang.com/schema/inlang-message-format\n\nThis is a URL and it cannot be translated.", | |
| "$schema": "https://inlang.com/schema/inlang-message-format", |
🤖 Prompt for AI Agents
In messages/tr.json at line 2, the $schema value incorrectly includes
explanatory text and line breaks after the URL, making the JSON schema reference
invalid. Remove the extra text and line breaks so that $schema contains only the
valid URL string "https://inlang.com/schema/inlang-message-format" without any
additional characters or newlines.
| it.concurrent('should delete channel and associated channel_devices', async () => { | ||
| const channelName = generateChannelName() | ||
| await createChannel(channelName, APPNAME) | ||
|
|
||
| // Get the channel ID | ||
| const { data: channelData } = await getSupabaseClient() | ||
| .from('channels') | ||
| .select('id') | ||
| .eq('name', channelName) | ||
| .eq('app_id', APPNAME) | ||
| .single() | ||
| .throwOnError() | ||
|
|
||
| const channelId = channelData!.id | ||
|
|
||
| // Create some channel_devices | ||
| const deviceIds = [randomUUID(), randomUUID(), randomUUID()] | ||
| for (const deviceId of deviceIds) { | ||
| await getSupabaseClient() | ||
| .from('channel_devices') | ||
| .insert({ | ||
| channel_id: channelId, | ||
| device_id: deviceId, | ||
| app_id: APPNAME, | ||
| owner_org: ORG_ID, | ||
| }) | ||
| .throwOnError() | ||
| } | ||
|
|
||
| // Verify channel_devices were created | ||
| const { data: devicesBefore } = await getSupabaseClient() | ||
| .from('channel_devices') | ||
| .select('*') | ||
| .eq('channel_id', channelId) | ||
| expect(devicesBefore).toHaveLength(3) | ||
|
|
||
| // Delete the channel | ||
| const output = await runCli(['channel', 'delete', channelName, APPNAME], APPNAME, false, undefined, true, true) | ||
| expect(output).toContain(`Deleting channel ${APPNAME}#${channelName} from Capgo`) | ||
| expect(output).toContain(`Done ✅`) | ||
|
|
||
| // Verify channel is deleted | ||
| const { data: channelAfter, error: channelError } = await getSupabaseClient() | ||
| .from('channels') | ||
| .select('*') | ||
| .eq('name', channelName) | ||
| .eq('app_id', APPNAME) | ||
| .single() | ||
| expect(channelError).toBeDefined() | ||
| expect(channelAfter).toBeNull() | ||
|
|
||
| // Verify channel_devices are also deleted | ||
| const { data: devicesAfter } = await getSupabaseClient() | ||
| .from('channel_devices') | ||
| .select('*') | ||
| .eq('channel_id', channelId) | ||
| expect(devicesAfter).toHaveLength(0) | ||
| }) |
There was a problem hiding this comment.
🧩 Verification correct
Critical Issue: Test fails due to missing cascade delete implementation in CLI
The test expects the CLI channel deletion command to automatically delete associated channel_devices entries, but the pipeline failures show foreign key constraint violations (error code 23503). The CLI implementation doesn't handle cascading deletes, causing this test to fail consistently.
The CLI channel deletion command needs to be updated to handle cascading deletes before this test can pass. Either:
- Update the CLI implementation to delete
channel_devicesentries before deleting the channel - Modify the test to reflect the current CLI behavior (not recommended as cascading deletes are likely desired functionality)
🏁 Script executed:
#!/bin/bash
# Description: Check if the CLI channel delete command properly handles cascading deletes
# Search for the CLI channel deletion implementation
ast-grep --pattern $'function $_ {
$$$
delete $$$
$$$
}'
# Look for any existing cascade delete logic
rg -A 10 -B 5 "channel.*delete|delete.*channel" --type tsLength of output: 24937
Critical Issue: Test fails due to missing cascade delete implementation in CLI
The test expects the CLI channel deletion command to automatically delete associated channel_devices entries, but the pipeline failures show foreign key constraint violations (error code 23503). The CLI implementation doesn't handle cascading deletes, causing this test to fail consistently.
The CLI channel deletion command needs to be updated to handle cascading deletes before this test can pass. Either:
- Update the CLI implementation to delete
channel_devicesentries before deleting the channel - Modify the test to reflect the current CLI behavior (not recommended as cascading deletes are likely desired functionality)
#!/bin/bash
# Description: Check if the CLI channel delete command properly handles cascading deletes
# Search for the CLI channel deletion implementation
ast-grep --pattern $'function $_ {
$$$
delete $$$
$$$
}'
# Look for any existing cascade delete logic
rg -A 10 -B 5 "channel.*delete|delete.*channel" --type ts🧰 Tools
🪛 GitHub Check: Run tests
[failure] 500-500: tests/cli-channel.test.ts > tests CLI channel commands > channel deletion > should delete channel and associated channel_devices
AssertionError: expected '\u001b[90m┌\u001b[39m Delete channel…' to contain 'Done ✅'
- Expected
- Received
- Done ✅
- ┌ Delete channel
- │
- ● Using custom supabase instance from provided options
- │
- ● Deleting channel com.cli_channel_5ece92a3-8637-45cd-baf9-a54e045414ae#test-channel-24b5b480 from Capgo
- │
- ■ Cannot delete Channel 🙀
- │ code: 23503
- │ details: Key is still referenced from table "channel_devices".
- │ hint: null
- │ message: update or delete on table "channels" violates foreign key constraint "channel_devices_channel_id_fkey" on table "channel_devices"
❯ tests/cli-channel.test.ts:500:22
[failure] 500-500: tests/cli-channel.test.ts > tests CLI channel commands > channel deletion > should delete channel and associated channel_devices
AssertionError: expected '\u001b[90m┌\u001b[39m Delete channel…' to contain 'Done ✅'
- Expected
- Received
- Done ✅
- ┌ Delete channel
- │
- ● Using custom supabase instance from provided options
- │
- ● Deleting channel com.cli_channel_5ece92a3-8637-45cd-baf9-a54e045414ae#test-channel-8a9e5835 from Capgo
- │
- ■ Cannot delete Channel 🙀
- │ code: 23503
- │ details: Key is still referenced from table "channel_devices".
- │ hint: null
- │ message: update or delete on table "channels" violates foreign key constraint "channel_devices_channel_id_fkey" on table "channel_devices"
❯ tests/cli-channel.test.ts:500:22
[failure] 461-461: tests/cli-channel.test.ts > tests CLI channel commands > channel deletion > should delete channel and associated channel_devices
Error: Test timed out in 20000ms.
If this is a long-running test, pass a timeout value as the last argument or configure it globally with "testTimeout".
❯ tests/cli-channel.test.ts:461:8
🪛 GitHub Actions: Run tests
[error] 461-500: Test timed out in 20000ms. The test 'should delete channel and associated channel_devices' failed due to a foreign key constraint violation preventing deletion of a channel because it is still referenced from table 'channel_devices'. Expected output to contain 'Done ✅' but received an error indicating 'Cannot delete Channel' with code 23503.
🤖 Prompt for AI Agents
In tests/cli-channel.test.ts around lines 461 to 518, the test fails because the
CLI channel deletion command does not handle cascading deletes of associated
channel_devices, causing foreign key constraint errors. To fix this, update the
CLI channel delete command implementation to explicitly delete all
channel_devices linked to the channel before deleting the channel itself. This
ensures the database constraints are respected and the test passes as expected.
| "register-next": "Register", | ||
| "reload": "Reload", | ||
| "remove-bundle-from-channel": "Remove bundle from channel", | ||
| "remove-bundle-from-this-channel": "Remove budnle from this channel", |
There was a problem hiding this comment.
Fix the typo in the localization key.
There's a typo: "budnle" should be "bundle".
- "remove-bundle-from-this-channel": "Remove budnle from this channel",
+ "remove-bundle-from-this-channel": "Remove bundle from this channel",📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| "remove-bundle-from-this-channel": "Remove budnle from this channel", | |
| "remove-bundle-from-this-channel": "Remove bundle from this channel", |
🤖 Prompt for AI Agents
In messages/en.json at line 539, fix the typo in the string value by changing
"budnle" to "bundle" so the localization key reads "Remove bundle from this
channel".
| "select-bundle-action-for-channel": "Select bundle action for channel", | ||
| "select-channel": "Select channel", | ||
| "select-channel-msg": "Please select the channel that you would like to use in this overwrite", | ||
| "select-channel-to-link": "Select channek to link", |
There was a problem hiding this comment.
Fix the typo in the localization key.
There's a typo: "channek" should be "channel".
- "select-channel-to-link": "Select channek to link",
+ "select-channel-to-link": "Select channel to link",📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| "select-channel-to-link": "Select channek to link", | |
| "select-channel-to-link": "Select channel to link", |
🤖 Prompt for AI Agents
In messages/en.json at line 574, correct the typo in the string value by
changing "channek" to "channel" so the text reads "Select channel to link".
| async function refreshFilteredVersions() { | ||
| if (!channel.value) | ||
| return | ||
|
|
||
| if (bundleLinkSearchVal.value && bundleLinkSearchVal.value.trim()) { | ||
| const { data, error } = await supabase.from('app_versions') | ||
| .select('*') | ||
| .eq('app_id', channel.value.app_id) | ||
| .eq('deleted', false) | ||
| .neq('id', channel.value.version.id) | ||
| .order('created_at', { ascending: false }) | ||
| .like('name', `%${bundleLinkSearchVal.value.trim()}%`) | ||
| .limit(5) | ||
| if (error) { | ||
| console.error(error) | ||
| toast.error(t('error-fetching-versions')) | ||
| } | ||
| bundleLinkVersions.value = data ?? [] | ||
| } | ||
| else { | ||
| const { data, error } = await supabase.from('app_versions') | ||
| .select('*') | ||
| .eq('app_id', channel.value.app_id) | ||
| .eq('deleted', false) | ||
| .neq('id', channel.value.version.id) | ||
| .order('created_at', { ascending: false }) | ||
| .limit(5) | ||
| if (error) { | ||
| console.error(error) | ||
| toast.error(t('error-fetching-versions')) | ||
| } | ||
| bundleLinkVersions.value = data ?? [] | ||
| } | ||
| } |
There was a problem hiding this comment.
🛠️ Refactor suggestion
Add loading state for bundle search operations.
The async search operations should show a loading indicator to provide better user feedback.
Add a loading state ref:
const isBundleSearchLoading = ref(false)Then update the search function:
async function refreshFilteredVersions() {
if (!channel.value)
return
+
+ isBundleSearchLoading.value = true
+ try {
if (bundleLinkSearchVal.value && bundleLinkSearchVal.value.trim()) {
const { data, error } = await supabase.from('app_versions')
// ... query
if (error) {
console.error(error)
toast.error(t('error-fetching-versions'))
}
bundleLinkVersions.value = data ?? []
}
else {
const { data, error } = await supabase.from('app_versions')
// ... query
if (error) {
console.error(error)
toast.error(t('error-fetching-versions'))
}
bundleLinkVersions.value = data ?? []
}
+ } finally {
+ isBundleSearchLoading.value = false
+ }
}And update the template to show loading state:
<!-- Add after line 908 -->
<div v-if="isBundleSearchLoading" class="text-center py-4">
<Spinner size="w-8 h-8" />
</div>🤖 Prompt for AI Agents
In src/pages/app/p/[package].channel.[channel].vue around lines 638 to 671, the
async function refreshFilteredVersions lacks a loading state to indicate when
the bundle search is in progress. To fix this, declare a ref named
isBundleSearchLoading initialized to false, set it to true at the start of
refreshFilteredVersions, and set it back to false after the search completes or
errors. Also, update the template around line 908 to conditionally render a
loading spinner when isBundleSearchLoading is true, providing clear user
feedback during search operations.
| console.error(error) | ||
| toast.error(t('cannot-test-app-some')) | ||
| else if (localDependencies.length === 0) { | ||
| toast.info('ignore-compatibility') |
There was a problem hiding this comment.
Use translation for toast message
The toast message should use the translation function for consistency.
- toast.info('ignore-compatibility')
+ toast.info(t('ignore-compatibility'))📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| toast.info('ignore-compatibility') | |
| toast.info(t('ignore-compatibility')) |
🤖 Prompt for AI Agents
In src/pages/app/p/[package].bundle.[bundle].vue at line 248, the toast message
'ignore-compatibility' is hardcoded and should use the translation function
instead. Replace the string with a call to the translation function (e.g., $t or
equivalent) passing 'ignore-compatibility' as the key to ensure the message is
localized consistently.
| watch(() => channelSearchVal.value, () => { | ||
| if (channelSearchVal.value.trim()) { | ||
| filteredChannels.value = channels.value.filter(channel => | ||
| channel.name.toLowerCase().includes(channelSearchVal.value.toLowerCase()), | ||
| ) | ||
| } | ||
| else { | ||
| filteredChannels.value = channels.value | ||
| } | ||
| }) | ||
|
|
||
| // Update filtered channels when channels change | ||
| watch(() => channels.value, () => { | ||
| if (channelSearchVal.value.trim()) { | ||
| filteredChannels.value = channels.value.filter(channel => | ||
| channel.name.toLowerCase().includes(channelSearchVal.value.toLowerCase()), | ||
| ) | ||
| } | ||
| else { | ||
| filteredChannels.value = channels.value | ||
| } | ||
| }, { immediate: true }) |
There was a problem hiding this comment.
🛠️ Refactor suggestion
Refactor duplicated channel filtering logic
The watch functions contain identical filtering logic, violating the DRY principle. Consider using a computed property instead.
Replace the two watch functions with a single computed property:
-// Watch for search changes
-watch(() => channelSearchVal.value, () => {
- if (channelSearchVal.value.trim()) {
- filteredChannels.value = channels.value.filter(channel =>
- channel.name.toLowerCase().includes(channelSearchVal.value.toLowerCase()),
- )
- }
- else {
- filteredChannels.value = channels.value
- }
-})
-
-// Update filtered channels when channels change
-watch(() => channels.value, () => {
- if (channelSearchVal.value.trim()) {
- filteredChannels.value = channels.value.filter(channel =>
- channel.name.toLowerCase().includes(channelSearchVal.value.toLowerCase()),
- )
- }
- else {
- filteredChannels.value = channels.value
- }
-}, { immediate: true })
+// Computed property for filtered channels
+const filteredChannels = computed(() => {
+ if (channelSearchVal.value.trim()) {
+ return channels.value.filter(channel =>
+ channel.name.toLowerCase().includes(channelSearchVal.value.toLowerCase()),
+ )
+ }
+ return channels.value
+})Also remove the reactive declaration on line 48:
-const filteredChannels = ref<(Database['public']['Tables']['channels']['Row'])[]>([])📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| watch(() => channelSearchVal.value, () => { | |
| if (channelSearchVal.value.trim()) { | |
| filteredChannels.value = channels.value.filter(channel => | |
| channel.name.toLowerCase().includes(channelSearchVal.value.toLowerCase()), | |
| ) | |
| } | |
| else { | |
| filteredChannels.value = channels.value | |
| } | |
| }) | |
| // Update filtered channels when channels change | |
| watch(() => channels.value, () => { | |
| if (channelSearchVal.value.trim()) { | |
| filteredChannels.value = channels.value.filter(channel => | |
| channel.name.toLowerCase().includes(channelSearchVal.value.toLowerCase()), | |
| ) | |
| } | |
| else { | |
| filteredChannels.value = channels.value | |
| } | |
| }, { immediate: true }) | |
| // Remove this reactive declaration: | |
| // - const filteredChannels = ref<(Database['public']['Tables']['channels']['Row'])[]>([]) | |
| // Add a computed property instead of two duplicated watchers: | |
| const filteredChannels = computed(() => { | |
| if (channelSearchVal.value.trim()) { | |
| return channels.value.filter(channel => | |
| channel.name.toLowerCase().includes(channelSearchVal.value.toLowerCase()), | |
| ) | |
| } | |
| return channels.value | |
| }) | |
| // (The two watch calls below have been removed) | |
| // watch(() => channelSearchVal.value, ...) { … } | |
| // watch(() => channels.value, …, { immediate: true }) { … } |
🤖 Prompt for AI Agents
In src/pages/app/p/[package].bundle.[bundle].vue around lines 51 to 72, the
channel filtering logic is duplicated in two watch functions. Refactor by
removing these watch functions and the reactive declaration on line 48, then
create a single computed property that returns the filtered channels based on
channelSearchVal and channels. This computed property will automatically update
when either value changes, eliminating duplication and adhering to the DRY
principle.
| @@ -1,511 +1,561 @@ | |||
| { | |||
| "$schema": "https://inlang.com/schema/inlang-message-format", | |||
| "$schema": "https://inlang.com/schema/dinh-dang-tin-nhan-inlang", | |||
There was a problem hiding this comment.
Keep schema URL in English
The schema URL should not be translated as it's a technical identifier that tools may depend on.
- "$schema": "https://inlang.com/schema/dinh-dang-tin-nhan-inlang",
+ "$schema": "https://inlang.com/schema/inlang-message-format",📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| "$schema": "https://inlang.com/schema/dinh-dang-tin-nhan-inlang", | |
| "$schema": "https://inlang.com/schema/inlang-message-format", |
🤖 Prompt for AI Agents
In messages/vi.json at line 2, the schema URL is currently translated, which
should be avoided because it is a technical identifier. Revert the schema URL
back to the original English version
"https://inlang.com/schema/message-format-inlang" to ensure compatibility with
tools that rely on this exact URL.
| { | ||
| "$schema": "https://inlang.com/schema/inlang-message-format", | ||
| "2fa": "2FA の管理", | ||
| "$schema": "https://inlang.com/schema/inlang-message-format\n\nを日本語に翻訳します:\n\nhttps://inlang.com/schema/inlang-メッセージ形式", |
There was a problem hiding this comment.
Fix malformed schema URL
The schema URL contains Japanese text that breaks the URL format. It should remain in English.
- "$schema": "https://inlang.com/schema/inlang-message-format\n\nを日本語に翻訳します:\n\nhttps://inlang.com/schema/inlang-メッセージ形式",
+ "$schema": "https://inlang.com/schema/inlang-message-format",📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| "$schema": "https://inlang.com/schema/inlang-message-format\n\nを日本語に翻訳します:\n\nhttps://inlang.com/schema/inlang-メッセージ形式", | |
| "$schema": "https://inlang.com/schema/inlang-message-format", |
🤖 Prompt for AI Agents
In messages/ja.json at line 2, the $schema URL is malformed because it includes
Japanese text, breaking the URL format. Replace the entire value with the
correct English URL "https://inlang.com/schema/inlang-message-format" without
any additional Japanese characters or line breaks.
There was a problem hiding this comment.
Actionable comments posted: 0
♻️ Duplicate comments (4)
src/pages/ApiKeys.vue (1)
533-553: Potential duplicate selection issue in checkbox handlers.The checkbox change handlers might add duplicate entries if called multiple times. Consider checking for existence before adding.
function handleOrgSelection(orgId: string, checked: boolean) { if (checked) { - if (!displayStore.selectedOrganizations.includes(orgId)) { - displayStore.selectedOrganizations.push(orgId) - } + const index = displayStore.selectedOrganizations.indexOf(orgId) + if (index === -1) { + displayStore.selectedOrganizations.push(orgId) + } } else { displayStore.selectedOrganizations = displayStore.selectedOrganizations.filter(id => id !== orgId) } }src/pages/app/p/[package].channel.[channel].vue (1)
638-671: Add loading state for bundle search operations.The async search operations should show a loading indicator to provide better user feedback.
Add a loading state ref:
const isBundleSearchLoading = ref(false)Then update the search function:
async function refreshFilteredVersions() { if (!channel.value) return + + isBundleSearchLoading.value = true + try { if (bundleLinkSearchVal.value && bundleLinkSearchVal.value.trim()) { const { data, error } = await supabase.from('app_versions') // ... query if (error) { console.error(error) toast.error(t('error-fetching-versions')) } bundleLinkVersions.value = data ?? [] } else { const { data, error } = await supabase.from('app_versions') // ... query if (error) { console.error(error) toast.error(t('error-fetching-versions')) } bundleLinkVersions.value = data ?? [] } + } finally { + isBundleSearchLoading.value = false + } }src/pages/app/p/[package].bundle.[bundle].vue (2)
51-72: Refactor duplicated channel filtering logicThis is the same duplicated filtering logic that was previously flagged. The two watch functions contain identical code and violate the DRY principle.
248-248: Use translation for toast messageThe toast message 'ignore-compatibility' is still hardcoded and should use the translation function for consistency.
🧹 Nitpick comments (1)
src/pages/app/p/[package].bundle.[bundle].vue (1)
828-1048: Consider extracting dialog content to separate componentsThe multiple Teleport components provide rich dialog content but result in a very long template. Consider extracting these into separate dialog content components for better maintainability.
For example, create components like:
ChannelLinkingDialog.vueChannelActionsDialog.vueBundleDeletionDialog.vueThis would improve code organization and reusability across the application.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (15)
src/components/dashboard/AppSetting.vue(18 hunks)src/components/dashboard/StepsApp.vue(3 hunks)src/components/dashboard/StepsBundle.vue(3 hunks)src/components/tables/BundleTable.vue(12 hunks)src/components/tables/ChannelTable.vue(8 hunks)src/components/tables/HistoryTable.vue(4 hunks)src/pages/ApiKeys.vue(9 hunks)src/pages/app/p/[package].bundle.[bundle].vue(10 hunks)src/pages/app/p/[package].channel.[channel].vue(17 hunks)src/pages/app/p/[package].d.[device].vue(4 hunks)src/pages/forgot_password.vue(3 hunks)src/pages/settings/Account.vue(10 hunks)src/pages/settings/organization/Usage.vue(3 hunks)src/services/supabase.ts(1 hunks)supabase/functions/_backend/utils/supabase.ts(1 hunks)
✅ Files skipped from review due to trivial changes (2)
- src/services/supabase.ts
- supabase/functions/_backend/utils/supabase.ts
🚧 Files skipped from review as they are similar to previous changes (8)
- src/components/tables/HistoryTable.vue
- src/pages/settings/organization/Usage.vue
- src/pages/app/p/[package].d.[device].vue
- src/components/dashboard/StepsBundle.vue
- src/components/dashboard/StepsApp.vue
- src/components/tables/ChannelTable.vue
- src/pages/forgot_password.vue
- src/components/tables/BundleTable.vue
🔇 Additional comments (23)
src/pages/settings/Account.vue (5)
17-17: Good migration to centralized dialog store.The import of
useDialogV2Storecorrectly replaces the old dialog management system.
32-34: Well-structured reactive state for MFA dialog inputs.The reactive variables for MFA verification code and QR code are properly declared and will integrate well with the new dialog system.
36-110: Dialog migration implemented correctly with proper error handling.The
deleteAccountfunction properly migrates to the new dialog store API with:
- Correct button roles and handlers
- Proper await pattern with
dialogStore.onDialogDismiss()- Maintained error handling logic
234-307: Excellent refactoring of MFA enablement into two-step dialog flow.The MFA setup is well-structured with:
- Clear separation between QR code display and verification steps
- Proper state management with reactive variables
- Correct error handling that returns
falseto prevent dialog closure- Good cleanup of MFA enrollment on cancellation
The sequential dialog approach improves user experience by breaking down the complex MFA setup process.
533-549: Well-implemented Teleport component for MFA dialog content.The Teleport component properly:
- Conditionally renders based on dialog state and title
- Handles both QR code display and verification input states
- Uses proper v-model binding for the verification code
- Includes appropriate styling and accessibility
The
deferattribute ensures proper DOM timing.src/pages/ApiKeys.vue (4)
13-13: Good migration to centralized dialog store.The import and initialization of
useDialogV2Storecorrectly replaces the old dialog management system.Also applies to: 19-19
29-40: Well-structured reactive state for API key dialog functionality.The reactive variables for dialog state management are properly declared:
newApiKeyNamefor name change dialogs- Checkbox states for organization/app limitations
availableAppsfor dynamic app selectionThese will integrate well with the new dialog system.
282-344: Well-structured API key creation function with proper validation.The
createApiKeyfunction properly:
- Validates organization and app selections before creation
- Returns
falseon validation failures to prevent dialog closure- Handles errors appropriately with user feedback
- Updates the local state after successful creation
The function correctly integrates with the new dialog system's button handler pattern.
624-685: Excellent Teleport implementation for complex API key creation dialog.The Teleport component for the "Add New Key" modal properly:
- Conditionally renders based on dialog state and title
- Implements nested checkbox logic for organization/app limitations
- Uses proper v-model bindings and event handlers
- Provides good UX with scrollable containers and clear labels
The organization-to-app filtering logic enhances usability by showing only relevant apps.
src/pages/app/p/[package].channel.[channel].vue (4)
22-22: Good migration to centralized dialog store.The import and initialization of
useDialogV2Storecorrectly replaces the old dialog management system.Also applies to: 31-31
46-57: Well-structured reactive state for bundle linking functionality.The reactive variables for bundle link dialog state are properly declared:
bundleLinkVersionsfor available versionsbundleLinkSearchValfor search inputbundleLinkSearchModefor UI state managementThe computed properties enhance the component's reactivity.
592-628: Excellent implementation of bundle version selection dialog.The
openSelectVersionfunction properly:
- Fetches available versions with appropriate filters
- Initializes dialog state correctly
- Uses the new dialog store API with proper configuration
- Handles errors with user feedback
The function sets up the foundation for the enhanced bundle management UX.
867-1012: Outstanding Teleport implementation for bundle management dialog.The bundle management dialog provides excellent UX with:
- Clear current bundle indication
- Search functionality with debounced input
- Action cards for different operations (link, unlink, revert)
- Proper conditional rendering based on search mode
- Good visual hierarchy and accessibility
The implementation properly separates search results from action options, making the interface intuitive.
src/components/dashboard/AppSetting.vue (5)
15-15: Good migration to centralized dialog store.The import and initialization of
useDialogV2Storecorrectly replaces the old dialog management system.Also applies to: 24-24
28-30: Well-structured reactive state for dialog inputs.The reactive variables for dialog inputs are properly declared:
transferAppIdInputfor app ID confirmationselectedChannelandavailableChannelsfor channel selectionThese will integrate well with the Teleport components.
158-211: Excellent refactoring of channel selection into dialog-based flow.The
setDefaultChannelfunction properly:
- Fetches available channels with error handling
- Uses reactive state for channel selection
- Implements proper validation in the dialog handler
- Returns
falseon validation failure to prevent dialog closure- Provides user feedback on success/failure
The radio button approach via Teleport enhances UX compared to a simple dropdown.
333-430: Outstanding implementation of multi-step app transfer flow.The
transferAppOwnershipfunction excellently implements a secure multi-step process:
- Initial confirmation - Warns about requirements
- Organization selection - Dynamic buttons for eligible organizations
- Final confirmation - Requires app ID input for verification
Key strengths:
- Proper validation at each step with early returns
- Secure app ID confirmation to prevent accidental transfers
- Good error handling and user feedback
- Proper integration with the new dialog system
The flow provides excellent UX while maintaining security.
573-607: Well-implemented Teleport components for dialog inputs.Both Teleport components properly:
- Conditionally render based on dialog state and title
- Use appropriate input controls (text input, radio buttons)
- Include proper styling and accessibility attributes
- Handle user interactions correctly
The radio button implementation for channel selection provides better UX than a dropdown.
src/pages/app/p/[package].bundle.[bundle].vue (5)
106-117: Well-implemented dialog migrationThe copyToast function has been properly migrated to use the new dialogStore with consistent button roles and proper async handling.
178-214: Clean channel chooser implementationThe refactored ASChannelChooser function properly handles permissions, initializes state, and uses the new dialog system consistently. The separation of concerns with handleChannelLink is well done.
216-260: Robust compatibility checking logicThe handleChannelLink function implements thorough compatibility validation with proper error handling and user confirmation flows. The fallback for compatibility checking is well handled.
532-656: Comprehensive bundle deletion workflowThe deleteBundle function implements a thorough multi-step deletion process with proper channel unlinking, permission checks, and both soft/hard deletion options. The error handling and user feedback are excellent.
717-727: Improved channel UI with settings accessThe addition of settings buttons next to each linked channel provides better UX for channel management. The styling and interaction patterns are consistent.
|



Summary
Test plan
Screenshots
Checklist
bun run lint-backend && bun run lint.Summary by CodeRabbit
New Features
Refactor
Bug Fixes
Chores
Style