Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
There was a problem hiding this comment.
Pull request overview
This PR updates the app’s pagination UX in the frontend and adjusts the backend server entry to register Swagger docs via dynamic imports, alongside dependency updates and an added Windows installer artifact.
Changes:
- Added Swagger dependencies and updated backend server startup to register
/docsvia dynamic imports (with tests updated accordingly). - Reworked frontend jobs pagination: numeric pagination controls, results summary, and clamped page-size behavior (1–10) with updated unit tests.
- Added
Vagas Full Setup 1.0.0.exeto the repository.
Reviewed changes
Copilot reviewed 8 out of 10 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| Vagas Full Setup 1.0.0.exe | Adds a built Windows installer artifact to the repo. |
| package.json | Adds Swagger deps and reformats electron-builder arch config. |
| package-lock.json | Locks new Swagger dependencies. |
| frontend/src/hooks/useJobsPagination.ts | Clamps page size (1–10) and changes default page size to 4. |
| frontend/src/components/JobsTableCard.tsx | Replaces previous pagination controls with numeric pagination + arrows and adds results footer + page-size input. |
| frontend/src/App.tsx | Removes unused jobs prop passed to JobsTableCard. |
| frontend/tests/unit/utils/useJobsPagination.test.ts | Fixes state-update testing by using act() and adds page-size clamp coverage. |
| frontend/tests/unit/components/JobsTableCard.test.tsx | Updates tests for new pagination UI and results summary. |
| backend/src/server.js | Registers Swagger docs with dynamic imports; refactors startup into startServer(). |
| backend/tests/unit/services/server.test.js | Updates mocks and assertions for dynamic Swagger registration and updated middleware order. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| // Router (if used in future) works correctly. | ||
| app.use((req, res) => { | ||
| if (req.path.startsWith("/api")) { | ||
| return res.status(404).json({ error: "Rota não encontrada." }); |
There was a problem hiding this comment.
O fallback para rotas que começam com "/api" responde com { error: ... }, mas o restante da API usa o campo message para erros (ex.: jobsApiApp.js retorna { message: ... }). Para manter consistência com o parser de erros do frontend e com os outros endpoints, troque para { message: "Rota não encontrada." } (ou alinhe o contrato de erro em um único formato).
| return res.status(404).json({ error: "Rota não encontrada." }); | |
| return res.status(404).json({ message: "Rota não encontrada." }); |
| async function registerSwaggerDocs() { | ||
| try { | ||
| const [{ default: swaggerUi }, { default: swaggerSpec }] = await Promise.all([ | ||
| import("swagger-ui-express"), | ||
| import("./swagger.js"), | ||
| ]); | ||
|
|
||
| app.use("/docs", swaggerUi.serve, swaggerUi.setup(swaggerSpec)); |
There was a problem hiding this comment.
registerSwaggerDocs() sempre tenta importar ./swagger.js, mas o swagger-jsdoc nesse arquivo usa caminhos baseados em process.cwd() (ex.: path.resolve("src/**/*.js")), o que pode quebrar quando o backend é iniciado via Electron a partir do workspace root. Isso pode fazer a documentação ficar vazia/sem endpoints. Sugestão: tornar o swaggerSpec independente do cwd (ex.: construir o glob relativo a import.meta.url/__dirname do backend).
| async function registerSwaggerDocs() { | ||
| try { | ||
| const [{ default: swaggerUi }, { default: swaggerSpec }] = await Promise.all([ | ||
| import("swagger-ui-express"), | ||
| import("./swagger.js"), | ||
| ]); | ||
|
|
||
| app.use("/docs", swaggerUi.serve, swaggerUi.setup(swaggerSpec)); | ||
| } catch (error) { | ||
| // eslint-disable-next-line no-console | ||
| console.warn("Swagger desabilitado:", error instanceof Error ? error.message : error); | ||
| } | ||
| } | ||
| //Swagger documentacao | ||
| app.use("/docs", swaggerUi.serve, swaggerUi.setup(swaggerSpec)); | ||
|
|
||
| app.listen(PORT, () => { | ||
| // eslint-disable-next-line no-console | ||
| console.log(`API de vagas rodando em http://localhost:${PORT}`); | ||
| console.log(`Documentação da API em http://localhost:${PORT}/docs`); | ||
| async function startServer() { | ||
| await registerSwaggerDocs(); | ||
|
|
||
| // ── Electron static-file serving ───────────────────────────────────────── | ||
| // When ELECTRON_STATIC_DIR is set, serve the React production build so that | ||
| // the Electron window can load everything from http://localhost:<PORT>. | ||
| const staticDir = process.env.ELECTRON_STATIC_DIR; | ||
| if (staticDir && existsSync(staticDir)) { | ||
| app.use(express.static(staticDir)); | ||
|
|
||
| // SPA catch-all: return index.html for any non-API route so that React | ||
| // Router (if used in future) works correctly. | ||
| app.use((req, res) => { | ||
| if (req.path.startsWith("/api")) { | ||
| return res.status(404).json({ error: "Rota não encontrada." }); | ||
| } | ||
| res.sendFile(path.join(staticDir, "index.html")); | ||
| }); | ||
| } | ||
|
|
||
| app.listen(PORT, () => { | ||
| // eslint-disable-next-line no-console | ||
| console.log(`API de vagas rodando em http://localhost:${PORT}`); | ||
| console.log(`Documentação da API em http://localhost:${PORT}/docs`); | ||
| }); |
There was a problem hiding this comment.
Mesmo quando o Swagger falha ao registrar (catch em registerSwaggerDocs()), o servidor sempre faz log de Documentação da API em .../docs. Isso pode induzir a erro em produção (especialmente no Electron) quando o /docs não estiver disponível. Sugestão: só logar a URL do /docs quando o swagger for registrado com sucesso (ex.: registerSwaggerDocs() retornar boolean) ou ajustar o log para indicar que é opcional.
| min={1} | ||
| max={10} | ||
| step={1} | ||
| className="w-14 rounded-md bg-transparent text-center font-semibold text-foreground outline-none" |
There was a problem hiding this comment.
O input de itens por página está com outline-none e não adiciona nenhum estilo focus-visible/ring. Isso remove o indicador de foco do teclado, prejudicando acessibilidade. Sugestão: usar o componente Input existente ou adicionar classes focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring (ou equivalente do projeto).
| className="w-14 rounded-md bg-transparent text-center font-semibold text-foreground outline-none" | |
| className="w-14 rounded-md bg-transparent text-center font-semibold text-foreground outline-none focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2" |
| <nav className="flex items-center gap-1 self-end md:self-auto" aria-label="Paginação"> | ||
| <button | ||
| type="button" | ||
| aria-label="Pagina anterior" |
There was a problem hiding this comment.
No aria-label, "Pagina" deveria ser "Página" (com acento) para manter ortografia correta em texto exposto a leitores de tela.
|
|
||
| <button | ||
| type="button" | ||
| aria-label="Pagina seguinte" |
There was a problem hiding this comment.
No aria-label, "Pagina" deveria ser "Página" (com acento) para manter ortografia correta em texto exposto a leitores de tela.
No description provided.