diff --git a/frontend/src/components/library-status-indicator/library-status-indicator.ts b/frontend/src/components/library-status-indicator/library-status-indicator.ts index 1186c16..5fb8fbe 100644 --- a/frontend/src/components/library-status-indicator/library-status-indicator.ts +++ b/frontend/src/components/library-status-indicator/library-status-indicator.ts @@ -297,9 +297,23 @@ export class LibraryStatusIndicator extends LitElement { // row to one and nothing to the other, and "Add … to library" // was the old button's promise written into the copy. if (this.actionable) { - return this.status === 'queued' - ? `Cancel the request for ${kind}${name}` - : `Request ${kind}${name}`; + if (this.status === 'queued') { + return `Cancel the request for ${kind}${name}`; + } + + // A partly-held album is actionable *and* has a count, and + // the count does not survive being named after the action + // alone. The `partial` case below says why it matters — a + // ring says "some" to a sighted user and nothing to anyone + // else — and that argument does not stop applying because + // the badge became clickable. This branch used to say only + // "Request album X", so the one state the ring exists for + // was the one state whose name did not mention it. + if (this.status === 'partial') { + return `Request the rest of ${kind}${name} — ${this.owned} of ${this.expected} tracks are in your library`; + } + + return `Request ${kind}${name}`; } switch (this.status) { diff --git a/frontend/test/components/library-status-indicator.test.ts b/frontend/test/components/library-status-indicator.test.ts index fca6361..64aae0b 100644 --- a/frontend/test/components/library-status-indicator.test.ts +++ b/frontend/test/components/library-status-indicator.test.ts @@ -77,3 +77,30 @@ describe('the library status badge', () => { expect(name).toContain('Glass Harbour'); }); }); + +/** + * A partly-held album is the one state that is *actionable and + * counted*: there are tracks left to ask for, so the badge is a button + * — and a control is named after what activating it does, which is how + * the count came to be dropped from exactly the state the ring exists + * for. Both, or the ring says "some" to an eye and nothing to anyone + * else. + */ +describe('a partial badge that can act', () => { + it('names the action and keeps the count', async () => { + const el = await fixture('library-status-indicator', { + status: 'partial', + owned: 9, + expected: 12, + entityType: 'album', + label: 'Glass Harbour', + requestMbid: 'rg-1', + }); + + const name = shadow(el, '.badge')?.getAttribute('aria-label') ?? ''; + + expect(shadow(el, 'button.badge')).not.toBeNull(); + expect(name).toContain('Request the rest of'); + expect(name).toContain('9 of 12'); + }); +});