Skip to content

feat: renomear pastas e arquivos (LUI-180) - #15

Merged
argentinaluiz merged 4 commits into
mainfrom
feature/lui-180-renomear-pastas-e-arquivos
Oct 16, 2026
Merged

argentinaluiz merged 4 commits into
mainfrom
feature/lui-180-renomear-pastas-e-arquivos

Conversation

@argentinaluiz

Copy link
Copy Markdown
Contributor

O que muda

PATCH /items/{id} renomeia uma pasta ou um arquivo ativo do Usuário (só o name nesta entrega). A Pasta raiz é recusada com validation_error, e o que o Usuário não enxerga responde not_found. Na web, a linha de pasta ganha o "Mais ações" e as duas linhas ganham "Renomear", com um diálogo que abre com o nome atual todo selecionado.

Fora do plano: MenuItem ganhou closeOnClick, e OpenableRow ignora o duplo clique que vem de botão, menu ou diálogo.

Aceite

docs/tickets/LUI-177/LUI-180/aceite.md

🤖 Generated with Claude Code

argentinaluiz and others added 2 commits October 15, 2026 20:27
Acceptance file docs/tickets/LUI-177/LUI-180/aceite.md (CA1-CA9). The OpenAPI snapshot gains PATCH /items/{id} (UpdateItemDto with only name, 200 ItemDto) and the UpdateItemDto schema; no table changes.

Decision: the route is the LLD's PATCH /items/{id}, with only name in this delivery. name is required now, and LUI-181 relaxes it to name and/or parentId, a change that breaks no client. A body with no field is therefore validation_error, as the ticket asks.

Decision: renaming the root folder answers validation_error, and not_found stays for what the User cannot see (missing, another User's, pending, not a UUID). The root's name is fixed, so the request is invalid input, and no new error code is needed. The root alias is accepted in the path, as in GET /items/{id}, and leads to the same refusal.

Decision: the rename takes no advisory lock, because it changes neither the depth nor the shape of the tree; only the move (LUI-181) needs it.

Decision: the name rules are shared with the folder creation (trimmed ends, 1 to 255 characters measured after the trim, no "/" or control characters), by extracting the name decorators the CreateFolderDto uses, so the two routes never drift apart.

Decision: the download needs no change, because downloadUrl reads the name from the item row at each call, so CA5 is proved by a test only.

Decision: the row menu moves to a client component that owns the rename dialog, because the Menu unmounts its items when it closes and would take the dialog with it. The folder row gains the "Mais ações" button, with "Renomear" only; "Mover para…" comes with LUI-181 and "Excluir" with the trash.

Files and interfaces the implementation will touch:
- apps/api/src/modules/items: ItemsController.update (PATCH :id), ItemsService.rename and ItemsRepository.rename (reads the active item of the owner, refuses the root, updates the name); dto/update-item.dto.ts; the name decorators extracted from dto/create-folder.dto.ts.
- apps/api/openapi.json: regenerated from the controller and the DTO; it must match the snapshot of this plan.
- apps/api/test: items-rename.e2e-spec.ts and the rename call in support/items.ts.
- apps/web: updateItem in lib/api/items.ts and its input type in lib/api/types.ts, renameItem in lib/dal/items.ts, the renameItem Server Action in app/(drive)/actions.ts, components/files/row-actions.tsx (menu and dialog) and rename-dialog.tsx, used by file-row.tsx.
- apps/web/e2e: rename.spec.ts.
- docs/lld.md: section 3.3 (the PATCH route with only the name for now) and the web section that says the folder row has no "Mais ações" button.

Existing tests whose behavior changes: none.

Data changes: none.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
PATCH /items/{id} changes the name of an active item of the User. The root
folder is refused with validation_error and anything the User cannot see is
not_found. The row menu gains "Renomear" on files and folders, with a dialog
that opens with the current name fully selected.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Copilot AI lite review requested due to automatic review settings October 15, 2026 23:58

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Há problemas pendentes de atomicidade na persistência e de atualização/composição da interface.

2 open findings
What changed in this PR

Implementa a renomeação de arquivos e pastas via API e interface web.

Changes:

  • Adiciona PATCH /items/{id}, validações e testes E2E.
  • Adiciona menus, diálogo e Server Action de renomeação.
  • Atualiza documentação e contrato OpenAPI.
File Description
docs/​tickets/​LUI-177/​LUI-180/​aceite.md Critérios de aceite
docs/​lld.md Contrato funcional atualizado
apps/​web/​lib/​dal/​items.ts DAL de renomeação
apps/​web/​lib/​api/​types.ts Tipos da atualização
apps/​web/​lib/​api/​items.ts Cliente da API
apps/​web/​e2e/​rename.spec.ts Testes Playwright
apps/​web/​components/​ui/​menu.tsx Fechamento configurável do menu
apps/​web/​components/​files/​row-actions.tsx Ações da linha
apps/​web/​components/​files/​rename-dialog.tsx Diálogo de renomeação; requer atualização das páginas carregadas
apps/​web/​components/​files/​openable-row.tsx Filtragem de duplo clique em controles
apps/​web/​components/​files/​file-row.tsx Integração das ações; requer suporte à vitrine
apps/​web/​app/​(drive)/​actions.ts Server Action e validações
apps/​api/​test/​support/​items.ts Helper HTTP
apps/​api/​test/​items-rename.e2e-spec.ts Testes E2E da API
apps/​api/​src/​modules/​items/​items.service.ts Regras de negócio
apps/​api/​src/​modules/​items/​items.repository.ts Persistência; requer atualização atômica
apps/​api/​src/​modules/​items/​items.controller.ts Endpoint PATCH
apps/​api/​src/​modules/​items/​entities/​item.entity.ts Resultado da renomeação
apps/​api/​src/​modules/​items/​dto/​update-item.dto.ts DTO da requisição
apps/​api/​openapi.json Contrato OpenAPI

🧠 Review effort: Lite


💡 Add a code-review agent skill for context-aware, tailored reviews. Learn more in the docs.

Comment thread apps/api/src/modules/items/items.repository.ts Outdated
Comment thread apps/web/components/files/rename-dialog.tsx
argentinaluiz and others added 2 commits October 16, 2026 01:56
…UI-180)

O renomear lia e gravava em operações separadas, deixando uma janela em
que o item podia mudar de estado. Agora é um UPDATE condicional, e só
sem linha afetada a leitura distingue Pasta raiz de not_found.

O router.refresh() só refaz a primeira página, então a linha vinda de
"Carregar mais" ficava com o nome antigo. O LoadMoreProvider ganhou
reset(), chamado pelo diálogo de renomear.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@argentinaluiz
argentinaluiz merged commit 58de801 into main Oct 16, 2026
2 checks passed
@argentinaluiz

Copy link
Copy Markdown
Contributor Author

Revisão de conformidade: LUI-180

# Severidade Achado Situação Motivo
1 média console.log('Hello, world!') solto em apps/api/src/main.ts, fora do plano. Não corrigido A linha está só no working tree do usuário e nunca entrou em commit nem no PR; o diff do revisor inclui o working tree. Ela não é desta mudança, e o usuário a desfaz com git restore apps/api/src/main.ts.
2 baixa O descarte das páginas acrescentadas depois de renomear não está no LLD, que só diz que elas "ficam como estavam" depois de um upload. Corrigido A seção "Paginação das listas" do docs/lld.md agora registra que o diálogo de renomear descarta as páginas acrescentadas e volta à primeira página.
3 baixa O duplo clique em button, dialog ou [role="menu"] deixou de abrir a pasta, o que não está no plano. Não corrigido É consequência necessária de o diálogo viver dentro da linha: sem o guard, um duplo clique no diálogo abriria a pasta. Fica registrado aqui; o teste CA9 cobre o diálogo.
4 baixa O teste de "Carregar mais" depois de renomear não tem ID de critério. Não corrigido O aceite está congelado, e só o usuário o descongela. O teste cobre o achado 2 e passa a valer como regressão sem ID.
5 baixa Desvio de forma: PickType(CreateFolderDto, ['name']) e renameActive, em vez da extração dos decoradores e de ItemsRepository.rename citados no plano. Não corrigido O objetivo do plano (regras de nome compartilhadas) é atendido e o contrato bate com o plano; a extração literal não traria ganho.
Relatório do revisor, na íntegra

Achados

# Severidade Onde Achado Direção da correção
1 média apps/api/src/main.ts:16 (diff: +console.log('Hello, world!');, antes do await bootstrap()) Linha de depuração solta na inicialização da API. Nenhum critério do LUI-180 a pede, nem o plano a lista entre os arquivos. A API passa a imprimir esse texto em todo boot, em produção também. Remover a linha e deixar main.ts sem alteração.
2 baixa apps/web/components/files/load-more.tsx (reset, useResetLoadedPages) e docs/lld.md:~1396 (seção "Paginação das listas") A mudança passa a descartar as páginas acrescentadas por "Carregar mais" depois de renomear. O LLD diz que as páginas acrescentadas "ficam como estavam" depois de um upload e não menciona o descarte depois de renomear. Nenhum critério nem o plano pedem esse comportamento, e o documento dono não mudou junto. Registrar a regra do descarte no LLD, seção de paginação das listas, ou tirar o reset e ficar com o router.refresh().
3 baixa apps/web/components/files/openable-row.tsx (onDoubleClick) O duplo clique em button, dialog ou [role="menu"] deixou de abrir a pasta. Isso não está no aceite nem no plano. O LLD diz que o duplo clique ainda não faz nada. É consequência necessária do diálogo dentro da linha, mas ficou fora do plano. Registrar a decisão na mensagem ou no PR, ou cobrir o caso com um teste atrelado a um critério.
4 baixa apps/web/e2e/rename.spec.ts (último teste, "renomear um item de uma página carregada por Carregar mais...") O teste não traz tag de ID, então nenhum critério o cobre. Ele prova o comportamento do achado 2. A CI aceita teste sem ID, mas o comportamento não está no aceite congelado. Se o comportamento ficar, o usuário decide se descongela o aceite para dar um ID a ele.
5 baixa apps/api/src/modules/items/dto/update-item.dto.ts:8 e items.repository.ts:~192 O plano dizia "extrair os decoradores de nome do CreateFolderDto" e nomeava ItemsRepository.rename. A implementação usa PickType(CreateFolderDto, ['name']) e renameActive. O objetivo (regras de nome compartilhadas) é atendido e o contrato bate. Registro só como desvio de forma em relação à mensagem de plano. Nenhuma, salvo se o usuário quiser a extração literal.

O que conferi sem achado

  • Critérios contra o aceite: os IDs CA1 a CA9 do ticket no Linear coincidem com os títulos de docs/tickets/LUI-177/LUI-180/aceite.md. Não falta nenhum critério no arquivo. O arquivo é novo no PR, então não houve alteração de aceite congelado.
  • Desvio do contrato: contract-drift.txt diz "iguais ao planejado" no commit 71f9d20. No diff, PATCH /items/{id} e UpdateItemDto são aditivos. A única alteração além deles é a reordenação do ItemListDto e do enum do parâmetro type, que não muda o contrato. Não há quebra.
  • Testes contra os cenários: CA1 a CA9 têm teste com a tag @LUI-180-CAn, e as asserções que li batem com o Dado, Quando, Então.
  • Documento dono: o LLD mudou junto, na linha da rota e na linha da lista da web.

O que não consegui conferir

  • Não rodei código nem testes, então não sei se os testes passam. Nem o conteúdo exato de CreateFolderDto (o trim e o limite de 255 caracteres herdados por PickType) eu li. Li só o diff e os documentos pedidos.
  • Não li items.service.ts inteiro, então não verifiquei como folderIdOf trata id que não é UUID (CA4). Também não li items.repository.ts inteiro. O git status do início mostra essas alterações como ainda sem commit. O diff as inclui, mas não confirmei que ele reflete o estado final do disco.
  • Não conferi a atualização do updatedAt (CA1) em renameActive. O UPDATE do Prisma depende de @updatedAt no schema, e não li o schema.prisma.
  • A validação visual do diálogo e do menu com o Figma (docs/design-system.md) não é verificável por mim.
  • Não conferi lib/dal/session nem as mensagens de errorMessage usadas nos erros do diálogo.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants