refactor(settings,lib): home licensesData + userMgmtHelpers to owners

a11y-branch hold lifted (Frank: modals get re-refactored separately, no rebase to
protect). Both were only blocked by their modal consumers:
- licensesData (pure licenses.json lazy-loader) → features/settings/utils; main
  consumer is the settings LicensesPanel. JSON dynamic import absolutized to
  @/data/licenses.json.
- userMgmtHelpers (pure formatLastSeen, lib/format only) → lib/format; multi-feature
  consumer set, same class as playlistDetailHelpers.
Drains utils/componentHelpers (dir removed). Only import lines changed in the
LicenseTextModal/SongInfoModal consumers (logic untouched); tests pass unmodified.
This commit is contained in:
Psychotoxical
2026-06-30 22:15:46 +02:00
parent ccaecdddd8
commit 6590bd15ef
10 changed files with 9 additions and 9 deletions
+1 -1
View File
@@ -12,7 +12,7 @@ import { previewInputFromSong, usePreviewStore } from '@/features/playback/store
import StarRating from '@/ui/StarRating';
import { codecLabel, type ColKey } from '@/features/album/utils/albumTrackListHelpers';
import { formatLongDuration } from '@/lib/format/formatDuration';
import { formatLastSeen } from '@/utils/componentHelpers/userMgmtHelpers';
import { formatLastSeen } from '@/lib/format/userMgmtHelpers';
import i18n from '@/lib/i18n';
import { offlineActionPolicy, type OfflineActionPolicy } from '@/features/offline';
import { resolveTrackArtistRefs } from '@/features/playback/utils/playback/trackArtistRefs';
@@ -4,7 +4,7 @@ import { AudioLines, ChevronRight, Play, Square, X } from 'lucide-react';
import type { ColDef } from '@/hooks/useTracklistColumns';
import type { SubsonicSong } from '@/lib/api/subsonicTypes';
import { codecLabel } from '@/lib/format/playlistDetailHelpers';
import { formatLastSeen } from '@/utils/componentHelpers/userMgmtHelpers';
import { formatLastSeen } from '@/lib/format/userMgmtHelpers';
import i18n from '@/lib/i18n';
import { formatTrackTime } from '@/lib/format/formatDuration';
import StarRating from '@/ui/StarRating';
@@ -4,7 +4,7 @@ import { AudioLines, ChevronRight, Heart, Play, Square, Trash2 } from 'lucide-re
import type { ColDef } from '@/hooks/useTracklistColumns';
import type { SubsonicSong } from '@/lib/api/subsonicTypes';
import { codecLabel } from '@/lib/format/playlistDetailHelpers';
import { formatLastSeen } from '@/utils/componentHelpers/userMgmtHelpers';
import { formatLastSeen } from '@/lib/format/userMgmtHelpers';
import i18n from '@/lib/i18n';
import { formatTrackTime } from '@/lib/format/formatDuration';
import StarRating from '@/ui/StarRating';
@@ -13,7 +13,7 @@ import { usePlaylistLayoutStore } from '@/features/playlist/store/playlistLayout
import { songToTrack } from '@/lib/media/songToTrack';
import { getQueueTracksView } from '@/features/playback/store/queueTrackView';
import { codecLabel } from '@/lib/format/playlistDetailHelpers';
import { formatLastSeen } from '@/utils/componentHelpers/userMgmtHelpers';
import { formatLastSeen } from '@/lib/format/userMgmtHelpers';
import { formatTrackTime } from '@/lib/format/formatDuration';
import i18n from '@/lib/i18n';
@@ -8,7 +8,7 @@ import {
loadLicensesData,
type LicenseEntry,
type LicensesData,
} from '@/utils/licensesData';
} from '@/features/settings/utils/licensesData';
import LicenseTextModal from '@/components/LicenseTextModal';
const ROW_HEIGHT = 56;
@@ -2,7 +2,7 @@ import React from 'react';
import { Shield, Trash2, User, Wand2 } from 'lucide-react';
import type { i18n as I18nType, TFunction } from 'i18next';
import type { NdLibrary, NdUser } from '@/lib/api/navidromeAdmin';
import { formatLastSeen } from '@/utils/componentHelpers/userMgmtHelpers';
import { formatLastSeen } from '@/lib/format/userMgmtHelpers';
interface Props {
user: NdUser;
@@ -0,0 +1,57 @@
// Lazy loader + types for the bundled `src/data/licenses.json` data.
//
// The JSON is generated by `node scripts/generate-licenses.mjs` (maintainer-only)
// and committed to source. Vite bundles it as a separate JS chunk via dynamic
// import below, so the heavy ~12 MB payload is only loaded when the user
// actually opens the Open Source Licenses panel — no runtime fetch, the data
// lives entirely inside the build artifact.
export interface LicenseEntry {
name: string;
version: string;
source: 'npm' | 'cargo';
licenses: string[];
repository?: string;
homepage?: string;
description?: string;
publisher?: string;
licenseText?: string;
}
export interface LicensesData {
generatedAt: string;
project: { name: string; version: string };
stats: { npm: number; cargo: number; total: number; withFullText: number };
entries: LicenseEntry[];
}
let cache: Promise<LicensesData> | null = null;
export function loadLicensesData(): Promise<LicensesData> {
if (cache) return cache;
cache = import('@/data/licenses.json')
.then((mod) => (mod.default ?? mod) as LicensesData)
.catch((e) => {
cache = null;
throw e;
});
return cache;
}
/**
* Curated list of dependency names shown in the highlight block at the top of
* the panel — the user-recognisable backbone of the app. Order matters here;
* the panel renders them top-to-bottom as listed.
*/
export const HIGHLIGHTED_DEPENDENCIES: Array<{ source: 'npm' | 'cargo'; name: string }> = [
{ source: 'cargo', name: 'tauri' },
{ source: 'npm', name: 'react' },
{ source: 'npm', name: 'zustand' },
{ source: 'cargo', name: 'rodio' },
{ source: 'cargo', name: 'symphonia' },
{ source: 'cargo', name: 'cpal' },
{ source: 'npm', name: 'axios' },
{ source: 'npm', name: '@tanstack/react-virtual' },
{ source: 'npm', name: 'react-i18next' },
{ source: 'npm', name: 'lucide-react' },
];