Formats repo
Build and Deploy / build-and-deploy (push) Successful in 15m3s

This commit is contained in:
2026-05-25 22:11:28 -04:00
parent 0b6b9c3d17
commit ac7a979fe9
3 changed files with 57 additions and 37 deletions
+12 -6
View File
@@ -36,13 +36,15 @@ data CookEntry = CookEntry
instance FromRow CookEntry where instance FromRow CookEntry where
fromRow = CookEntry <$> SQL.field <*> SQL.field <*> SQL.field <*> SQL.field <*> (trimQuotes <$> SQL.field) fromRow = CookEntry <$> SQL.field <*> SQL.field <*> SQL.field <*> SQL.field <*> (trimQuotes <$> SQL.field)
-- | Strip leading/trailing double-quote characters from a Text value. {- | Strip leading/trailing double-quote characters from a Text value.
-- This handles any accidental quote wrapping from the DB round-trip. This handles any accidental quote wrapping from the DB round-trip.
-}
trimQuotes :: Text -> Text trimQuotes :: Text -> Text
trimQuotes = T.dropAround (== '"') trimQuotes = T.dropAround (== '"')
instance ToJSON CookEntry where instance ToJSON CookEntry where
toJSON e = A.object toJSON e =
A.object
[ "id" A..= A.toJSON (ceId e) [ "id" A..= A.toJSON (ceId e)
, "recipe_filename" A..= A.toJSON (ceRecipeFilename e) , "recipe_filename" A..= A.toJSON (ceRecipeFilename e)
, "cooked_date" A..= A.toJSON (show (ceCookedDate e)) , "cooked_date" A..= A.toJSON (show (ceCookedDate e))
@@ -61,7 +63,9 @@ instance FromJSON CookEntry where
where where
parseDate t = case T.splitOn "-" t of parseDate t = case T.splitOn "-" t of
[y, m, d] -> case fromGregorianValid [y, m, d] -> case fromGregorianValid
(read (T.unpack y)) (read (T.unpack m)) (read (T.unpack d)) of (read (T.unpack y))
(read (T.unpack m))
(read (T.unpack d)) of
Just day -> pure day Just day -> pure day
Nothing -> fail "invalid date" Nothing -> fail "invalid date"
_ -> fail "expected YYYY-MM-DD" _ -> fail "expected YYYY-MM-DD"
@@ -104,7 +108,8 @@ insertEntry conn filename day mComment = do
-- | Fetch all entries for a given recipe, newest first. -- | Fetch all entries for a given recipe, newest first.
fetchEntries :: Connection -> Text -> IO [CookEntry] fetchEntries :: Connection -> Text -> IO [CookEntry]
fetchEntries conn filename = fetchEntries conn filename =
SQL.query conn SQL.query
conn
"SELECT id, recipe_filename, cooked_date, comment, created_at \ "SELECT id, recipe_filename, cooked_date, comment, created_at \
\ FROM cook_log WHERE recipe_filename = ? ORDER BY cooked_date DESC, id DESC" \ FROM cook_log WHERE recipe_filename = ? ORDER BY cooked_date DESC, id DESC"
(Only filename) (Only filename)
@@ -112,6 +117,7 @@ fetchEntries conn filename =
-- | Fetch all entries across all recipes, newest first. -- | Fetch all entries across all recipes, newest first.
fetchAllEntries :: Connection -> IO [CookEntry] fetchAllEntries :: Connection -> IO [CookEntry]
fetchAllEntries conn = fetchAllEntries conn =
SQL.query_ conn SQL.query_
conn
"SELECT id, recipe_filename, cooked_date, comment, created_at \ "SELECT id, recipe_filename, cooked_date, comment, created_at \
\ FROM cook_log ORDER BY cooked_date DESC, id DESC" \ FROM cook_log ORDER BY cooked_date DESC, id DESC"
+8 -3
View File
@@ -853,10 +853,15 @@ renderCookLog filename entries = do
H.form H.form
! A.class_ "roux-cook-log-form" ! A.class_ "roux-cook-log-form"
! H.dataAttribute "filename" (H.toValue (T.pack filename)) ! H.dataAttribute "filename" (H.toValue (T.pack filename))
! A.style "display: flex; gap: 0.3rem; margin-bottom: 0.5rem;" $ do ! A.style "display: flex; gap: 0.3rem; margin-bottom: 0.5rem;"
$ do
H.input ! A.type_ "date" ! A.name "cooked-date" H.input ! A.type_ "date" ! A.name "cooked-date"
H.input ! A.type_ "text" ! A.name "comment" ! A.placeholder "Optional note..." H.input
! A.maxlength "500" ! A.style "flex: 1;" ! A.type_ "text"
! A.name "comment"
! A.placeholder "Optional note..."
! A.maxlength "500"
! A.style "flex: 1;"
H.button ! A.type_ "submit" $ "Log it" H.button ! A.type_ "submit" $ "Log it"
H.div ! A.class_ "roux-cook-entries" $ do H.div ! A.class_ "roux-cook-entries" $ do
mapM_ renderEntry entries mapM_ renderEntry entries
+16 -7
View File
@@ -47,19 +47,19 @@ import qualified Data.Aeson.KeyMap as KM
import qualified Data.ByteString as BS import qualified Data.ByteString as BS
import Data.Maybe (fromMaybe, mapMaybe) import Data.Maybe (fromMaybe, mapMaybe)
import qualified Data.Text.Encoding as TE import qualified Data.Text.Encoding as TE
import qualified Database.SQLite.Simple as SQL
import Data.Time.Calendar (Day, fromGregorianValid) import Data.Time.Calendar (Day, fromGregorianValid)
import qualified Data.Time.Format as Time import qualified Data.Time.Format as Time
import Text.Read (readMaybe) import qualified Database.SQLite.Simple as SQL
import Roux.Config (AnthropicConfig (..), RouxConfig (..)) import Roux.Config (AnthropicConfig (..), RouxConfig (..))
import qualified Roux.CooklangPrint as CooklangPrint
import qualified Roux.CookLog as CookLog import qualified Roux.CookLog as CookLog
import qualified Roux.CooklangPrint as CooklangPrint
import qualified Roux.Html as Html import qualified Roux.Html as Html
import qualified Roux.RecipeIndex as Idx import qualified Roux.RecipeIndex as Idx
import Roux.SchemaOrg (SchemaOrgRecipe (..), parseSchemaOrgRecipe, schemaOrgToCooklang) import Roux.SchemaOrg (SchemaOrgRecipe (..), parseSchemaOrgRecipe, schemaOrgToCooklang)
import System.Exit (ExitCode (..)) import System.Exit (ExitCode (..))
import System.IO (hSetBinaryMode) import System.IO (hSetBinaryMode)
import System.Process (CreateProcess (..), StdStream (CreatePipe), createProcess, proc, waitForProcess) import System.Process (CreateProcess (..), StdStream (CreatePipe), createProcess, proc, waitForProcess)
import Text.Read (readMaybe)
-- | Read the full request body as a lazy ByteString. -- | Read the full request body as a lazy ByteString.
readRequestBody :: Wai.Request -> IO LB.ByteString readRequestBody :: Wai.Request -> IO LB.ByteString
@@ -645,7 +645,9 @@ handleRequest state db request respond = do
["cook-log", filename] -> do ["cook-log", filename] -> do
entries <- CookLog.fetchEntries db filename entries <- CookLog.fetchEntries db filename
let body = A.encode entries let body = A.encode entries
respond $ Wai.responseLBS HTTP.status200 respond $
Wai.responseLBS
HTTP.status200
[("Content-Type", "application/json")] [("Content-Type", "application/json")]
body body
-- Cook history page (all entries across recipes) -- Cook history page (all entries across recipes)
@@ -656,7 +658,9 @@ handleRequest state db request respond = do
-- Cook log JSON endpoint for all entries -- Cook log JSON endpoint for all entries
["cook-log"] -> do ["cook-log"] -> do
entries <- CookLog.fetchAllEntries db entries <- CookLog.fetchAllEntries db
respond $ Wai.responseLBS HTTP.status200 respond $
Wai.responseLBS
HTTP.status200
[("Content-Type", "application/json")] [("Content-Type", "application/json")]
(A.encode entries) (A.encode entries)
_ -> respond notFound _ -> respond notFound
@@ -671,11 +675,16 @@ handleCookLogPost db filename request respond = do
case parseDate dateStr of case parseDate dateStr of
Just day -> do Just day -> do
_ <- CookLog.insertEntry db filename day comment _ <- CookLog.insertEntry db filename day comment
let resp = Wai.responseLBS HTTP.status200 [("Content-Type", "application/json")] let resp =
Wai.responseLBS
HTTP.status200
[("Content-Type", "application/json")]
(LB.fromStrict (encodeUtf8 "{\"ok\":true}")) (LB.fromStrict (encodeUtf8 "{\"ok\":true}"))
respond resp respond resp
Nothing -> Nothing ->
let resp = Wai.responseLBS HTTP.status400 let resp =
Wai.responseLBS
HTTP.status400
[("Content-Type", "application/json")] [("Content-Type", "application/json")]
(LB.fromStrict (encodeUtf8 "{\"error\":\"Invalid date format\"}")) (LB.fromStrict (encodeUtf8 "{\"error\":\"Invalid date format\"}"))
in respond resp in respond resp