import * as Schema from "effect/Schema"; import { EnvironmentId, ProjectId, PullRequestInvolvement, PullRequestListFilters, PullRequestListState, } from "@t3tools/contracts"; export const PullRequestListSort = Schema.Literals([ "ready", "updated", "newest", "oldest", "largest", "smallest", ]); export type PullRequestListSort = typeof PullRequestListSort.Type; export interface PullRequestListPreferences { readonly involvement: PullRequestInvolvement; readonly state: PullRequestListState; readonly environmentId?: EnvironmentId; readonly projectId?: ProjectId; readonly host?: string; readonly q?: string; readonly draft?: "only" | "hide"; readonly review?: NonNullable; readonly checks?: NonNullable; readonly author?: string; readonly labels?: ReadonlyArray; readonly sort?: PullRequestListSort; } export type PullRequestListPreferencePatch = { [Key in keyof PullRequestListPreferences]?: PullRequestListPreferences[Key] | undefined; }; const DEFAULT_PULL_REQUEST_LIST_PREFERENCES = { involvement: "all", state: "open", } as const satisfies PullRequestListPreferences; const BoundedPreference = Schema.String.check(Schema.isMaxLength(200)); const PullRequestListPreferencesSchema = Schema.Struct({ involvement: PullRequestInvolvement, state: PullRequestListState, environmentId: Schema.optional(EnvironmentId), projectId: Schema.optional(ProjectId), host: Schema.optional(BoundedPreference), q: Schema.optional(BoundedPreference), draft: PullRequestListFilters.fields.draft, review: PullRequestListFilters.fields.review, checks: PullRequestListFilters.fields.checks, author: Schema.optional(BoundedPreference), labels: Schema.optional(Schema.Array(BoundedPreference).check(Schema.isMaxLength(10))), sort: Schema.optional(PullRequestListSort), }); const decodePullRequestListPreferences = Schema.decodeUnknownOption( PullRequestListPreferencesSchema, ); const PULL_REQUEST_LIST_PREFERENCES_STORAGE_KEY = "t3.pullRequests.preferences"; type PreferenceStorage = Pick; function resolvePreferenceStorage( storage: PreferenceStorage | undefined, ): PreferenceStorage | undefined { return storage ?? (typeof window === "undefined" ? undefined : window.localStorage); } /** Only list controls are remembered. The selected row remains a URL and right-panel concern. */ export function pullRequestListPreferences( search: PullRequestListPreferences | Schema.Schema.Type, ): PullRequestListPreferences { return { involvement: search.involvement, state: search.state, ...(search.environmentId ? { environmentId: search.environmentId } : {}), ...(search.projectId ? { projectId: search.projectId } : {}), ...(search.host ? { host: search.host } : {}), ...(search.q ? { q: search.q } : {}), ...(search.draft ? { draft: search.draft } : {}), ...(search.review ? { review: search.review } : {}), ...(search.checks ? { checks: search.checks } : {}), ...(search.author ? { author: search.author } : {}), ...(search.labels && search.labels.length > 0 ? { labels: search.labels } : {}), ...(search.sort && search.sort !== "ready" ? { sort: search.sort } : {}), }; } export function readPullRequestListPreferences( storage?: PreferenceStorage, ): PullRequestListPreferences { try { const raw = resolvePreferenceStorage(storage)?.getItem( PULL_REQUEST_LIST_PREFERENCES_STORAGE_KEY, ); if (!raw) return DEFAULT_PULL_REQUEST_LIST_PREFERENCES; const decoded = decodePullRequestListPreferences(JSON.parse(raw)); return decoded._tag === "Some" ? pullRequestListPreferences(decoded.value) : DEFAULT_PULL_REQUEST_LIST_PREFERENCES; } catch { return DEFAULT_PULL_REQUEST_LIST_PREFERENCES; } } export function writePullRequestListPreferences( preferences: PullRequestListPreferences, storage?: PreferenceStorage, ): void { try { resolvePreferenceStorage(storage)?.setItem( PULL_REQUEST_LIST_PREFERENCES_STORAGE_KEY, JSON.stringify(preferences), ); } catch { // Storage can be full or denied; the URL remains the source of truth for this visit. } }