diff --git a/.github/workflows/haskell-ci.yml b/.github/workflows/haskell-ci.yml index 4ef3d1e..7561002 100644 --- a/.github/workflows/haskell-ci.yml +++ b/.github/workflows/haskell-ci.yml @@ -5,6 +5,7 @@ jobs: build_test_doc: runs-on: ubuntu-latest steps: + - run: sudo apt install -y liblzma-dev pkg-config - uses: actions/checkout@v4 - uses: haskell-actions/setup@v2 id: setup diff --git a/exe-t4-api/API.hs b/exe-t4-api/API.hs new file mode 100644 index 0000000..8ed5b62 --- /dev/null +++ b/exe-t4-api/API.hs @@ -0,0 +1,65 @@ +import T4.Data +import T4.Storage +import qualified Data.Set as S +import Control.Monad.IO.Class +import Control.Lens +import Data.Aeson +import Servant +import Data.OpenApi hiding (Tag, Server, server) +import Servant.OpenApi +import Servant.Swagger.UI +import Network.Wai.Handler.Warp +import qualified Paths_terminal_time_tracking_tool as Paths + +instance ToSchema Clock where + declareNamedSchema _ = do + return $ NamedSchema (Just "Clock") $ mempty + & type_ ?~ OpenApiObject + & example ?~ toJSON clock + where clock = In (SLT (read "2025-11-04 09:15:00")) + (Just "T4 programming") + (S.fromList ["backend", "api", "haskell"]) + +t4OpenApi :: OpenApi +t4OpenApi = toOpenApi (Proxy :: Proxy T4API) + & info . title .~ "T4: Terminal Time Tracking Tool API" + & info . description ?~ "Read-only API for T4 time tracking" + +type API = T4API + :<|> "openapi.json" :> Get '[JSON] OpenApi + :<|> SwaggerSchemaUI "swagger-ui" "swagger.json" + :<|> Raw + +type T4API = Get '[JSON] (Maybe Clock) + :<|> "clocks" :> Get '[JSON] [Clock] + :<|> "categories" :> Get '[JSON] [Category] + :<|> "tags" :> Get '[JSON] [Tag] + +server :: FilePath -> Server API +server staticDir = apiServer + :<|> pure t4OpenApi + :<|> swaggerSchemaUIServer t4OpenApi + :<|> serveDirectoryFileServer staticDir + +apiServer :: Server T4API +apiServer = getStatus + :<|> getClocks + :<|> getCategories + :<|> getTags + + where getStatus = findMax <$> clocks + getClocks = S.toList <$> clocks + getCategories = S.toList . allCategories <$> clocks + getTags = S.toList . allTags <$> clocks + clocks = do dir <- liftIO getStorageDirectory + liftIO $ loadDataFromDir dir + findMax = fmap fst . S.maxView + +main :: IO () +main = do + staticDir <- Paths.getDataFileName "exe-t4-api/static" + putStrLn "T4 API Server starting..." + putStrLn " OpenAPI spec at: http://localhost:8080/openapi.json" + putStrLn " Swagger UI at: http://localhost:8080/swagger-ui" + putStrLn " API endpoints: http://localhost:8080/*" + run 8080 $ serve (Proxy :: Proxy API) $ server staticDir diff --git a/exe-t4-api/static/report.html b/exe-t4-api/static/report.html new file mode 100644 index 0000000..0c7f40c --- /dev/null +++ b/exe-t4-api/static/report.html @@ -0,0 +1,9 @@ + + +
+t4 report placeholder
+ + diff --git a/terminal-time-tracking-tool.cabal b/terminal-time-tracking-tool.cabal index eefc8f3..5bfca79 100644 --- a/terminal-time-tracking-tool.cabal +++ b/terminal-time-tracking-tool.cabal @@ -9,6 +9,7 @@ build-type: Simple synopsis: t4: terminal time tracking tool homepage: https://github.com/memowe/t4 bug-reports: https://github.com/memowe/t4/issues +data-files: exe-t4-api/static/**/* source-repository head type: git @@ -56,6 +57,24 @@ executable t5 hs-source-dirs: exe-t5-interactive main-is: TUI.hs +executable t4-api + import: basics + default-extensions: DataKinds + , TypeOperators + , FlexibleInstances + ghc-options: -Wno-orphans + build-depends: terminal-time-tracking-tool + , servant-server + , servant-openapi3 + , openapi3 + , servant-swagger-ui + , warp + , lens + hs-source-dirs: exe-t4-api + main-is: API.hs + other-modules: Paths_terminal_time_tracking_tool + autogen-modules: Paths_terminal_time_tracking_tool + test-suite library-test import: basics ghc-options: -Wno-orphans