zustand stores

This commit is contained in:
2026-03-27 03:32:48 +02:00
parent df17c7ab95
commit b0c2e48224
20 changed files with 1279 additions and 0 deletions
+80
View File
@@ -0,0 +1,80 @@
import { create } from 'zustand'
import { createJSONStorage, persist } from 'zustand/middleware'
import { sensitiveStorage } from '../lib/sensitive-storage'
/**
* Connection details for a Sonarr / Radarr instance. The user can have
* up to two of each: a "default" tier (1080p, regular library) and a
* "4K" tier (separate root folder + quality profile). Many users keep
* 4K and 1080p in separate libraries to avoid Jellyfin transcoding 4K
* down to 1080p on weak clients.
*/
export interface ArrInstance {
id: string
kind: 'sonarr' | 'radarr'
/** Display name shown in the request modal and Settings. */
name: string
baseUrl: string
apiKey: string
/** Distinguishes the regular tier from the 4K tier of the same kind. */
tier: 'default' | '4k'
/** Defaults the request modal pre-selects unless an override rule
* fires or the user picks something else. */
defaultQualityProfileId?: number
defaultRootFolder?: string
defaultLanguageProfileId?: number
/** Sonarr-only: monitor flag + season-folder layout the requester gets. */
defaultMonitored?: boolean
defaultSeasonFolder?: boolean
/** Optional connection-test verdict, refreshed when settings page tests it. */
lastTestedAt?: string
lastTestVersion?: string
lastTestError?: string
}
interface State {
instances: ArrInstance[]
upsert: (instance: ArrInstance) => void
remove: (id: string) => void
/** Convenience: find the instance matching kind + tier, or null. */
pick: (kind: 'sonarr' | 'radarr', tier: 'default' | '4k') => ArrInstance | null
}
function uid() {
return 'arr_' + Math.random().toString(36).slice(2, 10) + Date.now().toString(36)
}
export const useArrInstances = create<State>()(
persist(
(set, get) => ({
instances: [],
upsert: instance =>
set(s => {
const exists = s.instances.some(x => x.id === instance.id)
if (exists) {
return {
instances: s.instances.map(x => (x.id === instance.id ? instance : x)),
}
}
return { instances: [...s.instances, instance] }
}),
remove: id => set(s => ({ instances: s.instances.filter(x => x.id !== id) })),
pick: (kind, tier) =>
get().instances.find(x => x.kind === kind && x.tier === tier) || null,
}),
{ name: 'arr-instances-v1', storage: createJSONStorage(() => sensitiveStorage) },
),
)
export function newArrInstance(kind: 'sonarr' | 'radarr', tier: 'default' | '4k'): ArrInstance {
return {
id: uid(),
kind,
tier,
name: `${kind === 'sonarr' ? 'Sonarr' : 'Radarr'}${tier === '4k' ? ' 4K' : ''}`,
baseUrl: '',
apiKey: '',
defaultMonitored: true,
defaultSeasonFolder: true,
}
}