Skip to content

Development: Redesign the rating card - #2574

Merged
az108 merged 43 commits into
mainfrom
feat/rating-redesign
Jul 26, 2026
Merged

Development: Redesign the rating card#2574
az108 merged 43 commits into
mainfrom
feat/rating-redesign

Conversation

@SultanTheHL

@SultanTheHL SultanTheHL commented May 25, 2026

Copy link
Copy Markdown
Collaborator

Checklist

General

Server

  • Important: I implemented the changes with a very good performance and prevented too many (unnecessary) and too complex database calls.
  • I strictly followed the principle of data economy for all database calls.
  • I strictly followed the server coding and design guidelines.
  • I documented the Java code using JavaDoc style.

Client

  • Important: I implemented the changes with a very good performance, prevented too many (unnecessary) REST calls and made sure the UI is responsive, even with large data (e.g. using paging).
  • I strictly followed the principle of data economy for all client-server REST calls.
  • I strictly followed the client coding and design guidelines.
  • I documented the TypeScript code using JSDoc style.
  • I added multiple screenshots/screencasts of my UI changes.

Motivation and Context

Closes #1519

Ratings were shown as a row of coloured pills, one per step, with the label written inside the pill. That put the meaning on the colour and the text on top of it, which left several steps unreadable, and it gave no sense of the scale's shape: nothing said whether a rating sat near the top or the bottom without reading the word.

Comments also showed no rating, so a reviewer's reasoning and their score were never visible together.

Description

Rating input

  • The pills are replaced by a five star scale. The stars fill up to the chosen value and the word for that value sits underneath, so the position on the scale is visible at a glance and the exact meaning is still spelled out.
  • Hovering a star previews it: the row fills to that step in that step's colour and the word changes with it. Both fall back to the stored rating when the pointer leaves, and nothing is written until a click. Keyboard focus previews the same way.
  • Clicking the star that is already selected clears the rating, so "not rated yet" stays reachable.
  • The row behaves as a radio group: arrow keys move between steps, Home and End jump to the ends, and a roving tabindex keeps the whole row to a single tab stop instead of one per star.
  • The stored value is unchanged. The scale is still -2 to +2 and is only mapped to one to five for display, so none of the five places that use the component needed touching.

Average display

  • The average star display now uses the same colour scale as the input, through one shared function, so a 4.0 average is the same green as a four star rating. The two previously had separate colour logic and different empty-star colours. The application card renders this component, so its average changes appearance without the card itself being touched.
  • The component set its colour with an inline style, which is now a class.
  • star-half-stroke was rendered for fractional averages but had never been added to the registered icon set, so any average landing on a half star rendered nothing in that position. The icon is registered now.

Colours

  • One token per step, red through gold to green, applied to the filled stars. Because the colour now paints a shape rather than sitting behind text, it needs 3:1 rather than 4.5:1, which is what makes the red to green scale workable at all.
  • The reds and greens clear 3:1 against both a light and a dark background. The gold does not, at 1.65:1 on white, and is kept deliberately: the number of filled stars and the word beside them carry the rating, the colour only reinforces it, and every gold that clears the bar stops reading as gold. The measured pair is recorded next to each token.

Comments

  • Each comment shows the rating its author gave, beside the edit and delete actions, so reasoning and score sit together.
  • The review page loads the rating overview once and hands it to both the rating and the comment section. Each previously fetched it for itself, which issued two identical requests per review and let the two disagree: changing your rating refreshed one and left the other showing the old score.
  • The button that posts a new comment now reads "Post" rather than "Send".
  • Comments and ratings are paired by the id of the user behind them. RatingDTO and InternalCommentDTO each gained one (fromUserId and authorUserId, named after the flat variants that already carry it), because the pairing previously compared display names and two reviewers sharing a name would show each other's score. It also makes the ratings distinct on the server, where RatingOverviewDTO holds a Set that used to collapse same-name reviewers who gave the same score.

Interview page

  • The interview assessment rendered the evaluation page's generic rating label below the stars, which repeated the instruction already above them and spoke about applications rather than interviews. It is removed, along with the fixed 40px row it sat in, which was too short for the star scale and its word label.

Also in this PR

  • The dark scheme's text.onSuccess, onDanger, onWarn and onInfo change from black to white. These are the inverseColor for every PrimeNG severity component, not only the ratings, so severity buttons, tags and badges are affected in dark mode. Worth a look during review; a warn severity tag is now white on amber.

Steps for Testing

Prerequisites:

  1. Log in as a Professor or Employee.
  2. Open the review page for an application.

Steps:

  1. Under "Your Rating", hover across the stars. The row should fill to the star under the pointer in that step's colour, and the word underneath should change with it.
  2. Move the pointer away without clicking. The stars and the word should return to whatever was stored, or to empty if nothing was rated.
  3. Click a star. The rating should stay after the pointer leaves.
  4. Click the same star again. The rating should clear.
  5. Tab to the row. It should take one tab stop, not five. Use the arrow keys to move between steps, and Home and End to jump to either end.
  6. Check each of the five steps in turn: one star red, three gold, five green, with Poor through Excellent underneath.
  7. Switch to dark mode and repeat step 6. The stars and the word should stay readable at every step.
  8. Post a comment. The rating you gave should appear on it, next to the edit and delete buttons.
  9. Have a second reviewer rate and comment on the same application. Their comment should carry their rating, not yours.
  10. Give two reviewers the same first and last name, have both rate and comment, and confirm each comment shows its own author's rating.
  11. Change your rating and watch the comment section. Your comment's rating should follow without a reload. With the network tab open, loading the review should issue one request for the ratings, not two.
  12. Go back to the application list. The card's average should use the same colours as the input.
  13. Arrange two ratings that average to a half step, for example 3 and 4 giving 3.5. The card should show a half star rather than a gap.
  14. Open an application nobody has rated. The card should show "No ratings yet".

Review Progress

Code Review

  • Code Review 1

Manual Tests

  • Hover preview fills and clears without writing a rating
  • Clicking the selected star clears it
  • Arrow keys, Home and End move through the scale, and the row is one tab stop
  • All five steps readable in light and dark mode
  • Comments show their own author's rating, and follow a rating change without a reload
  • Reviewers who share a display name keep their own ratings
  • The interview page shows only its own rating instruction, with room for the word label
  • Card average matches the input's colours
  • Half star renders for a fractional average
  • PrimeNG severity buttons, tags and badges still look right in dark mode

Screenshots

Test Coverage

Client

Class/File Line Coverage Lines Expects Ratio
font-awesome-icons.ts 100.00% 280 ? ?
application-detail.component.ts 0.00% 544 55 10.1
rating.component.ts 98.21% 116 29 25.0
star-rating.component.ts 100.00% 47 19 40.4
comment-section.ts 98.36% 98 33 33.7
comment.ts 6.81% 69 11 15.9
rating-section.ts 100.00% 77 24 31.2
rating.util.ts 50.00% 27 4 14.8

Server

Class/File Line Coverage Lines
InternalCommentDTO.java 100.00% 20
RatingDTO.java 100.00% 10

Last updated: 2026-07-26 19:49:37 UTC

@SultanTheHL SultanTheHL self-assigned this May 25, 2026
@SultanTheHL
SultanTheHL requested a review from az108 as a code owner May 25, 2026 07:17
@SultanTheHL SultanTheHL added server Pull requests that update Java code. (Added Automatically!) client Pull requests that update TypeScript code. (Added Automatically!) ui/ux improvement labels May 25, 2026
@codacy-production

codacy-production Bot commented May 25, 2026

Copy link
Copy Markdown

Up to standards ✅

🟢 Issues 0 issues

Results:
0 new issues

View in Codacy

🟢 Metrics 12 complexity

Metric Results
Complexity 12

View in Codacy

NEW Get contextual insights on your PRs based on Codacy's metrics, along with PR and Jira context, without leaving GitHub. Enable AI reviewer
TIP This summary will be updated as you push new changes.

@SultanTheHL SultanTheHL changed the title Feat/rating redesign Development: Redesign the rating card May 25, 2026
# Conflicts:
#	src/main/webapp/app/shared/components/molecules/rating-section/rating-section.html
@github-actions github-actions Bot removed the server Pull requests that update Java code. (Added Automatically!) label May 25, 2026
@github-actions

Copy link
Copy Markdown
Contributor

🤖 No OpenAPI or client changes needed.

@github-actions

Copy link
Copy Markdown
Contributor

📊 Client Test Coverage Too Low

🔍 View coverage locally:

pnpm run test:ci
open build/test-results/vitest/coverage/index.html

🌐 View coverage from GitHub:
Download the "coverage-report-client" artifact from this workflow run.

@github-actions github-actions Bot added the tests label May 25, 2026
@github-actions

Copy link
Copy Markdown
Contributor

📊 Client Test Coverage Too Low

🔍 View coverage locally:

pnpm run test:ci
open build/test-results/vitest/coverage/index.html

🌐 View coverage from GitHub:
Download the "coverage-report-client" artifact from this workflow run.

Comment thread src/main/webapp/app/shared/components/atoms/rating/rating.component.html Outdated
Comment thread src/main/webapp/app/shared/components/atoms/rating/rating.component.html Outdated

@az108 az108 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

While testing i noticed that we should maybe bundle the bewertungs section, having it in two lines like this can be misleading and looks like we have given these ratings, also i would maybe put the blue background away and give it a hover effect in the colour which the pill will have after its selected. This could reduce the confusion. And did you forget adding a clickable hover effect 👀

Image

@github-actions

Copy link
Copy Markdown
Contributor

📊 Client Test Coverage Too Low

🔍 View coverage locally:

pnpm run test:ci
open build/test-results/vitest/coverage/index.html

🌐 View coverage from GitHub:
Download the "coverage-report-client" artifact from this workflow run.

@github-actions

Copy link
Copy Markdown
Contributor

📊 Client Test Coverage Too Low

🔍 View coverage locally:

pnpm run test:ci
open build/test-results/vitest/coverage/index.html

🌐 View coverage from GitHub:
Download the "coverage-report-client" artifact from this workflow run.

@github-actions

Copy link
Copy Markdown
Contributor

There hasn't been any activity on this pull request recently. Therefore, this pull request has been automatically marked as stale and will be closed if no further activity occurs within seven days. Thank you for your contributions.

@github-actions

Copy link
Copy Markdown
Contributor

There hasn't been any activity on this pull request recently. Therefore, this pull request has been automatically marked as stale and will be closed if no further activity occurs within seven days. Thank you for your contributions.

@github-actions

Copy link
Copy Markdown
Contributor

There hasn't been any activity on this pull request recently. Therefore, this pull request has been automatically marked as stale and will be closed if no further activity occurs within seven days. Thank you for your contributions.

# Conflicts:
#	src/main/webapp/i18n/de/button.json
#	src/main/webapp/i18n/en/button.json
Cathy0123456789 and others added 11 commits July 24, 2026 22:22
The excellent and poor chips became unreadable once selected.

A selected chip is filled with its rating colour and labelled with the matching
text-on-* token. Those tokens flip with the colour scheme, near-black in light and
white in dark, while the fills stay the same shades in both. So each fill ends up
paired with a foreground that suits only one of the two schemes.

Measured against WCAG AA, in light mode very_bad sat at 2.80:1, very_good at
3.47:1 and bad at 4.39:1; in dark mode neutral sat at 1.65:1 and good at 3.70:1.
The two reported are the worst of the five, but three others were failing too, and
no single foreground fixes all of them: white is unreadable on the yellow.

The foreground is now chosen per fill from the two fixed base tokens, which do not
move with the scheme, since the fills do not either. White on the dark red and
dark green, black on the yellow and mid green. The lowest pairing is now 4.72:1
and all five clear 4.5:1 in both schemes.

Verified the generated utilities resolve in the compiled stylesheet, and updated
the class expectations in the rating spec.

Verified: 2010 client tests, typecheck, eslint with no errors, a11y lint, the
production build and prettier.

Co-Authored-By: Claude <noreply@anthropic.com>
Follow-up to the contrast fix: the label is black on every chip now, rather than
switching between black and white depending on which fill it sits on.

That needed lighter fills. The default/hover/active triad is too dark at the ends
for a black label, and too dark for a white one on the yellow, which is why no
single label colour worked with it. The chips now use their own five-step scale,
light enough that a black label clears 4.5:1 on all of them and in both colour
schemes: 5.68 on very bad, 9.19 on bad, 13.86 on neutral, 11.52 on good and 5.68
on very good. The two ends match, so the scale still reads as symmetric.

The steps are declared as tokens next to the existing purpose-built ones, with the
measured ratio recorded per step so the next person changing a shade can see what
the number has to stay above.

Worth noting for the review: the dark-scheme text.on* values this PR flips from
black to white are also the inverseColor for every PrimeNG severity component, not
just these chips. The chips no longer depend on them, but a warn-severity button or
tag in dark mode is now white on amber, which is the 1.65:1 case. That is untouched
here and wants checking separately.

Verified the tokens and utilities resolve in the compiled stylesheet.

Verified: 2010 client tests, typecheck, eslint with no errors, a11y lint, the
production build and prettier.

Co-Authored-By: Claude <noreply@anthropic.com>
Moves the poor chip from danger.500 to danger.400, taking its label contrast from
5.68:1 to 7.06:1 while staying clearly apart from fair.

Excellent is left alone for now. The palette has no step between success.500 and
success.600, and moving it to 500 puts it within a colour difference of about 10
of good, which is close enough that the two chips read as the same green. Trading
the good/excellent distinction for contrast on a chip that already clears the
minimum did not seem worth doing without asking.

Co-Authored-By: Claude <noreply@anthropic.com>
Excellent moves from success.600 to success.500 and good from success.400 to
success.300, so both greens lighten together. Moving excellent on its own would
have left it about a colour difference of 10 from good, close enough that the two
chips read as one green.

The scale now sits between 7.06:1 and 13.86:1 against its black label, up from a
worst case of 5.68:1, and every neighbouring pair stays at least 18 apart, so the
five steps remain tellable apart. The recorded ratio next to each token has been
updated to match.

Verified the tokens resolve in the compiled stylesheet.

Verified: 2010 client tests, typecheck, eslint with no errors, a11y lint, the
production build and prettier.

Co-Authored-By: Claude <noreply@anthropic.com>
Five stars that fill up to the chosen value, with the word for that value
underneath. The stored scale is untouched: -2 to +2 is mapped to one to five
stars for display only, so none of the seven places using this component change.

The pills made colour carry the meaning, which is why the label kept colliding
with the fill and took three attempts to get readable. Stars carry it by count
instead, so filled against empty is legible whatever the scheme, and the word
underneath says which step it is rather than leaving it to be inferred from a
shade. The per-step colour tokens are gone with them.

Interaction follows the radio group pattern: arrow keys move between steps, Home
and End jump to the ends, and a roving tabindex keeps the row to a single tab
stop rather than one per star. Picking the current star again clears the rating,
so "not rated yet" stays reachable. The keydown handler sits on the stars rather
than the group, since the group is not focusable and the a11y lint rightly
objects to handlers on elements that cannot receive focus.

Stars use the primary colour, which holds 5.13:1 against a light background and
3.45:1 against a dark one, clearing the 3:1 that non-text contrast asks for. Gold
was the first instinct but only manages 1.51:1 on white.

Read-only rows keep the same stars with an aria-label naming the rating, and the
label beside them.

Verified: 2014 client tests, typecheck, eslint with no errors, a11y lint, the
production build and prettier.

Co-Authored-By: Claude <noreply@anthropic.com>
The stars take the red to green scale again, applied to the whole row rather than
to one chip: one star is red, three amber, five green. Because the colour now
paints a shape instead of sitting behind a label, it only has to clear the 3:1
non-text minimum instead of 4.5:1, which is what makes the scale usable again.

Each step uses the shade that clears 3:1 against both a light and a dark
background. The middle step is a deep amber rather than a bright gold, since gold
only reaches 2.4:1 on white. The measured pair is recorded next to each token.

Hovering a star previews it: the row fills to that step in that step's colour and
the word underneath fills in, and both fall back to the stored rating when the
pointer leaves. The stored value is untouched until a click, and aria-checked
keeps tracking the real rating rather than the preview. Keyboard focus previews
the same way, so the two do not disagree.

Verified the tokens and utilities resolve in the compiled stylesheet.

Verified: 2024 client tests, typecheck, eslint with no errors, a11y lint, the
production build and prettier.

Co-Authored-By: Claude <noreply@anthropic.com>
…verage

Two places show a star rating: the input on the application detail page, which
moves in whole steps, and the average on the application cards, which can be
fractional and shows half stars. They had separate colour logic, so they could
drift, and the card also set its colour through an inline style.

The step colours now live in one function that both call, alongside the existing
Likert conversion. The card passes its average and the input passes its star
count, and rounding to the nearest step keeps them agreeing: a 4.0 average is the
same green as a four star rating. The empty stars share a colour too, so the card
no longer uses a paler grey than the input. The inline style is gone with it.

The middle step is a bright gold now rather than the deep amber. It reaches
1.65:1 on a light background, short of the 3:1 that non-text contrast asks for.
That is a deliberate trade: the number of filled stars and the word beside them
carry the rating, the colour only reinforces it, and every gold that clears the
bar stops reading as gold. The reds and greens still clear it on both backgrounds.

Verified the tokens and utilities resolve in the compiled stylesheet, and checked
both views map the same values to the same colours.

Verified: 2037 client tests, typecheck, eslint with no errors, a11y lint, the
production build and prettier.

Co-Authored-By: Claude <noreply@anthropic.com>
Adds the spec the component never had, covering the filled and half star counts
across whole and fractional values, the boundary just under the half point, the
unrated state, maxStars, the shared step colours, the empty star colour, the
formatted value, showValue and the three sizes.

Writing it turned up a real defect. The template renders star-half-stroke for a
fractional rating, but that icon was never added to the registered set, only
faStar was. Any average landing on a half star, which is every average from an
even split of reviewers, hit "Could not find icon with iconName=star-half-stroke"
and rendered nothing in its place. The icon is registered now.

Verified: 2060 client tests, typecheck, eslint with no errors, a11y lint, the
production build and prettier.

Co-Authored-By: Claude <noreply@anthropic.com>
The rating section and the comment section each fetched the rating
overview for the same application, so opening a review issued two
identical requests. It also meant the two could disagree: changing your
rating refreshed the rating section but left your comment showing the
old score until a reload.

The rating section already owned the rating state and refetched it after
every write, so it now emits what it loaded and the review page passes
that down to the comment section. Removing the second fetch left the
loadCommentRatings error string unused, so it is gone from both locales.

On the interview page the rating block also rendered the evaluation
page's generic label below the stars, which both repeated the
instruction above them and spoke about applications rather than
interviews. The fixed 40px height it sat in was too short for the star
scale and its word label, so both are removed and the component sizes
itself.

Co-Authored-By: Claude <noreply@anthropic.com>
The comment section paired each comment with a rating by comparing
display names, so two reviewers called "Max Mustermann" would show each
other's score. Names are not unique and never were, and the client had
nothing else to match on: neither the comment nor the rating carried the
id of the user behind it.

Both DTOs now expose one, named after the flat variants that already do
this: RatingDTO gains fromUserId and InternalCommentDTO gains
authorUserId. The client keys the lookup on those instead.

This also makes the ratings distinct on the server. RatingOverviewDTO
holds a Set, so before this two reviewers sharing a name who happened to
give the same score collapsed into a single entry.

Co-Authored-By: Claude <noreply@anthropic.com>
@github-actions github-actions Bot added server Pull requests that update Java code. (Added Automatically!) evaluation Code changes in evaluation module. labels Jul 26, 2026
@az108
az108 merged commit 090140d into main Jul 26, 2026
15 of 16 checks passed
@az108
az108 deleted the feat/rating-redesign branch July 26, 2026 19:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

client Pull requests that update TypeScript code. (Added Automatically!) evaluation Code changes in evaluation module. ready for review server Pull requests that update Java code. (Added Automatically!) tests ui/ux improvement

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Improve visibility and interpretation of reviewer recommendations in application review view

3 participants