Skip to content

feat: choose an artist's portrait and banner from the artist page - #310

Merged
InstaZDLL merged 2 commits into
mainfrom
feat/artist-image-picker
Oct 23, 2026
Merged

InstaZDLL merged 2 commits into
mainfrom
feat/artist-image-picker

Conversation

@InstaZDLL

@InstaZDLL InstaZDLL commented Oct 23, 2026 •

Copy link
Copy Markdown
Owner

Step 3 of RFC-013: the web client draws the chosen images and lets owners and managers choose them. The server side is #309.

The artist header

  • A backdrop behind the header:
    • the chosen banner, cover-fitted at center 30%, the fixed framing the desktop uses (no cropping, as the RFC says);
    • otherwise the portrait, blurred (the album page's ambient treatment), so a header without a banner still carries the artist.
  • A gradient over it keeps the title readable over any picture, and the header's text turns light whenever there is a backdrop, in the light themes too.
  • A chosen portrait says "Portrait chosen by hand" instead of crediting Deezer. The Deezer credit still shows when the fetched portrait is the one displayed.

Choosing (owners and managers only)

  • Change portrait and Change banner each open a file picker for JPEG, PNG or WebP. The file is sent as its own bytes (PUT /artists/{id}/image/{kind}). The page then shows the server's answer immediately and re-reads the artist and the artist list.
  • Automatic portrait and No banner appear once a choice exists, and go back to the automatic image (DELETE).
  • A refusal is announced in a role="alert": "larger than 10 MB" for 413, "choose a JPEG, PNG or WebP image" for 422, a generic message otherwise. Success is announced in a role="status".
  • On a wide screen the controls sit in the header's top corner, out of the flow, so they never narrow the title. On a phone they follow the header's content.
  • Listeners see the banner and the portrait, and no control. The server refuses them regardless.

Client API

  • ArtistDetail gains library_id, banner_hash and image_choice.
  • setArtistImage and removeArtistImage are added.

Tests

  • Playwright, desktop and mobile, with axe:
    • "changes an artist's banner and portrait from the artist page": the blurred ambient with no banner; a banner chosen, its bytes sent and the banner drawn; a portrait chosen and marked as such; a refused file announced; both reverted with the two DELETEs.
    • "shows a listener the artist's banner with nothing to change".
  • Each test fails with its code removed, checked on a build that compiles: controls drawn for everyone, and the banner not drawn.
  • Dark-theme screenshots were checked on desktop and mobile.

Validation

  • lint (the same 7 warnings in refresh.css), tsc, 190 unit tests, build
  • Playwright: 192 passed, 12 skipped

Summary by CodeRabbit

  • Nouvelles fonctionnalités
    • Les propriétaires et gestionnaires autorisés peuvent remplacer le portrait ou la bannière d’un artiste par une image JPEG, PNG ou WebP, ou rétablir l’image automatique.
    • La page artiste affiche la bannière choisie ; à défaut, le portrait sert d’arrière-plan. Un indicateur signale les portraits sélectionnés manuellement.
    • Des messages précisent si l’image dépasse 10 Mo, si son format n’est pas accepté ou si l’opération échoue.

RFC-013 step 3. The artist header draws the chosen banner behind it, framed at a fixed point as the desktop frames it, or else the portrait blurred, under a gradient that keeps the title legible. Owners and managers get Change portrait and Change banner, which send the file as its own bytes, and a way back to the automatic image once one was chosen; a chosen portrait says so instead of crediting Deezer. Listeners see the images and no control.

Signed-off-by: InstaZDLL <github.105mh@8shield.net>
Signed-off-by: InstaZDLL <github.105mh@8shield.net>
@github-actions github-actions Bot added scope: web Embedded web player (React) scope: components Web UI components scope: docs Docs, README, assets type: feat New feature size: l 200-500 lines labels Oct 23, 2026
@coderabbitai

coderabbitai Bot commented Oct 23, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
📥 Commits

Reviewing files that changed from the base of the PR and between a1e017f and 2d4c9e0.

📒 Files selected for processing: 9
  • docs/rfcs/RFC-013-chosen-artist-imagery.md
  • webapp/e2e/studio-nocturne.spec.ts
  • webapp/src/api/catalog.ts
  • webapp/src/api/index.ts
  • webapp/src/api/queries.test.ts
  • webapp/src/components/artist-image-controls.tsx
  • webapp/src/pages/artist-page.tsx
  • webapp/src/state/i18n.tsx
  • webapp/src/styles/styles.css

Included review availability: This review used your included allowance. 0 included reviews remain after this review. Your included PR review attempts over the past 7 days set your current allowance at 2 reviews per hour.

📝 Walkthrough

Le client web peut remplacer ou réinitialiser le portrait et la bannière d’un artiste. La page affiche l’image choisie et réserve les commandes aux rôles autorisés dans la bibliothèque de l’artiste.

Changes: Choix des images d’artiste

Layer / File(s) Summary
Contrat API des images
webapp/src/api/catalog.ts, webapp/src/api/index.ts, webapp/src/api/queries.test.ts
ArtistDetail inclut la bibliothèque et les choix d’image. L’API expose les opérations de remplacement et de suppression, et le module public les réexporte. Le helper de test renseigne library_id.
Commandes de choix et de réinitialisation
webapp/src/components/artist-image-controls.tsx, webapp/src/state/i18n.tsx, webapp/e2e/studio-nocturne.spec.ts
Les commandes acceptent les formats JPEG, PNG et WebP, affichent les résultats et distinguent certaines erreurs HTTP. Les tests couvrent le remplacement, la réinitialisation et le refus d’une écriture.
Affichage et autorisation sur la page artiste
webapp/src/pages/artist-page.tsx, webapp/src/styles/styles.css, webapp/e2e/studio-nocturne.spec.ts, docs/rfcs/RFC-013-chosen-artist-imagery.md
La page affiche la bannière ou, à défaut, le portrait en arrière-plan. Elle affiche les commandes selon les droits dans la bibliothèque. Les styles adaptent l’en-tête aux petits écrans, et un test vérifie l’affichage pour un rôle listener. Le RFC associe cette étape à la PR #310.

Priority: ➖ Normal

Estimated code review effort: 3 (Moderate) | ~20 minutes

Change: Feature

Sequence Diagram(s)

sequenceDiagram
  participant ArtistPage
  participant ArtistImageControls
  participant setArtistImage
  participant API serveur
  ArtistPage->>ArtistImageControls: affiche les commandes si le rôle le permet
  ArtistImageControls->>setArtistImage: transmet l’artiste, le type et le fichier
  setArtistImage->>API serveur: envoie le fichier avec PUT
  API serveur-->>setArtistImage: retourne le détail de l’artiste
  setArtistImage-->>ArtistImageControls: retourne le résultat
Loading

Possibly related PRs

Merge Risk: ⚪ Minimal · up to 2d4c9

Artist image selection, reset, and display are ready to merge after normal checks.

Security architecture risk: 🔵 Low · up to 2d4c9

The new controls reuse server-enforced write permissions and library ownership checks. No introduced authorization bypass or cross-library exposure was established. Remaining uncertainty concerns production configuration and failure recovery rather than a demonstrated security defect.

Retained concerns
No architecture-level concerns identified.

Security review details

Security Blast Radius

  • observed — The intended mutation scope is the requested artist in a library where the caller is an owner or manager. Selected images become shared library imagery. Artwork lookup separately requires the requesting user to belong to a library referencing that artwork, including through an artist-image choice.

Security Findings and Attack Paths

  • observed — The concrete untrusted input is the selected file’s bytes. Bypassing the browser’s file-type or role-visibility restrictions still reaches server write-scope enforcement, image recognition, and artist-library authorization before a choice is committed.

Trust Boundaries and Controls

  • observed — Both mutation handlers authenticate with Access::Write and pass the resolved user ID to the service. Scope checks do not replace library authorization: chooser_library binds that user to the requested artist’s library and requires owner or manager metadata authority.
  • observed — Banner rendering reuses authenticated artwork retrieval rather than fetching a user-supplied remote URL. The browser requests an encoded artwork identifier, creates an object URL from the response, and the server checks library access before resolving the stored image.

Resilience and Maintainability Implications

  • observed — The server writer gate serializes choice mutations and rechecks authority before committing. The client disables its controls during an operation and releases its busy state in finally. These controls do not provide cross-tab idempotency; an already-removed choice still produces a reset error under the existing server contract.
Pre-merge checks: Passed 4 · Failed 1

Failed Failed checks: 1 warning

Check name Status Explanation Resolution
Docstring Coverage Warning Docstring coverage is 33.33% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 6 functions across 7 files. (2 skipped: 2… Write docstrings for the functions missing them to satisfy the coverage threshold.
Passed Passed checks: 4 passed
Check name Status Explanation
Title check Passed Le titre « feat: choose an artist's portrait and banner from the artist page » décrit le changement principal : choisir le portrait et la bannière d'un artiste depuis la page artiste. Le résumé brut c…
Description check Passed La description suit le modèle du dépôt : résumé avec lien vers la RFC-013 et l'issue serveur #309, liste des changements, section de tests avec les résultats de validation et section Notes. Les sectio…
Linked Issues check Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check Passed Check skipped because no linked issues were found for this pull request.
Full details: Title check

Explanation

Le titre « feat: choose an artist's portrait and banner from the artist page » décrit le changement principal : choisir le portrait et la bannière d'un artiste depuis la page artiste. Le résumé brut confirme ce périmètre (contrôles de remplacement, route PUT/DELETE, affichage de la bannière). Le titre est court, précis et en une seule phrase.

Full details: Description check

Explanation

La description suit le modèle du dépôt : résumé avec lien vers la RFC-013 et l'issue serveur #309, liste des changements, section de tests avec les résultats de validation et section Notes. Les sections Test plan ne reprennent pas exactement les cases du modèle (pas de lien explicite vers bun run dev ni de coche par commande), mais les validations sont décrites. La case de conformité à la licence AGPL-3.0-only et au DCO n'apparaît pas dans la description.

Full details: Docstring Coverage

Explanation

Docstring coverage is 33.33% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 6 functions across 7 files. (2 skipped: 2 unsupported.)

Resolution

Write docstrings for the functions missing them to satisfy the coverage threshold.

✨ Finishing Touches: 💡 1
📝 Generate docstrings: 💡
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Warning

Some tools did not complete. Review the errors below.

🔧 Biome (2.5.15)
webapp/e2e/studio-nocturne.spec.ts

Biome could not lint this file: nested root configuration. Check the repository's Biome configuration and plugins.

webapp/src/api/catalog.ts

Biome could not lint this file: nested root configuration. Check the repository's Biome configuration and plugins.

webapp/src/api/index.ts

Biome could not lint this file: nested root configuration. Check the repository's Biome configuration and plugins.

  • 5 others

Comment @coderabbitai help to get the list of available commands.

@github-actions github-actions Bot added type: feat New feature and removed type: feat New feature labels Oct 23, 2026
@InstaZDLL InstaZDLL self-assigned this Oct 23, 2026
@github-actions github-actions Bot added type: feat New feature and removed type: feat New feature labels Oct 23, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

scope: components Web UI components scope: docs Docs, README, assets scope: web Embedded web player (React) size: l 200-500 lines type: feat New feature

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant