Skip to content

release: glossary versioning per portfolio, expired sessions that log out, and the visual revamp - #201

Merged
SantiagoSC1999 merged 33 commits into
mainfrom
staging
Sep 15, 2026
Merged

SantiagoSC1999 merged 33 commits into
mainfrom
staging

Conversation

@yecksin

@yecksin yecksin commented Sep 15, 2026

Copy link
Copy Markdown
Contributor

Promueve a producción el versionamiento del glosario por portafolio y el arreglo de sesión expirada (#200), más el rediseño visual del front y el botón Sign in de la barra pública (#203, que incluye #202).

Rediseño visual (#203) — solo front

  • Barra pública nueva con el botón Sign in que lleva directo al login (ticket 161964).
  • Pantalla de acceso en panel dividido; deja de descargar la foto de 7,16 MB.
  • Panel de administración con sidebar fijo (Manage / Access / System): antes, al entrar, quedabas en un solo módulo sin forma de llegar a los otros.
  • Glosario público con un riel de versiones por portafolio: cada segmento es una definición.
  • Tema de PrimeNG recoloreado a la paleta de marca desde un generador, fijado por test.

Sin cambios de back ni migraciones. Desplegado y verificado en clarisatest; SonarCloud OK.

Qué cambia para quien usa la plataforma

Un término del glosario puede significar cosas distintas en cada portafolio del CGIAR. Hasta hoy el módulo de administración lo impedía —findByTitle respondía 409 ante cualquier título repetido, sin mirar el portafolio ni si la fila que chocaba llevaba desactivada desde 2023— así que esas definiciones se venían escribiendo directamente en la base de datos.

A partir de este release se gestionan desde el panel:

  • Separar un término compartido en una versión por portafolio, cada una con su definición.
  • Unir dos versiones que resultaron decir lo mismo; la fila que queda vacía se desactiva, nunca se borra.
  • Relacionar dos filas existentes como versiones de un mismo concepto. La relación se declara, no se infiere: las dos parejas que la necesitan difieren por un espacio duro en el título.
  • Ver y corregir los términos sin portafolio vinculado, que no aparecen bajo ningún filtro de la página pública.

La página pública dibuja una tarjeta por concepto, con los chips de todos sus portafolios y la definición que aplica al portafolio filtrado.

Y se corrige un defecto de sesión: una sesión vencida dejaba al usuario dentro del panel con todas las pantallas fallando en silencio. Ahora el guard rechaza un exp vencido y el interceptor cierra sesión ante un 401.

Migración

Migraciones 34 → 35. Una sola, y no toca ningún dato:

ALTER TABLE glossary ADD COLUMN group_id bigint NULL
CREATE INDEX IDX_glossary_group_id ON glossary (group_id)

NULL significa "esta fila es su propio concepto", que es el estado de las 308 filas que hoy tiene producción. Nada cambia de comportamiento hasta que alguien agrupe algo a propósito. Es idempotente: se apoya en INFORMATION_SCHEMA, porque en MySQL cada DDL confirma por su cuenta y una ejecución a medias no se revierte sola.

⚠️ Este release no replica datos. Los términos de producción se quedan exactamente como están.

Contrato público

GET api/glossary gana la clave groupId y puede devolver el mismo term más de una vez cuando alguien lo versione — una entrada por versión, distinguibles por portfolios[]. Los términos no versionados siguen devolviendo una sola entrada con las mismas claves. Hoy no hay ninguno versionado en producción, así que el payload no cambia el día del release.

Verificación

  • Back 944/944 tests, lint y build limpios. Front 360/360 con el rediseño incluido, build limpio.
  • Desplegado en clarisatest y validado ahí: groupId publicado en todos los términos y tantos grupos como filas, es decir, la migración no movió ninguna.
  • Validación funcional sobre datos reales: 16 conceptos quedaron con su par 2022-2024 / 2025-2030 correctamente separado y relacionado, sin títulos duplicados sueltos ni términos sin portafolio.
  • Revisado con @santiagosanchezc, que probó el flujo de separación en el panel.

🤖 Generated with Claude Code

yecksin and others added 20 commits September 15, 2026 08:51
A term can mean different things in different CGIAR portfolios, but every
write path in the admin module assumes one row per title: `findByTitle`
matches the title alone, ignores `is_active` and answers 409 even when the
colliding row was deactivated in 2023. The only way to register a
portfolio-specific definition today is to write it into the database by hand,
outside the panel and outside the audit trail.

OpenSpec change with the four artifacts: uniqueness becomes (title,
portfolio), splitting a shared term gets its own endpoint, bulk import matches
by title and portfolio, and an admin-only diagnostics read lists the rows
written outside the panel. No migration: the schema already supports one row
per version.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
A term written straight into `glossary` without its row in
`glossary_portfolios` never shows on the public page: it opens filtered by the
current portfolio, so an unlinked term is only reachable under "All
portfolios". The panel rendered those rows as an empty cell, so they were
invisible from the only screen that can fix them.

The table now counts them, states how many are active, flags each one in the
portfolio column and offers a "No portfolio linked" filter that lists them
whatever their status — so a term can be linked or deactivated from the same
screen. The filter sentinel is negative and lives only in the filter options,
never in the edit dialog, so it can never be saved as a portfolio id.

The dialog hint claimed a term with no portfolio still shows in the glossary.
It stopped being true when the public page started opening on the current
portfolio; corrected.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The notice counted every unlinked row, and the 2023 glossary replacement left
around 240 deactivated ones with no portfolio in every environment (238 in
production, 240 in test). A permanent "241 terms have no portfolio" banner
says nothing about the single active term that is actually missing from the
public page.

It now triggers on the active count and mentions the inactive ones as an
aside. The filter still lists every unlinked term, whatever its status.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…agnostic

Three constraints from Yeck, written into the spec so the implementation
cannot drift from them:

- Nothing is destructive. Every write creates a row or flips `is_active`; no
  DELETE, no dropped column, no key removed from the public payload.
- The panel repairs what is already broken: linking a term that has no
  portfolio, and merging two versions back into one — the emptied row is
  deactivated, so a wrong split costs one click.
- Portfolios stay data. No identifier is hardcoded, so the 2031-2036 portfolio
  becomes a new version, a new pill and a new default with no release.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Two rows that describe the same concept only have different ids in common, so
the panel lists them apart and the public page draws two unrelated cards. That
is the state production is in right now.

Grouping by normalized title does not hold: the two pairs that need it are
`Impact` 86/287 and `Non-IPSR pathway…` 302/347, whose titles differ by a
non-breaking space, and a term can be renamed in one portfolio and not the
other. So the relation is declared from the panel, not inferred.

A nullable `group_id` on `glossary` carries it: NULL means the row is its own
group, so no existing row moves and no read changes. A split inherits the
group, relating is guarded by the same one-portfolio-per-version invariant,
and `groupId` is published so the page can render one card per concept.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
A term means one thing in the 2022-2024 portfolio and another in 2025-2030,
and the glossary could not say so: `findByTitle` answered 409 on any repeated
title, ignoring both the portfolio and whether the colliding row had been
deactivated in 2023. The definitions were being written straight into the
production database instead.

- Uniqueness becomes (term, portfolio): two live versions may share a title as
  long as they do not claim the same portfolio. A deactivated row no longer
  reserves its name.
- `POST terms/:id/versions` splits the listed portfolios into a version with
  its own definition; the source row keeps the rest untouched. `PATCH` keeps
  meaning "edit this row for every portfolio it covers".
- `POST terms/:id/merge` is the inverse: portfolios move to the target and the
  emptied row is deactivated, never deleted.
- `POST/DELETE terms/:id/group` relate two rows as versions of one concept.
  Declared, not inferred: the two pairs that need it in production differ by a
  non-breaking space in the title. `group_id` is nullable — a row that was
  never related is its own group — so no row moves and no read changes.
- Bulk import matches by title and portfolio; a row that could refer to two
  versions is rejected instead of updating whichever one the database returned
  last.

Migration adds the nullable column and its index, guarded on
INFORMATION_SCHEMA so a half-applied run can be repeated.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The panel could only edit a term as a whole, so giving the 2025-2030 portfolio
its own definition meant writing it into the database by hand.

- A term that carries several definitions shows a "N versions" badge, and a new
  row action opens them: each record with its portfolios, its status and its
  definition.
- "Split" moves some portfolios of a record into a version with its own
  definition; the record keeps the rest exactly as it was.
- "Add version" creates the definition of that concept for a portfolio no
  version covers yet, related in the same request.
- "Relate an existing term" brings a row that already exists into the concept —
  needed for the pairs whose titles differ by a non-breaking space, which no
  title match would ever put together — and "Separate" undoes it.
- "Merge into #id" moves the portfolios onto another version and deactivates
  the emptied record, so a split decided by mistake is one click away.

Every dialog says what it does to the data, and none of them deletes a record.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Consumers read `GET api/glossary` and assume one entry per term. Once a
concept carries a definition per portfolio it is published once per version,
so the description now says it, points at `portfolios[]` to tell them apart
and at `groupId` to put them back together.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The versions dialog froze as soon as the "Search a term" dropdown was opened.
Virtual scroll was already on; the cost was not the rendering.

Three template lists were getters returning a new array on each call, and
Angular re-evaluates a getter on every change detection pass:

- the table asked `versionCount()` for every row, and each call scanned all
  ~300 terms — 300 scans of 300 rows per pass;
- the dialog ran a nested `*ngFor` over two freshly built arrays, so the
  differ saw new identities and re-rendered, triggering another pass;
- the relate dropdown rebuilt, mapped and re-sorted 300 labels on every
  keystroke of its own filter, which is where it hung.

They are fields now, computed on the events that change them: the counts once
per load into a map keyed by concept, the dialog rows when it opens, the
relate options when the picker opens, the split portfolios when the split
opens. A spy pins the count to the index so the scan cannot come back.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
A term with a definition per portfolio was drawn twice, with the same name and
one chip each, which reads as two duplicated entries instead of one concept.

Public page: one card per concept. It carries the chips of every portfolio the
concept covers, and the definition that applies — the one of the portfolio
being filtered, or the most recent one when the reader is looking at all of
them. The card keeps the exact shape the template already consumed, so nothing
else in the page changed.

Admin table: one line per concept, showing the version of the newest portfolio
and every portfolio as chips. The line opens into the other definitions, each
with its own record id, portfolio and actions. A filter keeps the concept when
any of its versions matches, so searching a wording that only exists in the
2022-2024 version still finds the term.

"Most recent" is read from the portfolio start years, never from a hardcoded
code, so the portfolio created next takes the lead on its own.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
An expired session left the user inside the panel. The guard only checked that
a `token` key existed, so a token that had expired hours earlier opened every
screen; the interceptor attached it to each request and never looked at the
answer, so the API replied 401 to everything and the panel sat there with
empty tables and no way to tell what was wrong.

- The guard now refuses a session whose `exp` has passed and ends it. It only
  acts when it can prove expiry: a token it cannot parse, or one without `exp`,
  is left to the API — guessing would log out a valid user over a payload shape
  nobody announced.
- The interceptor takes the user out on a 401 from the API, which is the only
  way to catch a token that looks valid but the server no longer accepts. The
  login call is excluded: its 401 means "wrong credentials" and belongs to the
  form. The error still reaches the caller.
- `logout()` clears the credentials before redirecting. It used to navigate,
  reload and clear in that order, so whether the new page saw the old token
  depended on timing.

Verified in the browser against both paths: a token expired by its own clock
never reaches the panel, and one the API rejects lands back on the login page
with `localStorage` empty.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The previous commit ran prettier over the whole `shared/` folder, so 15 files
this work never touched — tawk-to, router-events, redirect.service,
dynamic-table-filters and the legacy routes — travelled with it as pure
reformatting. That is noise in someone else's file and it was not asked for.

Restored to what they were. Only the five files of the session fix remain:
the interceptor, the auth service, the guard and their two specs.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The access screen ran the field photo at full strength with a flat white
rectangle dropped on it. Nothing separated the form from the crop, and the
heading — `#7ab800` on white, 2.3:1 — was the largest and least legible
element on the page.

- The image stays, darkened and slightly desaturated, under a radial wash and
  an inset vignette, so the card is the only lit object on screen.
- The card gets a 14px radius and a single deep shadow; PrimeNG's empty panel
  header, the grey strip at the top, is hidden — it was an artefact, not a
  design.
- Brand green moves off white text and onto what can carry it: the small
  CLARISA line, the focus ring and the button, which is full-width green with
  ink on top — 7.2:1, where white on the same green is 2.4:1 and fails.
- Inputs lose the pill shape (8px), gain a real focus state, and the fields
  gain labels instead of a table grid of inline styles.
- The heading becomes "Sign in" over "Request partners administrator", so the
  screen says what to do before it says where you are.

Typography unchanged: Poppins, already loaded by the app. No new font.

Verified at 1440px and 390px with real screenshots, and the button checked in
its enabled state — not only the disabled one an empty form shows.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The palette was never the real problem: there is no system, so every screen
repeats the colour by hand and nobody can change it in one place.

DESIGN.md now carries what an implementer needs and cannot guess:

- PrimeNG ships `lara-light-blue`, whose `--primary-color` is #3B82F6 — the
  library is blue underneath and every screen contradicts it with inline
  green. Redefining the theme's own CSS variables recolours all of it at once,
  which is the fix the dozens of `style="color:#7ab800"` were standing in for.
- `1rem = 10px` here (the theme sets 62.5%), so a scale written in rem lands at
  half size — exactly how the login shipped with 10px inputs.
- Bootstrap 3's `.container:before { display: table }` collapses any absolute
  pseudo-element that inherits it, which is why the login background painted
  at zero size.
- Tailwind is not installed; if it goes in it needs `preflight: false` and a
  prefix, or it takes the theme apart.

Plus the token set, the per-component rules for PrimeNG, the type scale in px,
and a prompt that can be handed to whoever implements it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The scale shipped at half its intended size: the theme sets
`html { font-size: 62.5% }`, so the 2rem heading rendered at 20px and the
inputs at 10px. Measured with getComputedStyle, not guessed from a screenshot.

Now 32 / 15 / 14 / 16 / 16 px, written in px so nobody inherits the
assumption. The 16px on the fields is a floor, not a taste: below it iOS
Safari zooms the page when the input takes focus.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…re made

Menta, a brand-coloured bar, the grouped sidebar, bordered fields and a zebra
table. The tokens move to that palette.

One measurement changed a decision: the accent #0f8a63 carries white at 4,34,
under the 4,5 minimum, so it cannot be the bar's background. The bar uses
#0a6449 — the same green, two steps deeper, at 7,16 — and the light accent
stays for active states on white, where it works.

Also written down: how a redesign proposal is put together here, since the
format is worth repeating — measure before drawing, one local HTML page, five
distinct ideas rather than five shades of one, real CLARISA content, each
option stating its cost and not only its virtue, contrast shown on the card.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The plan was to redefine `--primary-color` in `styles.scss` and let the library
follow. It does not: `lara-light-blue` declares that variable but never reads it
— `var(--primary-color)` appears 0 times in both `theme.css` and
`primeng.min.css`, while the blue is written as a literal hex 335 times. The
override would have left every button, table and focus ring blue and looked done.

So the accent is remapped where it lives. The theme's blue is five tones with one
role each; `scripts/generate-primeng-theme.js` maps them onto the Menta ramp and
writes `src/themes/clarisa-light-mint/theme.css`, which `angular.json` loads in
place of the packaged one. The compiled bundle carries 0 of the blue ramp and 340
of the mint.

Two of the five tones come out better than what they replace: the primary surface
now gives 5.70 with white on it where the blue gave 3.68, and the highlight text
gives 7.80 over its own surface where the blue gave 6.16.

Upgrading PrimeNG would hand the blue back in silence, because nothing else in
the build defines the accent. `theme.spec.ts` regenerates the file and compares,
so the upgrade turns the suite red instead; `npm run theme:build` is the fix.

The `--cl-*` tokens land in `styles.scss` as the single source of colour, with
`--cl-brand-deeper` added for the highlight text the ramp needs.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The screen was built before the palette was chosen, so it shipped in the old
CGIAR lime `#7ab800` and declared its own hexes — which is exactly what the token
block exists to prevent. With the library now mint, the card was the one surface
still arguing with it.

The lime forced dark ink on the button: white on it gives 2.4 and fails.
`--cl-brand-strong` carries white at 5.70, so the button reads like every other
primary in the application instead of being a local exception. Hover goes one
step deeper rather than lighter. The focus border and ring come from the tokens
too, and the disabled pair moves from 2.29 to 2.89.

Measured in the browser, not from the screenshot: button `#0b7554` on white,
52px tall, 16px type, ring `rgb(189,227,212)`.

The photograph treatment keeps its own literals — it is image grading, not brand
colour. The public navbar is still lime; that is the next phase.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…o-versioning

feat(glossary): one definition per portfolio, managed from the admin panel
…d rib

The bar was the last surface still arguing with the palette, and the reason was
the logo. Sampling the pixels of both files in the repository, the CGIAR has two
greens: the loose mark is forest `#387828` and the box is lime `#78b800`. Over
the mint bar the mark falls to 1.33 and the box to 2.95 — and the version
published today, a white mark on the lime box, is 2.43 on its own, whichever
background it sits on.

So the boxed logo stops hanging below the bar. The transparent mark goes over
white at 5.40, next to a CLARISA wordmark in ink. Links move from the lime
`#7ab800` — 2.42 over white, and the colour every link in the header used — to
ink at 8.17, in sentence case, because the uppercase came with the old theme and
cost width without adding hierarchy. The current section is marked with the soft
pill at 7.80, driven by `routerLinkActive` on the `<li>` so a parent lights up
when the active route lives inside its submenu.

A Sign in button is new: one solid primary at the right edge, 5.70. It sits
outside `.navbar-collapse` on purpose — at >=768px Bootstrap forces
`display: block !important` on that element, so anything inside it cannot take
part in a flex row, and the button dropped to a second line on the first render.

The Bootstrap skeleton is otherwise untouched, because the collapse and every
dropdown are wired by the global jQuery bundle. All of it is done from the
component's own SCSS with `:host`, without editing the shared global sheet and
without a single `!important`.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
yecksin and others added 9 commits September 15, 2026 14:53
…pository

Section 5 listed the conditions Tailwind would need but not the evidence, so the
question kept coming back. Measured here: 468 of the 609 blocks in
`style-landing.css` are selectors of two or more levels, plus 461 in the
Bootstrap sheet. A utility is a single class at 0,1,0 and loses to every one of
them, so the only way to make it win would be `important: true`.

`.container`, `.hidden` and `.table` collide by name with the Bootstrap 3 sheet
loaded globally, and the builder is Angular 14, which takes Tailwind v3 but not
v4. The public navbar is the worked example: the effort there went into beating
multi-level global rules and a Bootstrap `display: block !important`, and
Tailwind helps with neither.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The only link to the login lived inside the panel — that is, once you were
already in. From outside, the login was reached by typing the URL or by being
thrown there by the guard after clicking "Institution Request", which is the
roundabout way Héctor reported (ticket 161964).

The bar now carries a "Sign in" button on the right.

- The green is `#427730`, the one the bar already uses on the top border of its
  dropdowns: no new colour enters the palette. With white on top it measures
  5.37 : 1, where the brand lime would give 2.42 and fail.
- It sits as a direct child of the bar and never inside `.navbar-collapse`:
  from 768px Bootstrap forces `display: block !important` there and the button
  would drop to a second line.
- It comes after `.navbar-header`, so on a phone — where it stops floating — it
  lands under the logo instead of above it.

Two tests pin both the destination and the placement, because the placement is
the part a future edit would break without anyone noticing.

The template is left otherwise untouched: running prettier over it reformatted
101 lines for a twelve-line addition, which buries the change for the reviewer
and widens the collision with the visual revamp already rewriting this file.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The photograph goes. It was 7.16 MB at 4608x3456 — the first thing anyone
downloaded to reach a two-field form — and it forced the card to defend itself
with a radial wash and a 170px inner shadow. The brand pane replaces it: the
mark as texture and one line about what CLARISA is, with the form given the calm
half. The image no longer loads on this route at all.

The mark is knocked out to white because in its own forest green it is 1.33 over
this background and would read as a stain, and it is cropped to the wings: at
full height the asset's own CGIAR wordmark came through and read as a second,
giant logo competing with the one in the bar.

Two defects found by looking at the render rather than trusting the markup.
Both error messages showed on a pristine form: the template hides them with
`[hidden]`, but `[hidden]` is only `display: none` at user-agent strength and
the `.field__error { display: block }` rule was beating it. And the ghost was
sized by width alone, which is what let the wordmark through.

Visible text is new — the pane's heading and its line — so it needs Yeck's word
before this leaves the branch.

Measured in the browser: pane `#0a6449` with the heading at 7.16, fields 16px
and 52px tall with a full 1px border at radius 8, no horizontal scroll at 390px.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The four admin modules hung from the public «Services» dropdown, beside the API
documentation. Two things followed from that. Signing in dropped you on
Institution Requests with no way to reach the rest, because the only sidebar in
the panel was declared inside that one page. And a visitor with no account found
the modules in a public menu and was bounced to the login screen — the roundabout
route Héctor reported.

The sidebar moves up to the `manage` layout, so it is present on every admin
page, and the four entries come out of the dropdown. It is grouped rather than
flat («S3»): six entries in one column read as a pile, while Manage, Access and
System answer different questions. The current module is marked with the same
soft pill the public bar uses, at 7.80.

Its first 75px were hidden under the panel's fixed header, which is exactly the
brand block; the offset is now declared once and reused by the sticky top.

Zebra striping («T2») is declared once in `styles.scss` rather than passed table
by table, and the highlighted and hovered rows are given precedence so the
alternation does not eat the highlight on even rows. Verified on the institution
lifecycle table, which is the first one in this branch with real rows in it.

The table header and export button greens move to the tokens; they were literal
hexes outside the token block, which DESIGN.md counts as a review error.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…ions

A versioned concept is drawn as one card, but the card could only ever show
one definition: the one of the filtered portfolio, or the most recent. There
was no model for "the reader is looking at the 2022-2024 wording of this same
concept", so the view could not offer the choice.

The card becomes a class holding every version of the concept, ordered newest
portfolio first, plus the index of the one on screen. Definition, source,
source URL and reference date are getters over that index, so moving it is
enough to switch what the card shows — no regrouping, no rebuild.

Adds `shownVersion`, `portfolioOf`, `isCurrentVersion` (resolved by the
portfolio start year, not by a hardcoded code) and `showVersion`, and makes the
search scan every version: a word that only appears in the 2022-2024 wording
now finds the concept.

The template is untouched and behaviour is unchanged — this is the model the
portfolio tabs need, so the design work can build on it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Héctor's words: «no se sabe qué portafolio es el que está viendo la definición…
que estos tags se vean como tabs en esa esquina, que se pueda ver el valor de la
definición anterior pero también que se vea cuál es el por defecto, que diga
current o algo así, y mejorar el diseño de una vez».

The tags become a segmented rail in the card corner. With more than one
definition each segment is a version and switching one changes the text in place.
The current one carries the word Current, and which portfolio is current is
resolved by start year, not by a fixed code, so it moves on its own when
2031-2036 exists.

It is a rail of our own rather than a library tab strip: a bare `p-tabView`
brings its own box, underline and type scale, and inside a card it takes over the
header.

Two things came from looking at it rather than from the requirement.

A concept with a single definition first kept the old coloured tag, so the same
fact was drawn two different ways depending on how many versions a term had —
the inconsistency Yeck called out. Now every card gets the same rail; with one
version the segments are the portfolios that definition covers, which can still
be two, and they do not respond because there is nothing to switch to.

And the colour no longer encodes the portfolio. It used to cycle violet, grey,
green, blue and orange by `id % 5` with no legend anywhere, so it told the reader
nothing they did not already know. The only thing colour distinguishes now is the
thing that was actually asked about: a filled dot is the current portfolio, a
hollow one a previous period.

At 390px the long labels overflowed the rail and left the second segment sliced
down the middle, which reads as a paint bug rather than as «there is more». The
word Portfolio drops on narrow screens — the period alone identifies it and the
word is still in the filter above. Rail content now measures exactly its visible
width, with no page scroll.

Verified against the running page: on High-level output (HLO) the definition goes
from «HLOs are a means for P/As to plan…» to «High-level outputs are aggregated
clusters…» when the second segment is pressed.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
… redundant Current

Two corrections from Yeck.

The portfolio colours return to the dot. Dropping them made every segment look
alike, and the palette was the part that read well; what was wrong was asking one
channel to carry two meanings. Now the colour identifies the portfolio, exactly
as the old tags did, and the fill says which one governs: solid is current,
outlined is a previous period.

And the Current badge comes off the single-portfolio cards. It was repeating on
56 of 70 with nothing to contrast against — Héctor's question was which of two
definitions governs, so the word belongs where there are two.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Yeck asked for one place to look at and work in: the glossary tabs were born
from staging and carried none of the revamp, so opening that page showed the old
lime while the rest of the branch was already mint.

The glossary branch stays pushed and intact, so Héctor's request keeps its own
short path to production instead of waiting for the whole revamp. From here,
glossary changes are made there and merged forward into this branch, never the
other way round, so that path does not go stale.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…ary admin

Yeck's round of corrections, done in parallel and gated once.

The panel header was still the old lime one, so the admin sat under a bar that
contradicted every other screen. It is now the same white bar with the brand rib,
ink links in sentence case and the soft pill, with Logout as the one solid
primary at the right edge. Its brand block is deliberately absent: the sidebar
carries the mark about 70px below at the same x, and stacked they read as the
logo printed twice.

The admin sidebar becomes `position: fixed` with the content offset to match, so
the table no longer slides underneath it, and gains hairlines between groups and
a 3px indicator on the active entry.

The glossary admin loses its second column: «Terms / Bulk upload» was an aside
next to a sidebar, which is two columns of navigation in a row, and is now a
segmented control above the content. Definitions are clamped to three lines with
the full text in the title — single rows were running fifteen lines — and the
filters come down to 40px.

In the public glossary the Current badge goes. The filled dot already says which
portfolio governs, and the word repeated that next to the colour encoding it.

And the mark in the login pane stops looking broken: the crop that hides the
asset's own wordmark left a hard horizontal edge across the logo, which reads as
a failed image rather than as texture, so it fades out instead.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
yecksin and others added 4 commits September 15, 2026 16:22
The gate on #203 failed with a C rating: five `font-family` declarations for the
icon font with no generic fallback, a duplicated `background` in `.p-steps`, and
the login loader `<img>` with no `alt`.

The first two live in the vendor lara-light-blue theme, so they are patched in the
generator rather than by hand; the committed theme stays pinned to its output by
theme.spec.ts. Nothing renders differently: the icon font is always loaded, and
the removed `background` was already overridden by the one that wins.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

# Conflicts:
#	clarisa-front/src/app/landing-page/components/navigation-bar/navigation-bar.component.html
#	clarisa-front/src/app/landing-page/components/navigation-bar/navigation-bar.component.scss
The merge replaced the bar the ticket-161964 button was added to, so its two
tests went red: the button is now `.cl-signin` inside `.cl-bar` rather than
`.nav-signin` inside `.navbar`.

Deleting them would have dropped the only thing holding Héctor's request in
place, so the element keeps the `nav-signin` class and the structural assertion
moves to the new wrapper. What it guarantees is unchanged: a visible link
labelled Sign in pointing at the login, living outside the collapse that
Bootstrap forces to `display: block !important` above 768px.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…vamp

revamp: visual system, new public bar, split login, admin sidebar and glossary rail
@sonarqubecloud

Copy link
Copy Markdown

@yecksin yecksin changed the title release: glossary versioning per portfolio, and expired sessions that log out release: glossary versioning per portfolio, expired sessions that log out, and the visual revamp Sep 15, 2026

@SantiagoSC1999 SantiagoSC1999 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Approve

@SantiagoSC1999
SantiagoSC1999 merged commit 5fe7401 into main Sep 15, 2026
3 checks passed
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