From 201e196fa224c39fcbdebafd3d45949915e8bcc7 Mon Sep 17 00:00:00 2001 From: Dmitry Zuikov Date: Sat, 20 Apr 2024 11:47:31 +0300 Subject: [PATCH] wip --- .../assets/css/custom.css | 14 +++ .../assets/icon/blob.svg | 16 +++ .../assets/icon/tree-up.svg | 4 + .../assets/icon/tree.svg | 4 + hbs2-git/hbs2-git-dashboard/GitDashBoard.hs | 80 +++++++++++++- .../src/HBS2/Git/DashBoard/Prelude.hs | 2 + .../src/HBS2/Git/Web/Html/Root.hs | 104 +++++++++++++++++- hbs2-git/hbs2-git.cabal | 1 + 8 files changed, 218 insertions(+), 7 deletions(-) create mode 100644 hbs2-git/hbs2-git-dashboard-assets/assets/icon/blob.svg create mode 100644 hbs2-git/hbs2-git-dashboard-assets/assets/icon/tree-up.svg create mode 100644 hbs2-git/hbs2-git-dashboard-assets/assets/icon/tree.svg diff --git a/hbs2-git/hbs2-git-dashboard-assets/assets/css/custom.css b/hbs2-git/hbs2-git-dashboard-assets/assets/css/custom.css index cc8c2468..279a63e5 100644 --- a/hbs2-git/hbs2-git-dashboard-assets/assets/css/custom.css +++ b/hbs2-git/hbs2-git-dashboard-assets/assets/css/custom.css @@ -310,3 +310,17 @@ nav[role="tab-control"] li.active { color: #0089D1; } +.mono { + font-family: 'Courier New', Courier, monospace; +} + + +.blob { + width: 16px; + height: 16px; + display: inline-block; + + background-image: url('/icon/file.svg'); + background-size: cover; +} + diff --git a/hbs2-git/hbs2-git-dashboard-assets/assets/icon/blob.svg b/hbs2-git/hbs2-git-dashboard-assets/assets/icon/blob.svg new file mode 100644 index 00000000..cfbcd398 --- /dev/null +++ b/hbs2-git/hbs2-git-dashboard-assets/assets/icon/blob.svg @@ -0,0 +1,16 @@ + + + + + + + diff --git a/hbs2-git/hbs2-git-dashboard-assets/assets/icon/tree-up.svg b/hbs2-git/hbs2-git-dashboard-assets/assets/icon/tree-up.svg new file mode 100644 index 00000000..cd87bb8e --- /dev/null +++ b/hbs2-git/hbs2-git-dashboard-assets/assets/icon/tree-up.svg @@ -0,0 +1,4 @@ + + + + diff --git a/hbs2-git/hbs2-git-dashboard-assets/assets/icon/tree.svg b/hbs2-git/hbs2-git-dashboard-assets/assets/icon/tree.svg new file mode 100644 index 00000000..3516f786 --- /dev/null +++ b/hbs2-git/hbs2-git-dashboard-assets/assets/icon/tree.svg @@ -0,0 +1,4 @@ + + + + diff --git a/hbs2-git/hbs2-git-dashboard/GitDashBoard.hs b/hbs2-git/hbs2-git-dashboard/GitDashBoard.hs index 372d018a..8fbdf234 100644 --- a/hbs2-git/hbs2-git-dashboard/GitDashBoard.hs +++ b/hbs2-git/hbs2-git-dashboard/GitDashBoard.hs @@ -13,6 +13,8 @@ import HBS2.Polling import HBS2.Peer.RPC.API.Storage import HBS2.Peer.RPC.Client.StorageClient +import HBS2.Git.Local +import HBS2.Git.Local.CLI import HBS2.Git.Web.Assets import HBS2.Git.DashBoard.State @@ -39,6 +41,7 @@ import Control.Concurrent.STM (flushTQueue) import System.FilePath import System.Process.Typed import System.Directory (XdgDirectory(..),getXdgDirectory) +import Data.ByteString.Lazy.Char8 qualified as LBS8 configParser :: DashBoardPerks m => Parser (m ()) @@ -185,9 +188,6 @@ runDashboardWeb wo = do get "/repo/:lww" do lwws' <- captureParam @String "lww" <&> fromStringMay @(LWWRefKey HBS2Basic) - - env <- lift ask - flip runContT pure do lww <- lwws' & orFall (status status404) @@ -200,6 +200,80 @@ runDashboardWeb wo = do lift $ html =<< renderTextT (repoPage item) + get "/repo/:lww/manifest" do + lwws' <- captureParam @String "lww" <&> fromStringMay @(LWWRefKey HBS2Basic) + flip runContT pure do + lww <- lwws' & orFall (status status404) + + item <- lift (selectRepoList ( mempty + & set repoListByLww (Just lww) + & set repoListLimit (Just 1)) + ) + <&> listToMaybe + >>= orFall (status status404) + + lift $ html =<< renderTextT (repoManifest item) + + + get "/repo/:lww/refs" do + lwws' <- captureParam @String "lww" <&> fromStringMay @(LWWRefKey HBS2Basic) + flip runContT pure do + lww <- lwws' & orFall (status status404) + refs <- lift $ gitShowRefs lww + lift $ html =<< renderTextT (repoRefs lww refs) + + get "/repo/:lww/tree/:hash" do + lwws' <- captureParam @String "lww" <&> fromStringMay @(LWWRefKey HBS2Basic) + hash' <- captureParam @String "hash" <&> fromStringMay @GitHash + back <- queryParamMaybe @String "back" <&> ((fromStringMay @GitHash) =<<) + + flip runContT pure do + lww <- lwws' & orFall (status status404) + hash <- hash' & orFall (status status404) + tree <- lift $ gitShowTree lww hash + lift $ html =<< renderTextT (repoTree lww hash tree back) + + +repoDataPath :: (DashBoardPerks m, MonadReader DashBoardEnv m) => LWWRefKey 'HBS2Basic -> m FilePath +repoDataPath lw = asks _dataDir <&> ( (show $ pretty lw)) >>= canonicalizePath + + +gitShowTree :: (DashBoardPerks m, MonadReader DashBoardEnv m) + => LWWRefKey 'HBS2Basic + -> GitHash + -> m [(GitObjectType, GitHash, Text)] +gitShowTree what hash = do + path <- repoDataPath what + let cmd = [qc|git --git-dir {path} ls-tree {show $ pretty hash}|] + + -- FIXME: extract-method + gitRunCommand cmd + >>= orThrowUser ("can't read git repo" <+> pretty path) + <&> LBS8.lines + <&> fmap LBS8.words + <&> mapMaybe \case + [_,tp,h,name] -> do + (,,) <$> fromStringMay (LBS8.unpack tp) + <*> fromStringMay (LBS8.unpack h) + <*> pure (fromString (LBS8.unpack name)) + + _ -> Nothing + + +gitShowRefs :: (DashBoardPerks m, MonadReader DashBoardEnv m) => LWWRefKey 'HBS2Basic -> m [(GitRef, GitHash)] +gitShowRefs what = do + path <- repoDataPath what + let cmd = [qc|git --git-dir {path} show-ref|] + + -- FIXME: extract-method + gitRunCommand cmd + >>= orThrowUser ("can't read git repo" <+> pretty path) + <&> LBS8.lines + <&> fmap LBS8.words + <&> mapMaybe \case + [val,name] -> (GitRef (LBS8.toStrict name),) <$> fromStringMay @GitHash (LBS8.unpack val) + _ -> Nothing + runScotty :: DashBoardPerks m => DashBoardM m () runScotty = do diff --git a/hbs2-git/hbs2-git-dashboard/src/HBS2/Git/DashBoard/Prelude.hs b/hbs2-git/hbs2-git-dashboard/src/HBS2/Git/DashBoard/Prelude.hs index 739aecaa..f845d206 100644 --- a/hbs2-git/hbs2-git-dashboard/src/HBS2/Git/DashBoard/Prelude.hs +++ b/hbs2-git/hbs2-git-dashboard/src/HBS2/Git/DashBoard/Prelude.hs @@ -17,6 +17,7 @@ module HBS2.Git.DashBoard.Prelude , module Lens.Micro.Platform , module UnliftIO , module Codec.Serialise + , GitRef(..), GitHash(..), GitObjectType(..) , qc, q ) where @@ -41,6 +42,7 @@ import HBS2.Peer.Proto.LWWRef as API import HBS2.Peer.Proto.RefChan.Types as API import HBS2.Peer.Proto.RefChan.RefChanUpdate as API +import HBS2.Git.Local import Data.Config.Suckless as Config diff --git a/hbs2-git/hbs2-git-dashboard/src/HBS2/Git/Web/Html/Root.hs b/hbs2-git/hbs2-git-dashboard/src/HBS2/Git/Web/Html/Root.hs index e53ffb65..227febf2 100644 --- a/hbs2-git/hbs2-git-dashboard/src/HBS2/Git/Web/Html/Root.hs +++ b/hbs2-git/hbs2-git-dashboard/src/HBS2/Git/Web/Html/Root.hs @@ -21,6 +21,10 @@ import Data.Word import Data.Either import Safe +import Data.ByteString.Char8 qualified as BS8 +import Network.URI (uriToString, parseURI, URI(..), URIAuth(..)) +import Network.HTTP.Types.URI (renderQuery) + import Streaming.Prelude qualified as S rootPath :: [String] -> [String] @@ -161,11 +165,11 @@ repoMenuItem :: Term [Attribute] (t1 -> t2) => [Attribute] -> t1 -> t2 repoMenuItem misc name = li_ ([class_ "tab"] <> misc <> [tabClick]) name -repoPage :: (DashBoardPerks m, MonadReader DashBoardEnv m) => RepoListItem -> HtmlT m () -repoPage RepoListItem{..} = rootPage do +parsedManifest :: (DashBoardPerks m, MonadReader DashBoardEnv m) => RepoListItem -> m ([Syntax C], Text) +parsedManifest RepoListItem{..} = do sto <- asks _sto - mhead <- lift $ readRepoHeadFromTx sto (coerce rlRepoTx) + mhead <- readRepoHeadFromTx sto (coerce rlRepoTx) let rawManifest = (_repoManifest . snd =<< mhead) & fromMaybe (coerce rlRepoBrief) @@ -185,6 +189,90 @@ repoPage RepoListItem{..} = rootPage do let manifest = mconcat $ rights w + pure (meta, manifest) + + +repoManifest :: (DashBoardPerks m, MonadReader DashBoardEnv m) => RepoListItem -> HtmlT m () +repoManifest it@RepoListItem{..} = do + (_, manifest) <- lift $ parsedManifest it + toHtmlRaw (renderMarkdown' manifest) + +repoRefs :: (DashBoardPerks m, MonadReader DashBoardEnv m) + => LWWRefKey 'HBS2Basic + -> [(GitRef, GitHash)] + -> HtmlT m () +repoRefs lww refs = do + table_ [] do + for_ refs $ \(r,h) -> do + let link = path [ "repo", show $ pretty lww, "tree", show (pretty h) ] + tr_ mempty do + td_ mempty (toHtml $ show $ pretty r) + td_ [class_ "mono"] $ a_ [ href_ "#" + , hxGet_ link + , hxTarget_ "#repo-tab-data" + ] (toHtml $ show $ pretty h) + + + +repoTree :: (DashBoardPerks m, MonadReader DashBoardEnv m) + => LWWRefKey 'HBS2Basic + -> GitHash -- ^ this + -> [(GitObjectType, GitHash, Text)] + -> Maybe GitHash -- ^ back + -> HtmlT m () + +repoTree lww root tree back' = do + + table_ [] do + tr_ mempty do + + for_ back' $ \root -> do + let rootLink = path [ "repo", show $ pretty lww, "tree", show (pretty root) ] + td_ $ img_ [src_ "/icon/tree-up.svg"] + td_ ".." + td_ do a_ [ href_ "#" + , hxGet_ rootLink + , hxTarget_ "#repo-tab-data" + ] (toHtml $ show $ pretty root) + + for_ tree $ \(tp,h,name) -> do + + let back = show $ pretty root + let backPart = [qc|?back={back}|] + + let link = path [ "repo", show $ pretty lww, "tree", show (pretty h) ] + tr_ mempty do + td_ $ case tp of + Blob -> img_ [src_ "/icon/blob.svg"] + Tree -> img_ [src_ "/icon/tree.svg"] + _ -> mempty + + td_ mempty (toHtml $ show $ pretty name) + td_ [class_ "mono"] do + case tp of + Blob -> do + span_ do + toHtml $ show $ pretty h + + Tree -> do + a_ [ href_ "#" + , hxGet_ (link <> backPart) + , hxTarget_ "#repo-tab-data" + ] (toHtml $ show $ pretty h) + + _ -> mempty + + +repoPage :: (DashBoardPerks m, MonadReader DashBoardEnv m) => RepoListItem -> HtmlT m () +repoPage it@RepoListItem{..} = rootPage do + + let repo = show $ pretty rlRepoLww + + sto <- asks _sto + mhead <- lift $ readRepoHeadFromTx sto (coerce rlRepoTx) + + (meta, manifest) <- lift $ parsedManifest it + debug $ yellow "HEAD" <+> pretty rlRepoTx debug $ yellow "META" <+> pretty meta @@ -223,10 +311,18 @@ repoPage RepoListItem{..} = rootPage do nav_ [ role_ "tab-control" ] do repoMenu do repoMenuItem mempty $ a_ [href_ "/"] "root" - repoMenuItem0 mempty "manifest" + + repoMenuItem0 [ hxGet_ (path ["repo", repo, "manifest"]) + , hxTarget_ "#repo-tab-data" + ] "manifest" + + repoMenuItem [ hxGet_ (path ["repo", repo, "refs"]) + , hxTarget_ "#repo-tab-data" + ] "browse" section_ [id_ "repo-data"] do h1_ (toHtml $ rlRepoName) + div_ [id_ "repo-tab-data"] do toHtmlRaw (renderMarkdown' manifest) diff --git a/hbs2-git/hbs2-git.cabal b/hbs2-git/hbs2-git.cabal index 64a2ad0c..d5495f92 100644 --- a/hbs2-git/hbs2-git.cabal +++ b/hbs2-git/hbs2-git.cabal @@ -163,6 +163,7 @@ executable hbs2-git-dashboard , optparse-applicative , http-types , file-embed + , network-uri , wai , wai-extra , wai-middleware-static