Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/haskell-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
65 changes: 65 additions & 0 deletions exe-t4-api/API.hs
Original file line number Diff line number Diff line change
@@ -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
9 changes: 9 additions & 0 deletions exe-t4-api/static/report.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>t4 Report</title>
</head>
<body>
<p>t4 report placeholder</p>
</body>
</html>
19 changes: 19 additions & 0 deletions terminal-time-tracking-tool.cabal
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down