mirror of https://github.com/voidlizard/hbs2
wip, commits infinite scroll
This commit is contained in:
parent
2958b5f2ac
commit
416164c477
|
@ -326,6 +326,23 @@ td.tree-locator span {
|
||||||
margin-right: .5rem;
|
margin-right: .5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tr.commit-brief-title td,th {
|
||||||
|
border-bottom: none;
|
||||||
|
align: top;
|
||||||
|
}
|
||||||
|
|
||||||
|
tr.commit-brief-details td,th {
|
||||||
|
border-top: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
td.commit-brief-title {
|
||||||
|
background-color:
|
||||||
|
}
|
||||||
|
|
||||||
|
td.commit-brief-last, th.commit-brief-last {
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
pre > code.sourceCode { white-space: pre; position: relative; }
|
pre > code.sourceCode { white-space: pre; position: relative; }
|
||||||
pre > code.sourceCode > span { line-height: 1.25; }
|
pre > code.sourceCode > span { line-height: 1.25; }
|
||||||
pre > code.sourceCode > span:empty { height: 1.2em; }
|
pre > code.sourceCode > span:empty { height: 1.2em; }
|
||||||
|
@ -390,3 +407,5 @@ code span.vs { color: #4e9a06; } /* VerbatimString */
|
||||||
code span.wa { color: #8f5902; font-weight: bold; font-style: italic; } /* Warning */
|
code span.wa { color: #8f5902; font-weight: bold; font-style: italic; } /* Warning */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,7 @@ import HBS2.Git.Local.CLI
|
||||||
import HBS2.Git.Web.Assets
|
import HBS2.Git.Web.Assets
|
||||||
import HBS2.Git.DashBoard.State
|
import HBS2.Git.DashBoard.State
|
||||||
import HBS2.Git.DashBoard.State.Index
|
import HBS2.Git.DashBoard.State.Index
|
||||||
|
import HBS2.Git.DashBoard.State.Commits
|
||||||
import HBS2.Git.DashBoard.Types
|
import HBS2.Git.DashBoard.Types
|
||||||
import HBS2.Git.Web.Html.Root
|
import HBS2.Git.Web.Html.Root
|
||||||
|
|
||||||
|
@ -250,14 +251,34 @@ runDashboardWeb wo = do
|
||||||
co <- co' & orFall (status status404)
|
co <- co' & orFall (status status404)
|
||||||
blobHash <- blob' & orFall (status status404)
|
blobHash <- blob' & orFall (status status404)
|
||||||
|
|
||||||
back <- lift $ selectParentTree (TreeCommit co) (TreeTree hash)
|
|
||||||
|
|
||||||
blobInfo <- lift (selectBlobInfo (BlobHash blobHash))
|
blobInfo <- lift (selectBlobInfo (BlobHash blobHash))
|
||||||
>>= orFall (status status404)
|
>>= orFall (status status404)
|
||||||
|
|
||||||
lift $ html =<< renderTextT (repoBlob lww (TreeCommit co) (TreeTree hash) blobInfo)
|
lift $ html =<< renderTextT (repoBlob lww (TreeCommit co) (TreeTree hash) blobInfo)
|
||||||
|
|
||||||
|
|
||||||
|
get "/repo/:lww/commits" do
|
||||||
|
lwws' <- captureParam @String "lww" <&> fromStringMay @(LWWRefKey HBS2Basic)
|
||||||
|
|
||||||
|
let pred = mempty & set commitPredOffset 0
|
||||||
|
& set commitPredLimit 100
|
||||||
|
|
||||||
|
flip runContT pure do
|
||||||
|
lww <- lwws' & orFall (status status404)
|
||||||
|
lift $ html =<< renderTextT (repoCommits lww (Right pred))
|
||||||
|
|
||||||
|
get "/repo/:lww/commits/:off/:lim" do
|
||||||
|
lwws' <- captureParam @String "lww" <&> fromStringMay @(LWWRefKey HBS2Basic)
|
||||||
|
off <- captureParam @Int "off"
|
||||||
|
lim <- captureParam @Int "lim"
|
||||||
|
|
||||||
|
let pred = mempty & set commitPredOffset off
|
||||||
|
& set commitPredLimit lim
|
||||||
|
|
||||||
|
flip runContT pure do
|
||||||
|
lww <- lwws' & orFall (status status404)
|
||||||
|
lift $ html =<< renderTextT (repoCommits lww (Left pred))
|
||||||
|
|
||||||
|
|
||||||
gitShowTree :: (DashBoardPerks m, MonadReader DashBoardEnv m)
|
gitShowTree :: (DashBoardPerks m, MonadReader DashBoardEnv m)
|
||||||
=> LWWRefKey 'HBS2Basic
|
=> LWWRefKey 'HBS2Basic
|
||||||
|
@ -355,7 +376,7 @@ updateIndexPeriodially = do
|
||||||
lww <- lift (selectLwwByRefLog (RepoRefLog r))
|
lww <- lift (selectLwwByRefLog (RepoRefLog r))
|
||||||
>>= maybe (exit ()) pure
|
>>= maybe (exit ()) pure
|
||||||
|
|
||||||
dir <- asks (view dataDir) <&> (</> (show $ pretty lww))
|
dir <- lift $ repoDataPath (coerce lww)
|
||||||
|
|
||||||
here <- doesDirectoryExist dir
|
here <- doesDirectoryExist dir
|
||||||
|
|
||||||
|
|
|
@ -23,6 +23,7 @@ import DBPipe.SQLite hiding (insert)
|
||||||
import DBPipe.SQLite qualified as S
|
import DBPipe.SQLite qualified as S
|
||||||
import DBPipe.SQLite.Generic as G
|
import DBPipe.SQLite.Generic as G
|
||||||
|
|
||||||
|
|
||||||
import Data.ByteString.Lazy.Char8 qualified as LBS8
|
import Data.ByteString.Lazy.Char8 qualified as LBS8
|
||||||
import Data.ByteString.Lazy (ByteString)
|
import Data.ByteString.Lazy (ByteString)
|
||||||
import Lucid.Base
|
import Lucid.Base
|
||||||
|
@ -704,3 +705,5 @@ buildCommitTreeIndex dir = do
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,116 @@
|
||||||
|
{-# LANGUAGE TemplateHaskell #-}
|
||||||
|
module HBS2.Git.DashBoard.State.Commits where
|
||||||
|
|
||||||
|
import HBS2.Git.DashBoard.Prelude
|
||||||
|
import HBS2.Git.DashBoard.Types
|
||||||
|
|
||||||
|
import HBS2.Git.Local
|
||||||
|
import HBS2.Git.Local.CLI
|
||||||
|
|
||||||
|
import Data.ByteString.Lazy.Char8 qualified as LBS8
|
||||||
|
import Data.Text.Encoding qualified as Text
|
||||||
|
import Data.Text qualified as Text
|
||||||
|
import Data.Time (UTCTime,LocalTime)
|
||||||
|
import Data.Time.Clock.POSIX (posixSecondsToUTCTime)
|
||||||
|
import Data.Either
|
||||||
|
|
||||||
|
import Streaming.Prelude qualified as S
|
||||||
|
|
||||||
|
{- HLINT ignore "Functor law" -}
|
||||||
|
|
||||||
|
data CommitListStyle = CommitListBrief
|
||||||
|
|
||||||
|
data SelectCommitsPred =
|
||||||
|
SelectCommitsPred
|
||||||
|
{ _commitListStyle :: CommitListStyle
|
||||||
|
, _commitPredOffset :: Int
|
||||||
|
, _commitPredLimit :: Int
|
||||||
|
}
|
||||||
|
|
||||||
|
makeLenses ''SelectCommitsPred
|
||||||
|
|
||||||
|
instance Semigroup SelectCommitsPred where
|
||||||
|
(<>) _ _ = mempty
|
||||||
|
|
||||||
|
instance Monoid SelectCommitsPred where
|
||||||
|
mempty = SelectCommitsPred CommitListBrief 0 100
|
||||||
|
|
||||||
|
briefCommits :: SelectCommitsPred
|
||||||
|
briefCommits = mempty
|
||||||
|
|
||||||
|
newtype Author = Author Text
|
||||||
|
deriving stock (Generic,Data)
|
||||||
|
deriving newtype (Show)
|
||||||
|
|
||||||
|
|
||||||
|
newtype CommitListItemHash = CommitListItemHash GitHash
|
||||||
|
deriving stock (Generic,Data)
|
||||||
|
deriving newtype (Show,Pretty)
|
||||||
|
|
||||||
|
newtype CommitListItemTime = CommitListItemTime Integer
|
||||||
|
deriving stock (Generic,Data)
|
||||||
|
deriving newtype (Show)
|
||||||
|
|
||||||
|
newtype CommitListItemTitle = CommitListItemTitle Text
|
||||||
|
deriving stock (Generic,Data)
|
||||||
|
deriving newtype (Show)
|
||||||
|
|
||||||
|
newtype CommitListItemAuthor = CommitListItemAuthor Author
|
||||||
|
deriving stock (Generic,Data)
|
||||||
|
deriving newtype (Show)
|
||||||
|
|
||||||
|
data CommitListItem =
|
||||||
|
CommitListItemBrief
|
||||||
|
{ commitListHash :: CommitListItemHash
|
||||||
|
, commitListTime :: CommitListItemTime
|
||||||
|
, commitListTitle :: CommitListItemTitle
|
||||||
|
, commitListAuthor :: CommitListItemAuthor
|
||||||
|
}
|
||||||
|
deriving stock (Generic,Data)
|
||||||
|
|
||||||
|
selectCommits :: (DashBoardPerks m, MonadReader DashBoardEnv m)
|
||||||
|
=> LWWRefKey 'HBS2Basic
|
||||||
|
-> SelectCommitsPred
|
||||||
|
-> m [CommitListItem]
|
||||||
|
|
||||||
|
selectCommits lww SelectCommitsPred{..} = do
|
||||||
|
let lim = _commitPredLimit
|
||||||
|
let off = _commitPredOffset
|
||||||
|
let delim = "|||" :: Text
|
||||||
|
dir <- repoDataPath lww
|
||||||
|
|
||||||
|
let cmd = case _commitListStyle of
|
||||||
|
CommitListBrief -> do
|
||||||
|
let fmt = [qc|--pretty=format:"%H{delim}%at{delim}%an{delim}%s"|] :: String
|
||||||
|
[qc|git --git-dir={dir} log --all --max-count {lim} --skip {off} {fmt}|]
|
||||||
|
|
||||||
|
debug $ red "selectCommits" <+> pretty cmd
|
||||||
|
|
||||||
|
ls <- gitRunCommand cmd
|
||||||
|
<&> fromRight mempty
|
||||||
|
<&> LBS8.lines
|
||||||
|
<&> fmap (Text.decodeUtf8 . LBS8.toStrict)
|
||||||
|
|
||||||
|
S.toList_ do
|
||||||
|
for_ ls $ \l -> do
|
||||||
|
case Text.splitOn "|||" l of
|
||||||
|
z@[cohash,ts,au,msg] -> do
|
||||||
|
|
||||||
|
let utc = readMay @Integer (Text.unpack ts)
|
||||||
|
<&> CommitListItemTime
|
||||||
|
|
||||||
|
let hash = fromStringMay @GitHash (Text.unpack cohash)
|
||||||
|
<&> CommitListItemHash
|
||||||
|
|
||||||
|
let co = CommitListItemBrief
|
||||||
|
<$> hash
|
||||||
|
<*> utc
|
||||||
|
<*> pure (CommitListItemTitle msg)
|
||||||
|
<*> pure (CommitListItemAuthor (Author au))
|
||||||
|
|
||||||
|
maybe1 co none S.yield
|
||||||
|
|
||||||
|
_ -> none
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,7 @@ module HBS2.Git.Web.Html.Root where
|
||||||
import HBS2.Git.DashBoard.Prelude
|
import HBS2.Git.DashBoard.Prelude
|
||||||
import HBS2.Git.DashBoard.Types
|
import HBS2.Git.DashBoard.Types
|
||||||
import HBS2.Git.DashBoard.State
|
import HBS2.Git.DashBoard.State
|
||||||
|
import HBS2.Git.DashBoard.State.Commits
|
||||||
|
|
||||||
import HBS2.Git.Data.Tx.Git
|
import HBS2.Git.Data.Tx.Git
|
||||||
import HBS2.Git.Data.RepoHead
|
import HBS2.Git.Data.RepoHead
|
||||||
|
@ -44,6 +45,9 @@ myCss = do
|
||||||
hyper_ :: Text -> Attribute
|
hyper_ :: Text -> Attribute
|
||||||
hyper_ = makeAttribute "_"
|
hyper_ = makeAttribute "_"
|
||||||
|
|
||||||
|
-- makeGetQuery :: String -> Attribute
|
||||||
|
-- makeGetQuery _ = termRaw "jop"
|
||||||
|
|
||||||
onClickCopy :: Text -> Attribute
|
onClickCopy :: Text -> Attribute
|
||||||
onClickCopy s =
|
onClickCopy s =
|
||||||
hyper_ [qc|on click writeText('{s}') into the navigator's clipboard add .clicked to me wait 2s remove .clicked from me|]
|
hyper_ [qc|on click writeText('{s}') into the navigator's clipboard add .clicked to me wait 2s remove .clicked from me|]
|
||||||
|
@ -70,6 +74,14 @@ instance ToHtml RepoBrief where
|
||||||
|
|
||||||
data WithTime a = WithTime Integer a
|
data WithTime a = WithTime Integer a
|
||||||
|
|
||||||
|
agePure :: forall a b . (Integral a,Integral b) => a -> b -> Text
|
||||||
|
agePure t0 t = do
|
||||||
|
let sec = fromIntegral @_ @Word64 t - fromIntegral t0
|
||||||
|
fromString $ show $
|
||||||
|
if | sec > 86400 -> pretty (sec `div` 86400) <+> "days ago"
|
||||||
|
| sec > 3600 -> pretty (sec `div` 3600) <+> "hours ago"
|
||||||
|
| otherwise -> pretty (sec `div` 60) <+> "minutes ago"
|
||||||
|
|
||||||
instance ToHtml (WithTime RepoListItem) where
|
instance ToHtml (WithTime RepoListItem) where
|
||||||
toHtmlRaw = pure mempty
|
toHtmlRaw = pure mempty
|
||||||
|
|
||||||
|
@ -82,12 +94,7 @@ instance ToHtml (WithTime RepoListItem) where
|
||||||
let url = path ["repo", Text.unpack $ view rlRepoLwwAsText it]
|
let url = path ["repo", Text.unpack $ view rlRepoLwwAsText it]
|
||||||
let t = fromIntegral $ coerce @_ @Word64 rlRepoSeq
|
let t = fromIntegral $ coerce @_ @Word64 rlRepoSeq
|
||||||
|
|
||||||
let updated = "" <+> d
|
let updated = agePure t now
|
||||||
where
|
|
||||||
sec = now - t
|
|
||||||
d | sec > 86400 = pretty (sec `div` 86400) <+> "days ago"
|
|
||||||
| sec > 3600 = pretty (sec `div` 3600) <+> "hours ago"
|
|
||||||
| otherwise = pretty (sec `div` 60) <+> "minutes ago"
|
|
||||||
|
|
||||||
div_ [class_ "repo-list-item"] do
|
div_ [class_ "repo-list-item"] do
|
||||||
div_ [class_ "repo-info", style_ "flex: 1; flex-basis: 70%;"] do
|
div_ [class_ "repo-info", style_ "flex: 1; flex-basis: 70%;"] do
|
||||||
|
@ -99,7 +106,7 @@ instance ToHtml (WithTime RepoListItem) where
|
||||||
|
|
||||||
div_ [ ] do
|
div_ [ ] do
|
||||||
div_ [ class_ "attr" ] do
|
div_ [ class_ "attr" ] do
|
||||||
div_ [ class_ "attrname"] (toHtml $ show updated)
|
div_ [ class_ "attrname"] (toHtml updated)
|
||||||
|
|
||||||
when locked do
|
when locked do
|
||||||
div_ [ class_ "attr" ] do
|
div_ [ class_ "attr" ] do
|
||||||
|
@ -365,6 +372,55 @@ repoTree lww co root tree back' = do
|
||||||
|
|
||||||
{- HLINT ignore "Functor law" -}
|
{- HLINT ignore "Functor law" -}
|
||||||
|
|
||||||
|
repoCommits :: (DashBoardPerks m, MonadReader DashBoardEnv m)
|
||||||
|
=> LWWRefKey 'HBS2Basic
|
||||||
|
-> Either SelectCommitsPred SelectCommitsPred
|
||||||
|
-> HtmlT m ()
|
||||||
|
|
||||||
|
repoCommits lww predicate' = do
|
||||||
|
now <- getEpoch
|
||||||
|
let repo = show $ pretty lww
|
||||||
|
|
||||||
|
let predicate = either id id predicate'
|
||||||
|
|
||||||
|
co <- lift $ selectCommits lww predicate
|
||||||
|
|
||||||
|
let off = view commitPredOffset predicate
|
||||||
|
let lim = view commitPredLimit predicate
|
||||||
|
let noff = off + lim
|
||||||
|
|
||||||
|
let query = path ["repo", repo, "commits", show noff, show lim]
|
||||||
|
|
||||||
|
let rows = do
|
||||||
|
for_ co $ \case
|
||||||
|
CommitListItemBrief{..} -> do
|
||||||
|
tr_ [class_ "commit-brief-title"] do
|
||||||
|
td_ $ img_ [src_ "/icon/git-commit.svg"]
|
||||||
|
td_ $ small_ $ toHtml (agePure (coerce @_ @Integer commitListTime) now)
|
||||||
|
td_ [class_ "mono", width_ "20rem"] do
|
||||||
|
let hash = show $ pretty $ coerce @_ @GitHash commitListHash
|
||||||
|
a_ [href_ ""] (toHtml hash)
|
||||||
|
td_ do
|
||||||
|
small_ $ toHtml $ coerce @_ @Text commitListAuthor
|
||||||
|
tr_ [class_ "commit-brief-details"] do
|
||||||
|
td_ [colspan_ "1"] mempty
|
||||||
|
td_ [colspan_ "3", class_ "commit-brief-title"] do
|
||||||
|
small_ $ toHtml $ coerce @_ @Text commitListTitle
|
||||||
|
|
||||||
|
unless (List.null co) do
|
||||||
|
tr_ [ class_ "commit-brief-last"
|
||||||
|
, hxGet_ query
|
||||||
|
, hxTrigger_ "revealed"
|
||||||
|
, hxSwap_ "afterend"
|
||||||
|
] do
|
||||||
|
td_ [colspan_ "4"] do
|
||||||
|
mempty
|
||||||
|
|
||||||
|
if isRight predicate' then do
|
||||||
|
table_ rows
|
||||||
|
else do
|
||||||
|
rows
|
||||||
|
|
||||||
repoBlob :: (DashBoardPerks m, MonadReader DashBoardEnv m)
|
repoBlob :: (DashBoardPerks m, MonadReader DashBoardEnv m)
|
||||||
=> LWWRefKey 'HBS2Basic
|
=> LWWRefKey 'HBS2Basic
|
||||||
-> TreeCommit
|
-> TreeCommit
|
||||||
|
@ -499,7 +555,8 @@ repoPage it@RepoListItem{..} = rootPage do
|
||||||
, hxTarget_ "#repo-tab-data"
|
, hxTarget_ "#repo-tab-data"
|
||||||
] "manifest"
|
] "manifest"
|
||||||
|
|
||||||
repoMenuItem [
|
repoMenuItem [ hxGet_ (path ["repo", repo, "commits"])
|
||||||
|
, hxTarget_ "#repo-tab-data"
|
||||||
] "commits"
|
] "commits"
|
||||||
|
|
||||||
repoMenuItem (showRefsHtmxAttribs repo) "tree"
|
repoMenuItem (showRefsHtmxAttribs repo) "tree"
|
||||||
|
|
|
@ -147,6 +147,7 @@ executable hbs2-git-dashboard
|
||||||
HBS2.Git.DashBoard.Prelude
|
HBS2.Git.DashBoard.Prelude
|
||||||
HBS2.Git.DashBoard.Types
|
HBS2.Git.DashBoard.Types
|
||||||
HBS2.Git.DashBoard.State
|
HBS2.Git.DashBoard.State
|
||||||
|
HBS2.Git.DashBoard.State.Commits
|
||||||
HBS2.Git.DashBoard.State.Index
|
HBS2.Git.DashBoard.State.Index
|
||||||
HBS2.Git.DashBoard.State.Index.Channels
|
HBS2.Git.DashBoard.State.Index.Channels
|
||||||
HBS2.Git.DashBoard.State.Index.Peer
|
HBS2.Git.DashBoard.State.Index.Peer
|
||||||
|
|
Loading…
Reference in New Issue