feat: Implement project dashboard and snippet management views - #3
Conversation
|
Caution Review failedThe pull request is closed. ℹ️ Recent review info⚙️ Run configurationConfiguration used: Repository UI (base), Organization UI (inherited) Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (4)
📝 WalkthroughWalkthroughA alteração adiciona o frontend React do Devaulty, com roteamento, tema, dashboard de projetos, gerenciamento de snippets, cliente Axios, hooks React Query, estilos e configurações de build. O backend passa a permitir CORS para a aplicação local em ChangesAplicação web Devaulty
Estimated code review effort: 4 (Complex) | ~60 minutes Sequence Diagram(s)sequenceDiagram
participant Route as ProjectDetailRouteComponent
participant View as ProjectDetailView
participant Hooks as useSnippetsQuery
participant API as snippetsApi
Route->>View: Renderiza a rota do projeto
View->>Hooks: Busca snippets
Hooks->>API: Solicita dados
API-->>View: Retorna snippets
View->>API: Salva snippet
API-->>View: Retorna snippet atualizado
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches📝 Generate docstrings
Comment |
There was a problem hiding this comment.
Actionable comments posted: 14
🧹 Nitpick comments (9)
frontend/src/components/ProjectDetailView.tsx (2)
555-565: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueImport declarado no meio do módulo.
import { useQueryClient } from "@tanstack/react-query";na linha 562 funciona por hoisting de módulos ES, mas colocar umimportapós declarações de função dificulta a leitura e pode ser pego por regras de lint comoimport/first. Recomenda-se mover para o topo do arquivo junto aos demais imports.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@frontend/src/components/ProjectDetailView.tsx` around lines 555 - 565, Move the useQueryClient import to the top-level import section of ProjectDetailView.tsx, alongside the other imports, and remove it from between the useParamsHelper and useQueryClientHelper declarations; keep useQueryClientHelper unchanged otherwise.
342-358: 🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick winUse
useUpdateSnippetMutationno fluxo de edição
Oupdatejá tem um hook em~features/snippets/hooks/useSnippetsque invalidasnippetsKeys.all(projectId)e atualiza o detalhe. Usá-lo aqui elimina oimport()dinâmico e osnippet-savedglobal, deixando a sincronização de cache no mesmo lugar das outras mutations.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@frontend/src/components/ProjectDetailView.tsx` around lines 342 - 358, Replace the direct snippetsApi.update call in the editing branch of ProjectDetailView with useUpdateSnippetMutation from ~features/snippets/hooks/useSnippets, passing projectId and selectedSnippetId as required. Await its mutateAsync result, remove the dynamic import and global snippet-saved event dispatch, and preserve the existing success/error toast and form-state updates.frontend/src/components/DashboardView.tsx (1)
15-19: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winFunção
getIconComponentduplicada em outro arquivo.A mesma implementação (cast idêntico via
unknown as Record<...>) aparece emfrontend/src/components/ProjectDetailView.tsx(linhas 126-130). Vale extrair para um utilitário compartilhado (ex.:frontend/src/utils/icons.ts) para evitar divergência futura.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@frontend/src/components/DashboardView.tsx` around lines 15 - 19, Extraia a implementação duplicada de getIconComponent para um utilitário compartilhado, como icons.ts, preservando o fallback para Icons.Folder e o mesmo cast de tipos; atualize DashboardView e ProjectDetailView para importarem e usarem essa função compartilhada, removendo as definições locais.frontend/src/routes/projects.$projectId.module.css (1)
347-360: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueRemover CSS morto em
frontend/src/routes/projects.$projectId.module.css:347-446
.codeViewer,.formTextareae.formEditornão são usadas emfrontend/src/components/ProjectDetailView.tsxnem em outro ponto do frontend; podem sair do módulo.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@frontend/src/routes/projects`.$projectId.module.css around lines 347 - 360, Remove the unused CSS selectors `.codeViewer`, `.formTextarea`, and `.formEditor` from the stylesheet, confirming they have no remaining frontend references before deletion.frontend/src/features/projects/hooks/useProjects.ts (1)
67-75: 🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick winCache de detalhe do projeto não é limpo após exclusão.
useArchiveProjectMutation/useUnarchiveProjectMutationinvalidamprojectsKeys.detail(id)além deall, masuseDeleteProjectMutationnão. Após excluir um projeto, o cache de detalhe permanece com dados obsoletos de um recurso inexistente, podendo ser servido caso alguma view ainda consulteprojectsKeys.detail(id).🔧 Sugestão de fix
export const useDeleteProjectMutation = () => { const queryClient = useQueryClient(); return useMutation({ mutationFn: (id: string) => projectsApi.delete(id), - onSuccess: () => { + onSuccess: (_, id) => { queryClient.invalidateQueries({ queryKey: projectsKeys.all }); + queryClient.removeQueries({ queryKey: projectsKeys.detail(id) }); }, }); };🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@frontend/src/features/projects/hooks/useProjects.ts` around lines 67 - 75, Atualize useDeleteProjectMutation para invalidar também projectsKeys.detail(id) após a exclusão, além de projectsKeys.all; use o id recebido pela mutation no callback onSuccess e siga o padrão adotado por useArchiveProjectMutation/useUnarchiveProjectMutation.backend/src/main/java/com/devaulty/backend/infrastructure/security/WebConfig.java (1)
16-19: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winOrigem de CORS hardcoded dificulta uso em outros ambientes.
A origem
http://localhost:5173está fixa no código. Isso é aceitável para desenvolvimento local, mas qualquer deploy em staging/produção com outra URL de frontend vai exigir alteração de código e novo build do backend. Considere externalizar viaapplication.yml/@Value(ex.:app.cors.allowed-origins).♻️ Sugestão de externalização
`@Configuration` public class WebConfig { + + `@Value`("${app.cors.allowed-origins:http://localhost:5173}") + private String[] allowedOrigins; `@Bean` public WebMvcConfigurer corsConfigurer(){ return new WebMvcConfigurer() { `@Override` public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/api/**") - .allowedOrigins("http://localhost:5173") + .allowedOrigins(allowedOrigins) .allowedMethods("GET", "POST", "PATCH", "DELETE", "PUT") .allowedHeaders("*"); } }; } }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@backend/src/main/java/com/devaulty/backend/infrastructure/security/WebConfig.java` around lines 16 - 19, Externalize the hardcoded CORS origin in WebConfig by injecting an application property such as app.cors.allowed-origins via `@Value` or configuration properties, and use that value in the registry.addMapping("/api/**") configuration. Define a development default in application.yml while allowing staging and production to override it without rebuilding the backend.frontend/src/features/snippets/hooks/useSnippets.ts (1)
47-55: 🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick winCache de detalhe do snippet não é limpo após exclusão.
Mesmo padrão observado em
useDeleteProjectMutation(useProjects.ts): o cache de detalhe (snippetsKeys.detail(projectId, snippetId)) não é removido/invalidado após a exclusão, podendo servir dados obsoletos de um snippet já excluído.🔧 Sugestão de fix
export const useDeleteSnippetMutation = (projectId: string) => { const queryClient = useQueryClient(); return useMutation({ mutationFn: (snippetId: string) => snippetsApi.delete(projectId, snippetId), - onSuccess: () => { + onSuccess: (_, snippetId) => { queryClient.invalidateQueries({ queryKey: snippetsKeys.all(projectId) }); + queryClient.removeQueries({ queryKey: snippetsKeys.detail(projectId, snippetId) }); }, }); };🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@frontend/src/features/snippets/hooks/useSnippets.ts` around lines 47 - 55, Atualize useDeleteSnippetMutation para capturar o snippetId no onSuccess e invalidar também snippetsKeys.detail(projectId, snippetId), além de manter a invalidação de snippetsKeys.all(projectId), garantindo a limpeza do cache de detalhes após a exclusão.frontend/src/components/RootLayout.tsx (1)
152-152: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick winNão fixe o endpoint da API no status bar.
http://localhost:8080/api/v1ficará incorreto em staging, produção ou qualquer ambiente com outra URL. Reutilize a mesma configuração/base URL do cliente Axios para evitar divergência entre o endpoint real e o texto exibido.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@frontend/src/components/RootLayout.tsx` at line 152, Replace the hardcoded API URL in the status bar with the configured base URL used by the Axios client, referencing the existing API configuration or client symbol in RootLayout so the displayed endpoint matches each environment.frontend/README.md (1)
1-75: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winAtualize o README para refletir o aplicativo real.
O conteúdo ainda é o README genérico do template Vite e não documenta como iniciar o frontend, configurar a API ou usar o roteamento e as integrações adicionadas. Isso dificulta o onboarding e pode induzir a configurações incorretas.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@frontend/README.md` around lines 1 - 75, Substitua o README genérico do template Vite por uma documentação do aplicativo real: descreva os pré-requisitos, instalação e comandos para iniciar o frontend, explique a configuração da API e variáveis de ambiente, e documente o roteamento e as integrações disponíveis. Remova as seções específicas do template, como React Compiler e recomendações genéricas de ESLint, e use os scripts e símbolos reais definidos no projeto.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@frontend/src/api/client.ts`:
- Around line 16-21: Substitua o baseURL fixo na configuração de apiClient por
import.meta.env.VITE_API_BASE_URL, permitindo definir o endpoint conforme o
ambiente via variáveis do Vite. Considere fornecer um fallback apropriado para
desenvolvimento local.
- Around line 16-21: Configure a finite timeout in the axios instance created by
apiClient, using the project’s standard request-timeout value or a reasonable
default, so unresponsive backend requests fail promptly instead of remaining
pending indefinitely.
In `@frontend/src/components/DashboardView.tsx`:
- Around line 116-139: Action buttons remain clickable while archive, unarchive,
or delete mutations are pending, allowing duplicate requests. In the
DashboardView action controls and the corresponding unarchive controls, use
archiveMutation.isPending, unarchiveMutation.isPending, and
deleteMutation.isPending to set each button’s disabled state, preventing
repeated clicks during its mutation.
- Around line 168-176: O div archiveHeader é acionável apenas por clique e não
pode ser operado por teclado. Adicione role="button", tabIndex={0} e um handler
onKeyDown que alterne showArchived em Enter ou Espaço, preservando o onClick
existente e evitando a ação padrão do navegador nesses casos.
In `@frontend/src/components/ProjectDetailView.tsx`:
- Around line 378-387: Substitua o elemento input de descrição no componente
ProjectDetailView por um textarea, mantendo value, onChange e placeholder, e
aplique styles.formTextarea em vez de styles.formInput para permitir múltiplas
linhas e reutilizar o estilo existente.
- Around line 17-49: Atualize a constante POPULAR_LANGUAGES para incluir todas
as linguagens tratadas por mapLanguageToMonaco que estão ausentes: MONGODB,
GRAPHQL, TOML, INI, ENV, PROPERTIES, JSX, TSX, FISH, BATCH, VUE, SVELTE, SCSS,
LESS, KUBERNETES_YAML e PLSQL, garantindo que o select controlado ofereça uma
option para cada valor válido de SnippetLanguage.
- Around line 442-456: Os botões do formulário de snippet não refletem o estado
pendente das mutações, permitindo submissões duplicadas. Em ProjectDetailView,
use createSnippetMutation.isPending e o estado pending da mutação de atualização
no botão “Save” para definir disabled durante a operação; desabilite também
“Cancel” enquanto a mutação estiver pendente e preserve o comportamento após sua
conclusão.
In `@frontend/src/components/RootLayout.tsx`:
- Around line 120-125: Corrija a referência de estilo no fallback do sidebar: em
RootLayout, substitua ou remova o uso de styles.logoDot conforme as classes
realmente declaradas em __root.module.css, garantindo que o elemento do logo
utilize uma classe CSS existente e mantenha a estilização visual esperada.
- Line 161: O Toaster em RootLayout está fixado no tema escuro e deve acompanhar
o tema global. Mova-o para um componente filho renderizado dentro do
ThemeProvider, use useTheme() nesse componente e passe theme={theme} ao Toaster,
preservando suas demais propriedades.
- Around line 38-41: Os Links ativos aplicam apenas navItemActive e perdem os
estilos base. Atualize ambos os componentes Link em RootLayout para combinar
navItem com navItemActive em activeProps, preservando layout, padding e
text-decoration.
- Around line 13-16: Restrinja o lookup em getIconComponent a um allowlist
explícito de nomes de ícones permitidos pelo formulário, validando iconName
antes de acessar Icons; retorne Icons.Folder para valores ausentes,
desconhecidos ou não renderizáveis, e use esse componente validado ao montar
ProjectIcon.
In `@frontend/src/features/projects/components/ProjectForm.tsx`:
- Around line 120-134: Os botões de cor renderizados no mapa PRESET_COLORS não
têm informações acessíveis. Adicione a cada botão um aria-label que identifique
a cor e um aria-pressed indicando se color === col, mantendo o estado visual
existente em colorOptionActive.
In `@frontend/src/main.tsx`:
- Line 4: Substitua o import e o uso de createMemoryHistory por
createBrowserHistory em main.tsx, mantendo a configuração do createRouter e do
RouterProvider compatível com a history do navegador para preservar URL,
refresh, voltar/avançar e deep links.
In `@frontend/vite.config.ts`:
- Line 5: Substitua o uso de __dirname no arquivo de configuração do Vite por
uma resolução baseada em import.meta.url, usando fileURLToPath e dirname
conforme necessário; atualize também o import de path e preserve os aliases
definidos em resolve.alias para que funcionem no modo ESM.
---
Nitpick comments:
In
`@backend/src/main/java/com/devaulty/backend/infrastructure/security/WebConfig.java`:
- Around line 16-19: Externalize the hardcoded CORS origin in WebConfig by
injecting an application property such as app.cors.allowed-origins via `@Value` or
configuration properties, and use that value in the
registry.addMapping("/api/**") configuration. Define a development default in
application.yml while allowing staging and production to override it without
rebuilding the backend.
In `@frontend/README.md`:
- Around line 1-75: Substitua o README genérico do template Vite por uma
documentação do aplicativo real: descreva os pré-requisitos, instalação e
comandos para iniciar o frontend, explique a configuração da API e variáveis de
ambiente, e documente o roteamento e as integrações disponíveis. Remova as
seções específicas do template, como React Compiler e recomendações genéricas de
ESLint, e use os scripts e símbolos reais definidos no projeto.
In `@frontend/src/components/DashboardView.tsx`:
- Around line 15-19: Extraia a implementação duplicada de getIconComponent para
um utilitário compartilhado, como icons.ts, preservando o fallback para
Icons.Folder e o mesmo cast de tipos; atualize DashboardView e ProjectDetailView
para importarem e usarem essa função compartilhada, removendo as definições
locais.
In `@frontend/src/components/ProjectDetailView.tsx`:
- Around line 555-565: Move the useQueryClient import to the top-level import
section of ProjectDetailView.tsx, alongside the other imports, and remove it
from between the useParamsHelper and useQueryClientHelper declarations; keep
useQueryClientHelper unchanged otherwise.
- Around line 342-358: Replace the direct snippetsApi.update call in the editing
branch of ProjectDetailView with useUpdateSnippetMutation from
~features/snippets/hooks/useSnippets, passing projectId and selectedSnippetId as
required. Await its mutateAsync result, remove the dynamic import and global
snippet-saved event dispatch, and preserve the existing success/error toast and
form-state updates.
In `@frontend/src/components/RootLayout.tsx`:
- Line 152: Replace the hardcoded API URL in the status bar with the configured
base URL used by the Axios client, referencing the existing API configuration or
client symbol in RootLayout so the displayed endpoint matches each environment.
In `@frontend/src/features/projects/hooks/useProjects.ts`:
- Around line 67-75: Atualize useDeleteProjectMutation para invalidar também
projectsKeys.detail(id) após a exclusão, além de projectsKeys.all; use o id
recebido pela mutation no callback onSuccess e siga o padrão adotado por
useArchiveProjectMutation/useUnarchiveProjectMutation.
In `@frontend/src/features/snippets/hooks/useSnippets.ts`:
- Around line 47-55: Atualize useDeleteSnippetMutation para capturar o snippetId
no onSuccess e invalidar também snippetsKeys.detail(projectId, snippetId), além
de manter a invalidação de snippetsKeys.all(projectId), garantindo a limpeza do
cache de detalhes após a exclusão.
In `@frontend/src/routes/projects`.$projectId.module.css:
- Around line 347-360: Remove the unused CSS selectors `.codeViewer`,
`.formTextarea`, and `.formEditor` from the stylesheet, confirming they have no
remaining frontend references before deletion.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI (base), Organization UI (inherited)
Review profile: CHILL
Plan: Pro
Run ID: 9da94837-35f0-491c-b004-bc3ce795884f
⛔ Files ignored due to path filters (4)
frontend/package-lock.jsonis excluded by!**/package-lock.jsonfrontend/public/favicon.svgis excluded by!**/*.svgfrontend/public/icons.svgis excluded by!**/*.svgfrontend/src/assets/logo-devaulty.svgis excluded by!**/*.svg
📒 Files selected for processing (33)
backend/src/main/java/com/devaulty/backend/infrastructure/security/WebConfig.javafrontend/.gitignorefrontend/README.mdfrontend/eslint.config.jsfrontend/index.htmlfrontend/package.jsonfrontend/src/api/client.tsfrontend/src/components/DashboardView.tsxfrontend/src/components/LogoDevaulty.tsxfrontend/src/components/ProjectDetailView.tsxfrontend/src/components/RootLayout.tsxfrontend/src/components/ThemeProvider.tsxfrontend/src/features/projects/api/projectsApi.tsfrontend/src/features/projects/components/ProjectForm.module.cssfrontend/src/features/projects/components/ProjectForm.tsxfrontend/src/features/projects/hooks/useProjects.tsfrontend/src/features/snippets/api/snippetsApi.tsfrontend/src/features/snippets/hooks/useSnippets.tsfrontend/src/hooks/useTheme.tsfrontend/src/index.cssfrontend/src/main.tsxfrontend/src/routeTree.gen.tsfrontend/src/routes/__root.module.cssfrontend/src/routes/__root.tsxfrontend/src/routes/index.module.cssfrontend/src/routes/index.tsxfrontend/src/routes/projects.$projectId.module.cssfrontend/src/routes/projects.$projectId.tsxfrontend/src/types/api.tsfrontend/tsconfig.app.jsonfrontend/tsconfig.jsonfrontend/tsconfig.node.jsonfrontend/vite.config.ts
…ing to browser history, and refine UI state management and API configuration.
There was a problem hiding this comment.
🧹 Nitpick comments (1)
frontend/src/components/ProjectDetailView.tsx (1)
163-181: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winExtraia o allowlist de ícones para um util compartilhado
ICON_MAPPINGegetIconComponentestão duplicados emfrontend/src/components/ProjectDetailView.tsx,frontend/src/components/DashboardView.tsxefrontend/src/components/RootLayout.tsx. Centralizar isso em um módulo comum evita divergência quando novos ícones forem adicionados.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@frontend/src/components/ProjectDetailView.tsx` around lines 163 - 181, Centralize the duplicated ICON_MAPPING allowlist and getIconComponent helper into a shared frontend utility module. Update ProjectDetailView, DashboardView, and RootLayout to import and use the shared symbols, removing their local definitions while preserving the existing fallback to Icons.Folder and icon type support.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@frontend/src/components/ProjectDetailView.tsx`:
- Around line 163-181: Centralize the duplicated ICON_MAPPING allowlist and
getIconComponent helper into a shared frontend utility module. Update
ProjectDetailView, DashboardView, and RootLayout to import and use the shared
symbols, removing their local definitions while preserving the existing fallback
to Icons.Folder and icon type support.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI (base), Organization UI (inherited)
Review profile: CHILL
Plan: Pro
Run ID: c4dd86b4-e439-4451-945a-3aa203bb4438
📒 Files selected for processing (7)
frontend/src/api/client.tsfrontend/src/components/DashboardView.tsxfrontend/src/components/ProjectDetailView.tsxfrontend/src/components/RootLayout.tsxfrontend/src/features/projects/components/ProjectForm.tsxfrontend/src/main.tsxfrontend/vite.config.ts
🚧 Files skipped from review as they are similar to previous changes (5)
- frontend/src/api/client.ts
- frontend/vite.config.ts
- frontend/src/features/projects/components/ProjectForm.tsx
- frontend/src/components/DashboardView.tsx
- frontend/src/components/RootLayout.tsx
This pull request introduces the initial setup for the frontend and backend integration, including configuration for CORS, project dashboard UI, API client, and development tooling. The main changes are the addition of CORS support in the backend, a comprehensive React-based frontend with project management features, and configuration for linting and development dependencies.
Backend Integration
WebConfigclass to configure CORS in the backend, allowing frontend requests fromhttp://localhost:5173to the/api/**endpoints and supporting common HTTP methods.Frontend Project Bootstrapping
package.jsonwith essential dependencies for React, routing, API calls, styling, and development tools, establishing the foundation for the frontend application..gitignoreto exclude build artifacts, logs, and IDE/editor files from version control.index.htmland a custom SVG logo component (LogoDevaulty.tsx). [1] [2]Frontend Features: Project Dashboard and API Client
DashboardViewcomponent for managing projects, including creating, editing, archiving, unarchiving, and deleting projects, with UI feedback and error handling.apiClient) using Axios, with custom error handling via theApiErrorclass to standardize error responses throughout the app.Development Tooling
eslint.config.js) with recommended rules for JavaScript, TypeScript, React hooks, and Vite integration, promoting code quality and consistency.README.mdwith guidance on expanding ESLint rules and using React/Vite tooling.Summary by CodeRabbit
Novos Recursos
Melhorias
Documentação