fix(settings): sort the contributors list chronologically (#700)

* fix(settings): sort the contributors list chronologically

The Settings → System contributors list rendered the array in raw
insertion order, so Psychotoxical (since v1.0.0) showed up last and
hand-maintained ordering drifted over time.

Sort on export instead: ascending by the `since` app version (reusing
isNewer), tie-broken by the first-contribution PR number. The list
stays correctly ordered regardless of where new entries are inserted.

* docs(changelog): add entry for contributors list sort fix (#700)
This commit is contained in:
Frank Stellmacher
2026-05-14 21:45:34 +02:00
committed by GitHub
parent f054fe425c
commit 77f6933410
3 changed files with 49 additions and 1 deletions
+6
View File
@@ -255,6 +255,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## Fixed ## Fixed
### Settings — contributors list sorted chronologically
**By [@Psychotoxical](https://github.com/Psychotoxical), PR [#700](https://github.com/Psychotoxical/psysonic/pull/700)**
* The **Settings → System → Contributors** list rendered in raw insertion order, so the original maintainer (since v1.0.0) showed up last and the hand-maintained ordering drifted as new entries were appended. It is now sorted on render — ascending by the app version a contributor first appeared in, tie-broken by their first-contribution PR number — so it stays correct no matter where new entries land in the source list.
### Internet Radio — Add / Edit station modal no longer clipped on empty library ### Internet Radio — Add / Edit station modal no longer clipped on empty library
**By [@cucadmuh](https://github.com/cucadmuh), thanks to voidboywannabe for the report on the Psysonic Discord, PR [#699](https://github.com/Psychotoxical/psysonic/pull/699)** **By [@cucadmuh](https://github.com/cucadmuh), thanks to voidboywannabe for the report on the Psysonic Discord, PR [#699](https://github.com/Psychotoxical/psysonic/pull/699)**
+24
View File
@@ -0,0 +1,24 @@
import { describe, it, expect } from 'vitest';
import { CONTRIBUTORS } from './settingsCredits';
import { isNewer } from '../utils/componentHelpers/appUpdaterHelpers';
describe('CONTRIBUTORS ordering', () => {
it('is sorted ascending by the `since` app version', () => {
for (let i = 1; i < CONTRIBUTORS.length; i++) {
// a preceding entry must never be newer than the one after it
expect(isNewer(CONTRIBUTORS[i - 1].since, CONTRIBUTORS[i].since)).toBe(false);
}
});
it('puts the original maintainer (v1.0.0) first', () => {
expect(CONTRIBUTORS[0].github).toBe('Psychotoxical');
});
it('breaks `since` ties by first-contribution PR number', () => {
// nullobject (PR #7) and trbn1 (PR #9) both first appeared in v1.22.0
const nullobject = CONTRIBUTORS.findIndex(c => c.github === 'nullobject');
const trbn1 = CONTRIBUTORS.findIndex(c => c.github === 'trbn1');
expect(nullobject).toBeGreaterThanOrEqual(0);
expect(nullobject).toBeLessThan(trbn1);
});
});
+19 -1
View File
@@ -1,5 +1,7 @@
import { isNewer } from '../utils/componentHelpers/appUpdaterHelpers';
// Credits list rendered on the Settings → System tab. Update via PR when adding a contributor. // Credits list rendered on the Settings → System tab. Update via PR when adding a contributor.
export const CONTRIBUTORS = [ const CONTRIBUTOR_ENTRIES = [
{ {
github: 'jiezhuo', github: 'jiezhuo',
since: '1.21', since: '1.21',
@@ -284,6 +286,22 @@ export const CONTRIBUTORS = [
}, },
] as const; ] as const;
// PR number of a contributor's first listed contribution, used as the
// tie-breaker when several contributors share the same `since` version.
function firstContributionPr(entry: { contributions: readonly string[] }): number {
const match = entry.contributions[0]?.match(/PR #(\d+)/);
return match ? Number(match[1]) : Number.MAX_SAFE_INTEGER;
}
// Rendered chronologically: ascending by the app version a contributor first
// appeared in (`since`), then by their first-contribution PR number. Sorting
// here keeps the order correct no matter where new entries land in the array.
export const CONTRIBUTORS = [...CONTRIBUTOR_ENTRIES].sort((a, b) => {
if (isNewer(a.since, b.since)) return 1;
if (isNewer(b.since, a.since)) return -1;
return firstContributionPr(a) - firstContributionPr(b);
});
export const MAINTAINERS = [ export const MAINTAINERS = [
{ github: 'Psychotoxical' }, { github: 'Psychotoxical' },
{ github: 'cucadmuh' }, { github: 'cucadmuh' },