From b8e050f66d047c5310c5c78cbe7d0795ae32b5dc Mon Sep 17 00:00:00 2001 From: Niels Mokkenstorm Date: Thu, 16 Jul 2026 22:12:41 +0200 Subject: [PATCH] refactor(web): move ignored-proposals json codec from model to prefs --- web/src/at_record_web.gleam | 2 +- web/src/at_record_web/effects.gleam | 2 +- web/src/at_record_web/model.gleam | 27 --------------------------- web/src/at_record_web/prefs.gleam | 28 ++++++++++++++++++++++++++++ web/test/prefs_test.gleam | 7 ++++--- 5 files changed, 34 insertions(+), 32 deletions(-) diff --git a/web/src/at_record_web.gleam b/web/src/at_record_web.gleam index cf29117..119eb02 100644 --- a/web/src/at_record_web.gleam +++ b/web/src/at_record_web.gleam @@ -122,6 +122,6 @@ fn initial_display() -> model.Display { /// synchronous-at-init reasoning as `initial_display`. fn initial_ignored_proposals() -> List(#(String, String)) { prefs.get(prefs.ignored_proposals_key) - |> result.map(model.decode_ignored_proposals) + |> result.map(prefs.decode_ignored_proposals) |> result.unwrap([]) } diff --git a/web/src/at_record_web/effects.gleam b/web/src/at_record_web/effects.gleam index 412ee31..bd00f45 100644 --- a/web/src/at_record_web/effects.gleam +++ b/web/src/at_record_web/effects.gleam @@ -447,7 +447,7 @@ pub fn persist_ignored_proposals( effect.from(fn(_dispatch) { prefs.set( prefs.ignored_proposals_key, - model.encode_ignored_proposals(ignored), + prefs.encode_ignored_proposals(ignored), ) }) } diff --git a/web/src/at_record_web/model.gleam b/web/src/at_record_web/model.gleam index 8d5e0a3..c03fd64 100644 --- a/web/src/at_record_web/model.gleam +++ b/web/src/at_record_web/model.gleam @@ -1,9 +1,7 @@ import at_record/gen/defs.{type Price, type Snapshot} import at_record/gen/shelf/entry.{type ShelfEntry} import gleam/dict -import gleam/dynamic/decode import gleam/int -import gleam/json import gleam/list import gleam/option.{type Option, None} import gleam/set @@ -465,31 +463,6 @@ pub fn add_ignored_proposal( } } -pub fn encode_ignored_proposals(ignored: List(#(String, String))) -> String { - ignored - |> json.array(fn(pair) { - json.object([ - #("uri", json.string(pair.0)), - #("cid", json.string(pair.1)), - ]) - }) - |> json.to_string -} - -/// Anything that fails to parse (never persisted, corrupted, a stale shape) -/// falls back to an empty ignore list rather than blocking the inbox. -pub fn decode_ignored_proposals(raw: String) -> List(#(String, String)) { - let decoder = { - use uri <- decode.field("uri", decode.string) - use cid <- decode.field("cid", decode.string) - decode.success(#(uri, cid)) - } - case json.parse(raw, decode.list(decoder)) { - Ok(pairs) -> pairs - Error(_) -> [] - } -} - /// The outcome of one capped collection-import run. pub type ImportRun { ImportRun( diff --git a/web/src/at_record_web/prefs.gleam b/web/src/at_record_web/prefs.gleam index f96f86a..e0c25f6 100644 --- a/web/src/at_record_web/prefs.gleam +++ b/web/src/at_record_web/prefs.gleam @@ -5,6 +5,9 @@ //// runtime) just means a preference silently doesn't persist, never a //// crash - callers always have a sensible default to fall back to. +import gleam/dynamic/decode +import gleam/json + @external(javascript, "./ffi.mjs", "prefsGet") fn ffi_get(key: String) -> Result(String, Nil) @@ -34,3 +37,28 @@ pub fn get(key: String) -> Result(String, Nil) { pub fn set(key: String, value: String) -> Nil { ffi_set(namespaced(key), value) } + +pub fn encode_ignored_proposals(ignored: List(#(String, String))) -> String { + ignored + |> json.array(fn(pair) { + json.object([ + #("uri", json.string(pair.0)), + #("cid", json.string(pair.1)), + ]) + }) + |> json.to_string +} + +/// Anything that fails to parse (never persisted, corrupted, a stale shape) +/// falls back to an empty ignore list rather than blocking the inbox. +pub fn decode_ignored_proposals(raw: String) -> List(#(String, String)) { + let decoder = { + use uri <- decode.field("uri", decode.string) + use cid <- decode.field("cid", decode.string) + decode.success(#(uri, cid)) + } + case json.parse(raw, decode.list(decoder)) { + Ok(pairs) -> pairs + Error(_) -> [] + } +} diff --git a/web/test/prefs_test.gleam b/web/test/prefs_test.gleam index 4a1ca4e..2f826b1 100644 --- a/web/test/prefs_test.gleam +++ b/web/test/prefs_test.gleam @@ -10,6 +10,7 @@ import at_record_web/model.{ ProposalFields, ProposalReviewing, Rows, } import at_record_web/msg.{GotEditInbox, IgnoreProposal, SetDisplay} +import at_record_web/prefs import at_record_web/update.{update} import gleam/int import gleam/list @@ -65,13 +66,13 @@ pub fn set_display_persists_and_updates_the_model_test() { pub fn ignored_proposals_round_trip_through_json_test() { let ignored = [#("at://a/edit/1", "cid-1"), #("at://a/edit/2", "cid-2")] let decoded = - ignored |> model.encode_ignored_proposals |> model.decode_ignored_proposals + ignored |> prefs.encode_ignored_proposals |> prefs.decode_ignored_proposals assert decoded == ignored } pub fn ignored_proposals_decode_falls_back_to_empty_on_garbage_test() { - assert model.decode_ignored_proposals("not json") == [] - assert model.decode_ignored_proposals("{}") == [] + assert prefs.decode_ignored_proposals("not json") == [] + assert prefs.decode_ignored_proposals("{}") == [] } pub fn add_ignored_proposal_dedupes_on_uri_test() { -- 2.51.2