feat(web): add Vue 3 + shadcn-style chat dashboard UI#22
Conversation
|
Thank you for contributing to this project with this PR, welcome to the community and the amazing world of open source! |
|
Warning Rate limit exceeded
⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. 📝 WalkthroughWalkthroughThis PR adds a complete Vue 3 + Vite-based dashboard application to clients/web. It includes configuration files, UI component library inspired by shadcn-vue, a chat interface with configurable gateway settings, entry point setup, and TypeScript configuration. The dashboard runs on port 4323 with Tailwind CSS styling and uses Biome for code formatting. Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes 🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches🧪 Generate unit tests (beta)
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. Comment |
✅ Contributor ReportUser: @yacosta738
Contributor Report evaluates based on public GitHub activity. Analysis period: 2025-02-17 to 2026-02-17 |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: c65e1eff7d
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| "dependencies": { | ||
| "class-variance-authority": "^0.7.1", | ||
| "clsx": "^2.1.1", | ||
| "tailwind-merge": "^3.3.1", | ||
| "vue": "^3.5.22" |
There was a problem hiding this comment.
Commit lockfile entries for dashboard dependencies
This change adds new dependencies to the dashboard manifest, but clients/web/pnpm-lock.yaml was not updated (importers.apps/dashboard remains {}), so installs that enforce lockfile consistency will fail with an outdated lockfile error. In this repository that directly impacts both Gradle-driven web builds (clients/web/build.gradle.kts uses install --frozen-lockfile when the lockfile exists) and CI workflows that run frozen installs, blocking the new dashboard package from being built.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Actionable comments posted: 3
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
clients/web/README.md (1)
12-12:⚠️ Potential issue | 🟡 MinorStale comment: dashboard directory description still says "pendiente".
The directory tree describes the dashboard as
# Dashboard web (pendiente)but this PR adds the actual scaffold. Update to reflect the current state (e.g.,# Dashboard web (Vue 3 + Vite)).🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@clients/web/README.md` at line 12, Update the stale README entry for the dashboard directory: locate the line containing "dashboard/ # Dashboard web (pendiente)" and replace the comment to reflect the scaffold added (for example "dashboard/ # Dashboard web (Vue 3 + Vite)") so the directory tree accurately documents the current state.
🧹 Nitpick comments (5)
clients/web/apps/dashboard/package.json (1)
7-13: No test scripts or test dependencies are included.The scaffold has no test runner configured (no vitest, no test script). While this is understandable for an initial scaffold, consider adding at least a placeholder
testscript andvitestdependency to encourage test-first development as components are built out.As per coding guidelines, "Testing: Verify that tests cover critical paths and follow established naming conventions."
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@clients/web/apps/dashboard/package.json` around lines 7 - 13, Add a minimal test runner and script to package.json: add a "test" script and include "vitest" (and optionally "happy-dom" or "jsdom" if DOM tests are expected) in devDependencies so contributors have a placeholder for tests; update the "scripts" object (the existing "scripts" key) to include "test": "vitest" (or "vitest --run") and add "vitest" to devDependencies in package.json (or via package manager install), ensuring the project can run vitest out-of-the-box for future component tests.clients/web/apps/dashboard/src/App.vue (4)
1-104: No unit or component tests for the new chat UI.This component contains non-trivial interaction logic (send validation, config toggle, message appending). Consider adding at least a Vitest + Vue Test Utils spec covering
sendMessagebehavior and the config toggle. As per coding guidelines, "Verify that tests cover critical paths."🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@clients/web/apps/dashboard/src/App.vue` around lines 1 - 104, Add unit/component tests that cover the critical chat UI interactions: write a Vitest + Vue Test Utils spec for App.vue that mounts the component and asserts sendMessage behavior (use the exported sendMessage via user interaction or form submit), verifying that when prompt has text (canSend true) a user message and an assistant placeholder are appended to messages and prompt is cleared; also test the config toggle by clicking the Button that flips showConfig to true/false and asserting the config fields (baseUrl, pairingCode, bearerToken, webhookSecret) render when showConfig is true and the chat view (ChatMessage list) renders when false. Reference the component-level symbols: sendMessage, showConfig, canSend, messages, prompt and the form submit/Button to drive the interactions.
19-22: Sensitive credentials stored in plain reactive state.
bearerTokenandwebhookSecretare held as plainrefstrings. For a scaffold this is fine, but be aware this means they'll appear in Vue DevTools and any component snapshot. When this moves beyond mock stage, avoid persisting these in component state — prefer a short-lived submission or a secrets manager integration.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@clients/web/apps/dashboard/src/App.vue` around lines 19 - 22, The current reactive refs bearerToken and webhookSecret in App.vue store sensitive secrets in component state (bearerToken, webhookSecret), exposing them to Vue DevTools and snapshots; change handling so secrets are not persisted as reactive refs: accept them as ephemeral input values (use local non-reactive variables or read directly from the form submit handler), immediately POST/submit to the backend or a secrets manager from the submit method, then clear the variables, and/or move any long-lived secret configuration to secure storage (env vars or a vault) rather than keeping them in component-level refs (also review pairingCode/baseUrl usage to ensure only non-sensitive values remain reactive).
50-103: Mixed languages in UI strings — consider i18n consistency.The UI mixes Spanish (
"Hola, soy …","Escribe un mensaje...","Enviar","Configuración del gateway","Volver al chat") with English ("Simple AI chat","Config","Base URL", labels). If this is intentional for a specific locale, consider extracting all strings to a locale file (e.g., vue-i18n) to simplify future localization. If not, pick one language for the scaffold.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@clients/web/apps/dashboard/src/App.vue` around lines 50 - 103, UI strings in App.vue are inconsistent between Spanish and English; extract all hard-coded labels and placeholders (e.g., "Simple AI chat", "Configuración del gateway", "Config", "Volver al chat", "Base URL", "Pairing code", "Bearer token", "Webhook secret", "Escribe un mensaje...", "Enviar", and any other text used with showConfig, modelName, prompt, sendMessage, Button, Input, ChatMessage) into a locale file and replace them with i18n keys (e.g., using vue-i18n $t('...')) so the template uses translations instead of mixed literals; add a default locale JSON with consistent language entries and update the App.vue template to call $t for each label/placeholder and the header text.
87-101: Chat area won't auto-scroll to the latest message.When messages are appended, the chat container (
overflow-y-auto) won't scroll to the bottom automatically. Users will need to scroll manually after each send. Consider adding anextTickscroll-to-bottom after pushing messages:Sketch
+import { computed, ref, nextTick } from 'vue' ... +const chatContainer = ref<HTMLElement | null>(null) + function sendMessage() { ... prompt.value = '' + nextTick(() => { + chatContainer.value?.scrollTo({ top: chatContainer.value.scrollHeight, behavior: 'smooth' }) + }) }Then add
ref="chatContainer"to the<div class="flex-1 space-y-3 overflow-y-auto p-4">element.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@clients/web/apps/dashboard/src/App.vue` around lines 87 - 101, The chat container currently doesn't auto-scroll; add a ref (e.g., ref="chatContainer") to the div with class "flex-1 space-y-3 overflow-y-auto p-4" and implement a scroll-to-bottom helper that runs after messages change—call it via Vue.nextTick (or await nextTick()) from the sendMessage method (and/or a watcher on messages) so after pushing a new message the code measures chatContainer.scrollHeight and sets scrollTop to that value; reference the template ChatMessage loop, the messages array, and the sendMessage function to locate where to attach the nextTick scroll call.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@clients/web/apps/dashboard/package.json`:
- Around line 20-27: Remove the unnecessary autprefixer devDependency from the
devDependencies block in package.json: delete the "autoprefixer" entry (the
string "autoprefixer") and ensure the JSON remains valid (commas adjusted) since
Tailwind CSS v4 handles vendor prefixes via Lightning CSS; keep other
devDependencies like "postcss" and "@tailwindcss/postcss" untouched.
In `@clients/web/apps/dashboard/src/App.vue`:
- Line 44: The mock assistant message is interpolating raw user input (text)
into the template string in App.vue (content: `Procesando "${text}" con
${modelName}. Gateway: ${baseUrl.value}`), so sanitize or escape text before
embedding: create/ reuse an escapeHtml or sanitizeWithDomPurify utility and use
escapedText when constructing the content string (e.g. replace occurrences of
text with escapedText), and validate/limit length of text if appropriate; ensure
any place that forwards this mock message (or renders it with v-html) uses the
sanitized version to prevent XSS or unsafe forwarding.
- Around line 40-45: Message IDs used in messages.value are generated with
Date.now() (and +1), which can collide; replace that with a dedicated
incrementing counter (e.g., messageIdCounter) scoped to the component so each
new message (both user and assistant) uses messageIdCounter++ for unique ids;
update places that push messages (the code around messages.value.push in
sendMessage) to stop using Date.now() and use the counter instead, ensuring the
counter is initialized once (0 or 1) and incremented for each pushed message so
Vue :key values never duplicate.
---
Outside diff comments:
In `@clients/web/README.md`:
- Line 12: Update the stale README entry for the dashboard directory: locate the
line containing "dashboard/ # Dashboard web (pendiente)" and replace the
comment to reflect the scaffold added (for example "dashboard/ # Dashboard
web (Vue 3 + Vite)") so the directory tree accurately documents the current
state.
---
Nitpick comments:
In `@clients/web/apps/dashboard/package.json`:
- Around line 7-13: Add a minimal test runner and script to package.json: add a
"test" script and include "vitest" (and optionally "happy-dom" or "jsdom" if DOM
tests are expected) in devDependencies so contributors have a placeholder for
tests; update the "scripts" object (the existing "scripts" key) to include
"test": "vitest" (or "vitest --run") and add "vitest" to devDependencies in
package.json (or via package manager install), ensuring the project can run
vitest out-of-the-box for future component tests.
In `@clients/web/apps/dashboard/src/App.vue`:
- Around line 1-104: Add unit/component tests that cover the critical chat UI
interactions: write a Vitest + Vue Test Utils spec for App.vue that mounts the
component and asserts sendMessage behavior (use the exported sendMessage via
user interaction or form submit), verifying that when prompt has text (canSend
true) a user message and an assistant placeholder are appended to messages and
prompt is cleared; also test the config toggle by clicking the Button that flips
showConfig to true/false and asserting the config fields (baseUrl, pairingCode,
bearerToken, webhookSecret) render when showConfig is true and the chat view
(ChatMessage list) renders when false. Reference the component-level symbols:
sendMessage, showConfig, canSend, messages, prompt and the form submit/Button to
drive the interactions.
- Around line 19-22: The current reactive refs bearerToken and webhookSecret in
App.vue store sensitive secrets in component state (bearerToken, webhookSecret),
exposing them to Vue DevTools and snapshots; change handling so secrets are not
persisted as reactive refs: accept them as ephemeral input values (use local
non-reactive variables or read directly from the form submit handler),
immediately POST/submit to the backend or a secrets manager from the submit
method, then clear the variables, and/or move any long-lived secret
configuration to secure storage (env vars or a vault) rather than keeping them
in component-level refs (also review pairingCode/baseUrl usage to ensure only
non-sensitive values remain reactive).
- Around line 50-103: UI strings in App.vue are inconsistent between Spanish and
English; extract all hard-coded labels and placeholders (e.g., "Simple AI chat",
"Configuración del gateway", "Config", "Volver al chat", "Base URL", "Pairing
code", "Bearer token", "Webhook secret", "Escribe un mensaje...", "Enviar", and
any other text used with showConfig, modelName, prompt, sendMessage, Button,
Input, ChatMessage) into a locale file and replace them with i18n keys (e.g.,
using vue-i18n $t('...')) so the template uses translations instead of mixed
literals; add a default locale JSON with consistent language entries and update
the App.vue template to call $t for each label/placeholder and the header text.
- Around line 87-101: The chat container currently doesn't auto-scroll; add a
ref (e.g., ref="chatContainer") to the div with class "flex-1 space-y-3
overflow-y-auto p-4" and implement a scroll-to-bottom helper that runs after
messages change—call it via Vue.nextTick (or await nextTick()) from the
sendMessage method (and/or a watcher on messages) so after pushing a new message
the code measures chatContainer.scrollHeight and sets scrollTop to that value;
reference the template ChatMessage loop, the messages array, and the sendMessage
function to locate where to attach the nextTick scroll call.
| "devDependencies": { | ||
| "@biomejs/biome": "2.3.15", | ||
| "@tailwindcss/postcss": "^4.1.16", | ||
| "@types/node": "^24.10.1", | ||
| "@vitejs/plugin-vue": "^6.0.1", | ||
| "@vue/tsconfig": "^0.8.1", | ||
| "autoprefixer": "^10.4.21", | ||
| "postcss": "^8.5.6", |
There was a problem hiding this comment.
🛠️ Refactor suggestion | 🟠 Major
Remove autoprefixer — it's unnecessary with Tailwind CSS v4.
Tailwind v4 has built-in Lightning CSS integration that handles vendor prefixes automatically. The autoprefixer dependency on Line 26 is unused overhead.
♻️ Proposed fix
"devDependencies": {
"@biomejs/biome": "2.3.15",
"@tailwindcss/postcss": "^4.1.16",
"@types/node": "^24.10.1",
"@vitejs/plugin-vue": "^6.0.1",
"@vue/tsconfig": "^0.8.1",
- "autoprefixer": "^10.4.21",
"postcss": "^8.5.6",
"tailwindcss": "^4.1.16",📝 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.
| "devDependencies": { | |
| "@biomejs/biome": "2.3.15", | |
| "@tailwindcss/postcss": "^4.1.16", | |
| "@types/node": "^24.10.1", | |
| "@vitejs/plugin-vue": "^6.0.1", | |
| "@vue/tsconfig": "^0.8.1", | |
| "autoprefixer": "^10.4.21", | |
| "postcss": "^8.5.6", | |
| "devDependencies": { | |
| "@biomejs/biome": "2.3.15", | |
| "@tailwindcss/postcss": "^4.1.16", | |
| "@types/node": "^24.10.1", | |
| "@vitejs/plugin-vue": "^6.0.1", | |
| "@vue/tsconfig": "^0.8.1", | |
| "postcss": "^8.5.6", |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@clients/web/apps/dashboard/package.json` around lines 20 - 27, Remove the
unnecessary autprefixer devDependency from the devDependencies block in
package.json: delete the "autoprefixer" entry (the string "autoprefixer") and
ensure the JSON remains valid (commas adjusted) since Tailwind CSS v4 handles
vendor prefixes via Lightning CSS; keep other devDependencies like "postcss" and
"@tailwindcss/postcss" untouched.
| messages.value.push({ id: Date.now(), role: 'user', content: text }) | ||
| messages.value.push({ | ||
| id: Date.now() + 1, | ||
| role: 'assistant', | ||
| content: `Procesando "${text}" con ${modelName}. Gateway: ${baseUrl.value}`, | ||
| }) |
There was a problem hiding this comment.
Message IDs can collide across sends.
Date.now() is not guaranteed to be unique — two rapid calls to sendMessage can produce the same millisecond timestamp, and the +1 trick collides with the next user message's base ID. This will cause Vue's :key to duplicate, leading to rendering bugs.
Use an incrementing counter instead:
Proposed fix
+let nextId = 1
+
function sendMessage() {
const text = prompt.value.trim()
if (!text) {
return
}
- messages.value.push({ id: Date.now(), role: 'user', content: text })
+ messages.value.push({ id: nextId++, role: 'user', content: text })
messages.value.push({
- id: Date.now() + 1,
+ id: nextId++,
role: 'assistant',
content: `Procesando "${text}" con ${modelName}. Gateway: ${baseUrl.value}`,
})
prompt.value = ''
}🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@clients/web/apps/dashboard/src/App.vue` around lines 40 - 45, Message IDs
used in messages.value are generated with Date.now() (and +1), which can
collide; replace that with a dedicated incrementing counter (e.g.,
messageIdCounter) scoped to the component so each new message (both user and
assistant) uses messageIdCounter++ for unique ids; update places that push
messages (the code around messages.value.push in sendMessage) to stop using
Date.now() and use the counter instead, ensuring the counter is initialized once
(0 or 1) and incremented for each pushed message so Vue :key values never
duplicate.
| messages.value.push({ | ||
| id: Date.now() + 1, | ||
| role: 'assistant', | ||
| content: `Procesando "${text}" con ${modelName}. Gateway: ${baseUrl.value}`, |
There was a problem hiding this comment.
User-supplied text interpolated directly into the mock response.
content: \Procesando "${text}" ...embeds raw user input into the assistant message string. While this is a mock and Vue's template rendering escapes HTML by default (so no XSS via{{ }}), be cautious if this content is ever rendered with v-html` or forwarded to a backend without sanitization. As per coding guidelines, "Check for vulnerabilities in encryption, crypto code, and configuration handling."
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@clients/web/apps/dashboard/src/App.vue` at line 44, The mock assistant
message is interpolating raw user input (text) into the template string in
App.vue (content: `Procesando "${text}" con ${modelName}. Gateway:
${baseUrl.value}`), so sanitize or escape text before embedding: create/ reuse
an escapeHtml or sanitizeWithDomPurify utility and use escapedText when
constructing the content string (e.g. replace occurrences of text with
escapedText), and validate/limit length of text if appropriate; ensure any place
that forwards this mock message (or renders it with v-html) uses the sanitized
version to prevent XSS or unsafe forwarding.
Deploying corvus with
|
| Latest commit: |
87cb373
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://58984e62.corvus-42x.pages.dev |
| Branch Preview URL: | https://codex-add-basic-chat-ui-with.corvus-42x.pages.dev |
Motivation
Description
clients/web/apps/dashboardwithvite.config.ts,tsconfig.*,index.html, and PostCSS/Tailwind hooks and acomponents.jsonfor shadcn-vue conventions.src/App.vue) with a model header, gateway config panel, chat message list, composer, and mocked assistant responses.ButtonandInput(src/components/ui/*) and acnclass utility (src/lib/utils.ts) plus styles insrc/style.css.clients/web/README.mdand add a shortclients/web/apps/dashboard/README.mdwith run instructions.Testing
pnpm installinclients/web, which failed due to a registry 403 when fetching@tailwindcss/postcss, so dependencies could not be installed.pnpm run checkin the dashboard app, which failed because the existingclients/web/biome.jsoncontains keys that are incompatible with the localbiomebinary.pnpm run buildandpnpm run devin the dashboard app, both of which failed because dependencies were not installed (vue-tsc/vitenot found).Codex Task
Summary by CodeRabbit
Release Notes