From c790159250388c54e877a1c52d8cda5943aa0187 Mon Sep 17 00:00:00 2001 From: nala Date: Tue, 10 Nov 2026 18:07:50 +0200 Subject: [PATCH] Restore prominent Concursos dropdown before authorized APIEX and SWOT delivery --- .../unification/traceability-and-manual.md | 6 +++ docs/investmoz/v2/auditoria-portal/backlog.md | 6 +++ .../visao-consolidada-modulos.md | 6 +++ .../js/components/portal-grouped-menu.tsx | 12 +++-- resources/js/lib/portal-navigation.ts | 33 ++++++++++---- tests/frontend/portal-navigation.test.mjs | 44 +++++++++++++++++++ 6 files changed, 95 insertions(+), 12 deletions(-) diff --git a/docs/investmoz/unification/traceability-and-manual.md b/docs/investmoz/unification/traceability-and-manual.md index 7bb1ed92..c043be7f 100644 --- a/docs/investmoz/unification/traceability-and-manual.md +++ b/docs/investmoz/unification/traceability-and-manual.md @@ -1,3 +1,9 @@ +## 10/11/2026 — Concursos visíveis no menu principal; instalação agrupada autorizada + +Conferência delimitada do destino7476dc34 por SSH autenticado: `procurement.enabled=true`, módulo disponível, tabelas presentes; `/concursos` e raiz HTTP200 com `procurementEnabled=true`. Preservados um concurso em rascunho e zero versões publicadas. O módulo não desapareceu nem estava desligado: a ligação estava dentro de Descoberta. Pedido Tempo «onde foram parar concurso? depois de resolver isso autorizo a instalação»: entrada promovida a grupo próprio **Concursos e anúncios** no menu horizontal comum, com **Consultar concursos e anúncios** e, após autenticação, **Os concursos que acompanho**. Retirada só a ligação duplicada de Descoberta; cinco atalhos principais e autorizações editoriais preservados. Não cria/publica concursos nem muda flags, dados ou schema. + +Prova dirigida da navegação:20casos aprovados, incluindo visitante/utilizador, disponibilidade, destinos únicos e selecção correcta de catálogo/ficha/acompanhamentos. Tipos/lint/compilação QA aprovados. Observação anterior `outputs/investment-preparation-20261110/concursos-before.json`; pacote agrupado `outputs/entrega-apiex-swot-concursos-20261110.zip`, preservando o pacote APIEX/SWOT anterior. O conjunto APIEX/SWOT abaixo conserva as provas aceites, sem repetição. Instalação autorizada expressamente após esta correcção; execução e recibo final separados desta prova QA. Visual continua pendente por indisponibilidade do conector. + ## 10/11/2026 — APIEX e SWOT no dossier existente: QA concluído, instalação pendente **Instalado:** `7476dc343098f15a7982e9d7581bf4f59d43bc1a` em https://teste-investidor.tempo.co.mz, promovido às14:28:12UTC e conferido às14:29:07UTC (16:29 locais). Transporte CBF15 deixa de ser pendência de instalação. Delta14hashes Git/HTTPS, root/up/login/revision200, configuração intacta, zero migrations/importações; backup/restauro190tabelas e369ficheiros conferidos. Recibos `outputs/cbf15-carry-delivery-20261110/`; release anterior e pacotes preservados. diff --git a/docs/investmoz/v2/auditoria-portal/backlog.md b/docs/investmoz/v2/auditoria-portal/backlog.md index 4dd4ebbc..bc8af9c5 100644 --- a/docs/investmoz/v2/auditoria-portal/backlog.md +++ b/docs/investmoz/v2/auditoria-portal/backlog.md @@ -1,3 +1,9 @@ +## 10/11/2026 — Concursos visíveis no menu principal; instalação agrupada autorizada + +Conferência delimitada do destino7476dc34 por SSH autenticado: `procurement.enabled=true`, módulo disponível, tabelas presentes; `/concursos` e raiz HTTP200 com `procurementEnabled=true`. Preservados um concurso em rascunho e zero versões publicadas. O módulo não desapareceu nem estava desligado: a ligação estava dentro de Descoberta. Pedido Tempo «onde foram parar concurso? depois de resolver isso autorizo a instalação»: entrada promovida a grupo próprio **Concursos e anúncios** no menu horizontal comum, com **Consultar concursos e anúncios** e, após autenticação, **Os concursos que acompanho**. Retirada só a ligação duplicada de Descoberta; cinco atalhos principais e autorizações editoriais preservados. Não cria/publica concursos nem muda flags, dados ou schema. + +Prova dirigida da navegação:20casos aprovados, incluindo visitante/utilizador, disponibilidade, destinos únicos e selecção correcta de catálogo/ficha/acompanhamentos. Tipos/lint/compilação QA aprovados. Observação anterior `outputs/investment-preparation-20261110/concursos-before.json`; pacote agrupado `outputs/entrega-apiex-swot-concursos-20261110.zip`, preservando o pacote APIEX/SWOT anterior. O conjunto APIEX/SWOT abaixo conserva as provas aceites, sem repetição. Instalação autorizada expressamente após esta correcção; execução e recibo final separados desta prova QA. Visual continua pendente por indisponibilidade do conector. + ## 10/11/2026 — APIEX e SWOT no dossier existente: QA concluído, instalação pendente **Instalado:** `7476dc343098f15a7982e9d7581bf4f59d43bc1a` em https://teste-investidor.tempo.co.mz, promovido às14:28:12UTC e conferido às14:29:07UTC (16:29 locais). Transporte CBF15 deixa de ser pendência de instalação. Delta14hashes Git/HTTPS, root/up/login/revision200, configuração intacta, zero migrations/importações; backup/restauro190tabelas e369ficheiros conferidos. Recibos `outputs/cbf15-carry-delivery-20261110/`; release anterior e pacotes preservados. diff --git a/docs/investmoz/v2/auditoria-portal/visao-consolidada-modulos.md b/docs/investmoz/v2/auditoria-portal/visao-consolidada-modulos.md index 84c496b7..be7aff8e 100644 --- a/docs/investmoz/v2/auditoria-portal/visao-consolidada-modulos.md +++ b/docs/investmoz/v2/auditoria-portal/visao-consolidada-modulos.md @@ -1,3 +1,9 @@ +## 10/11/2026 — Concursos visíveis no menu principal; instalação agrupada autorizada + +Conferência delimitada do destino7476dc34 por SSH autenticado: `procurement.enabled=true`, módulo disponível, tabelas presentes; `/concursos` e raiz HTTP200 com `procurementEnabled=true`. Preservados um concurso em rascunho e zero versões publicadas. O módulo não desapareceu nem estava desligado: a ligação estava dentro de Descoberta. Pedido Tempo «onde foram parar concurso? depois de resolver isso autorizo a instalação»: entrada promovida a grupo próprio **Concursos e anúncios** no menu horizontal comum, com **Consultar concursos e anúncios** e, após autenticação, **Os concursos que acompanho**. Retirada só a ligação duplicada de Descoberta; cinco atalhos principais e autorizações editoriais preservados. Não cria/publica concursos nem muda flags, dados ou schema. + +Prova dirigida da navegação:20casos aprovados, incluindo visitante/utilizador, disponibilidade, destinos únicos e selecção correcta de catálogo/ficha/acompanhamentos. Tipos/lint/compilação QA aprovados. Observação anterior `outputs/investment-preparation-20261110/concursos-before.json`; pacote agrupado `outputs/entrega-apiex-swot-concursos-20261110.zip`, preservando o pacote APIEX/SWOT anterior. O conjunto APIEX/SWOT abaixo conserva as provas aceites, sem repetição. Instalação autorizada expressamente após esta correcção; execução e recibo final separados desta prova QA. Visual continua pendente por indisponibilidade do conector. + ## 10/11/2026 — APIEX e SWOT no dossier existente: QA concluído, instalação pendente **Instalado:** `7476dc343098f15a7982e9d7581bf4f59d43bc1a` em https://teste-investidor.tempo.co.mz, promovido às14:28:12UTC e conferido às14:29:07UTC (16:29 locais). Transporte CBF15 deixa de ser pendência de instalação. Delta14hashes Git/HTTPS, root/up/login/revision200, configuração intacta, zero migrations/importações; backup/restauro190tabelas e369ficheiros conferidos. Recibos `outputs/cbf15-carry-delivery-20261110/`; release anterior e pacotes preservados. diff --git a/resources/js/components/portal-grouped-menu.tsx b/resources/js/components/portal-grouped-menu.tsx index f6a0bf89..498b8347 100644 --- a/resources/js/components/portal-grouped-menu.tsx +++ b/resources/js/components/portal-grouped-menu.tsx @@ -131,9 +131,14 @@ export function PortalGroupedMenu() { ); const accountGroups = groups.filter( (group) => - !['home', 'discovery', 'realization', 'support', 'work'].includes( - group.id, - ), + ![ + 'home', + 'procurement-area', + 'discovery', + 'realization', + 'support', + 'work', + ].includes(group.id), ); const institutionalCurrent = url.split('?')[0] === '/contacto'; return ( @@ -195,6 +200,7 @@ export function PortalGroupedMenu() { {groups .filter((group) => [ + 'procurement-area', 'discovery', 'realization', 'support', diff --git a/resources/js/lib/portal-navigation.ts b/resources/js/lib/portal-navigation.ts index 433c805c..3b6e8065 100644 --- a/resources/js/lib/portal-navigation.ts +++ b/resources/js/lib/portal-navigation.ts @@ -478,6 +478,30 @@ export function portalNavigation(access: PortalNavAccess): PortalNavItem[] { : null) : null; return uniqueNavigationDestinations([ + ...(access.procurement + ? [ + { + id: 'procurement-area', + label: 'Concursos e anúncios', + children: [ + link( + 'procurement', + 'Consultar concursos e anúncios', + '/concursos', + ), + ...(access.authenticated + ? [ + link( + 'procurement-watched', + 'Os concursos que acompanho', + '/concursos/acompanhar', + ), + ] + : []), + ], + }, + ] + : []), { id: 'discovery', label: 'Descoberta', @@ -501,15 +525,6 @@ export function portalNavigation(access: PortalNavAccess): PortalNavItem[] { : []), ] : []), - ...(access.procurement - ? [ - link( - 'procurement', - 'Concursos e anúncios', - '/concursos', - ), - ] - : []), { id: 'related-catalogues', label: 'Catálogos relacionados', diff --git a/tests/frontend/portal-navigation.test.mjs b/tests/frontend/portal-navigation.test.mjs index 92bde936..911aedd9 100644 --- a/tests/frontend/portal-navigation.test.mjs +++ b/tests/frontend/portal-navigation.test.mjs @@ -404,3 +404,47 @@ void test('funding links require installation and saved list requires authentica true, ); }); + +void test('installed concours has its own primary group and preserves public and private destinations', () => { + const base = { authenticated: false, manager: false }; + assert.equal( + portalNavigation(base).some((g) => g.id === 'procurement-area'), + false, + ); + for (const authenticated of [false, true]) { + const groups = portalNavigation({ + ...base, + authenticated, + procurement: true, + }); + const group = groups.find((g) => g.id === 'procurement-area'); + assert.equal(group.label, 'Concursos e anúncios'); + assert.equal( + destinations(groups).filter((h) => h === '/concursos').length, + 1, + ); + assert.equal( + JSON.stringify(groups.find((g) => g.id === 'discovery')).includes( + '/concursos', + ), + false, + ); + assert.equal( + currentNavigationGroup(groups, '/concursos?q=obras'), + 'procurement-area', + ); + assert.equal( + currentNavigationGroup(groups, '/concursos/fixture'), + 'procurement-area', + ); + assert.equal( + destinations(group.children).includes('/concursos/acompanhar'), + authenticated, + ); + if (authenticated) + assert.equal( + currentNavigationItem(groups, '/concursos/acompanhar'), + 'procurement-watched', + ); + } +});