UI: Project: Component list HTML version

This commit is contained in:
Pere Lev 2023-11-02 12:35:35 +02:00
parent 5d52db9377
commit acc1d13c63
No known key found for this signature in database
GPG key ID: 5252C5C863E5E57D
4 changed files with 221 additions and 35 deletions

View file

@ -216,38 +216,75 @@ postProjectNewR = do
getProjectStampR :: KeyHashid Project -> KeyHashid SigKey -> Handler TypedContent getProjectStampR :: KeyHashid Project -> KeyHashid SigKey -> Handler TypedContent
getProjectStampR = servePerActorKey projectActor LocalActorProject getProjectStampR = servePerActorKey projectActor LocalActorProject
getProjectCollabsR :: KeyHashid Project -> Handler Html getProjectCollabsR :: KeyHashid Project -> Handler TypedContent
getProjectCollabsR projectHash = do getProjectCollabsR projectHash = do
projectID <- decodeKeyHashid404 projectHash projectID <- decodeKeyHashid404 projectHash
(project, actor, collabs, invites, joins) <- runDB $ do collabs <- runDB $ do
project <- get404 projectID _project <- get404 projectID
actor <- getJust $ projectActor project grants <- getTopicGrants CollabTopicProjectCollab CollabTopicProjectProject projectID
collabs <- do for grants $ \ (role, actor, _ct, time) ->
grants <- (role,time,) <$> bitraverse pure (getRemoteActorURI <=< getJust) actor
getTopicGrants CollabTopicProjectCollab CollabTopicProjectProject projectID h <- asksSite siteInstanceHost
for grants $ \ (role, actor, ct, time) -> encodeRouteLocal <- getEncodeRouteLocal
(,role,ct,time) <$> getPersonWidgetInfo actor encodeRouteHome <- getEncodeRouteHome
invites <- do hashPerson <- getEncodeKeyHashid
invites' <- let makeItem (role, time, i) = AP.Relationship
getTopicInvites CollabTopicProjectCollab CollabTopicProjectProject projectID { AP.relationshipId = Nothing
for invites' $ \ (inviter, recip, time, role) -> (,,,) , AP.relationshipExtraTypes = []
<$> (getPersonWidgetInfo =<< bitraverse grabPerson pure inviter) , AP.relationshipSubject = encodeRouteHome $ ProjectR projectHash
<*> getPersonWidgetInfo recip , AP.relationshipProperty = Left AP.RelHasCollab
<*> pure time , AP.relationshipObject =
<*> pure role case i of
joins <- do Left personID -> encodeRouteHome $ PersonR $ hashPerson personID
joins' <- Right u -> u
getTopicJoins CollabTopicProjectCollab CollabTopicProjectProject projectID , AP.relationshipAttributedTo = encodeRouteLocal $ ProjectR projectHash
for joins' $ \ (recip, time, role) -> , AP.relationshipPublished = Just time
(,time,role) <$> getPersonWidgetInfo recip , AP.relationshipUpdated = Nothing
return (project, actor, collabs, invites, joins) , AP.relationshipInstrument = Just role
defaultLayout $(widgetFile "project/collab/list") }
collabsAP = AP.Collection
{ AP.collectionId = encodeRouteLocal $ ProjectCollabsR projectHash
, AP.collectionType = CollectionTypeUnordered
, AP.collectionTotalItems = Just $ length collabs
, AP.collectionCurrent = Nothing
, AP.collectionFirst = Nothing
, AP.collectionLast = Nothing
, AP.collectionItems = map (Doc h . makeItem) collabs
, AP.collectionContext =
Just $ encodeRouteLocal $ ProjectR projectHash
}
provideHtmlAndAP collabsAP $ getHtml projectID
where where
grabPerson actorID = do getHtml projectID = do
actorByKey <- getLocalActor actorID (project, actor, collabs, invites, joins) <- handlerToWidget $ runDB $ do
case actorByKey of project <- get404 projectID
LocalActorPerson personID -> return personID actor <- getJust $ projectActor project
_ -> error "Surprise, local inviter actor isn't a Person" collabs <- do
grants <-
getTopicGrants CollabTopicProjectCollab CollabTopicProjectProject projectID
for grants $ \ (role, actor, ct, time) ->
(,role,ct,time) <$> getPersonWidgetInfo actor
invites <- do
invites' <-
getTopicInvites CollabTopicProjectCollab CollabTopicProjectProject projectID
for invites' $ \ (inviter, recip, time, role) -> (,,,)
<$> (getPersonWidgetInfo =<< bitraverse grabPerson pure inviter)
<*> getPersonWidgetInfo recip
<*> pure time
<*> pure role
joins <- do
joins' <-
getTopicJoins CollabTopicProjectCollab CollabTopicProjectProject projectID
for joins' $ \ (recip, time, role) ->
(,time,role) <$> getPersonWidgetInfo recip
return (project, actor, collabs, invites, joins)
$(widgetFile "project/collab/list")
where
grabPerson actorID = do
actorByKey <- getLocalActor actorID
case actorByKey of
LocalActorPerson personID -> return personID
_ -> error "Surprise, local inviter actor isn't a Person"
getProjectInviteR :: KeyHashid Project -> Handler Html getProjectInviteR :: KeyHashid Project -> Handler Html
getProjectInviteR projectHash = do getProjectInviteR projectHash = do
@ -352,7 +389,7 @@ getProjectComponentsR projectHash = do
encodeRouteHome <- getEncodeRouteHome encodeRouteHome <- getEncodeRouteHome
hashActor <- getHashLocalActor hashActor <- getHashLocalActor
let componentsAP = Collection let componentsAP = Collection
{ collectionId = encodeRouteLocal here { collectionId = encodeRouteLocal $ ProjectComponentsR projectHash
, collectionType = CollectionTypeUnordered , collectionType = CollectionTypeUnordered
, collectionTotalItems = Just $ length components , collectionTotalItems = Just $ length components
, collectionCurrent = Nothing , collectionCurrent = Nothing
@ -371,12 +408,10 @@ getProjectComponentsR projectHash = do
, collectionContext = , collectionContext =
Just $ encodeRouteLocal $ ProjectR projectHash Just $ encodeRouteLocal $ ProjectR projectHash
} }
provideHtmlAndAP componentsAP $ redirectToPrettyJSON here provideHtmlAndAP componentsAP $ getHtml projectID
where where
here = ProjectComponentsR projectHash
getRepos projectID = getRepos projectID =
fmap (map E.unValue) $ fmap (map E.unValue) $
E.select $ E.from $ \ (comp `E.InnerJoin` enable `E.InnerJoin` local `E.InnerJoin` repo) -> do E.select $ E.from $ \ (comp `E.InnerJoin` enable `E.InnerJoin` local `E.InnerJoin` repo) -> do
@ -415,6 +450,68 @@ getProjectComponentsR projectHash = do
E.where_ $ comp E.^. ComponentProject E.==. E.val projectID E.where_ $ comp E.^. ComponentProject E.==. E.val projectID
return (i E.^. InstanceHost, ro E.^. RemoteObjectIdent) return (i E.^. InstanceHost, ro E.^. RemoteObjectIdent)
getHtml projectID = do
(project, actor, comps, drafts) <- handlerToWidget $ runDB $ do
project <- get404 projectID
actor <- getJust $ projectActor project
cs <-
E.select $ E.from $ \ (comp `E.InnerJoin` enable `E.InnerJoin` grant) -> do
E.on $ enable E.^. ComponentEnableGrant E.==. grant E.^. OutboxItemId
E.on $ comp E.^. ComponentId E.==. enable E.^. ComponentEnableComponent
E.where_ $ comp E.^. ComponentProject E.==. E.val projectID
return (comp, grant)
cs' <- for cs $ \ (Entity cid c, Entity _ i) -> do
byKeyOrRaid <- bimap snd snd <$> getComponentIdent cid
identView <-
bitraverse
(\ byKey -> do
actorID <-
case byKey of
ComponentRepo k -> repoActor <$> getJust k
ComponentDeck k -> deckActor <$> getJust k
ComponentLoom k -> loomActor <$> getJust k
actor <- getJust actorID
return (byKey, actor)
)
(\ remoteActorID -> do
remoteActor <- getJust remoteActorID
remoteObject <- getJust $ remoteActorIdent remoteActor
inztance <- getJust $ remoteObjectInstance remoteObject
return (inztance, remoteObject, remoteActor)
)
byKeyOrRaid
return (identView, componentRole c, outboxItemPublished i)
ds <-
E.select $ E.from $ \ (comp `E.LeftOuterJoin` enable) -> do
E.on $ E.just (comp E.^. ComponentId) E.==. enable E.?. ComponentEnableComponent
E.where_ $
comp E.^. ComponentProject E.==. E.val projectID E.&&.
E.isNothing (enable E.?. ComponentEnableId)
return comp
ds' <- for ds $ \ (Entity cid c) -> do
byKeyOrRaid <- bimap snd snd <$> getComponentIdent cid
identView <-
bitraverse
(\ byKey -> do
actorID <-
case byKey of
ComponentRepo k -> repoActor <$> getJust k
ComponentDeck k -> deckActor <$> getJust k
ComponentLoom k -> loomActor <$> getJust k
actor <- getJust actorID
return (byKey, actor)
)
(\ remoteActorID -> do
remoteActor <- getJust remoteActorID
remoteObject <- getJust $ remoteActorIdent remoteActor
inztance <- getJust $ remoteObjectInstance remoteObject
return (inztance, remoteObject, remoteActor)
)
byKeyOrRaid
return (identView, componentRole c)
return (project, actor, cs', ds')
$(widgetFile "project/components")
getProjectCollabLiveR getProjectCollabLiveR
:: KeyHashid Project -> KeyHashid CollabEnable -> Handler () :: KeyHashid Project -> KeyHashid CollabEnable -> Handler ()
getProjectCollabLiveR projectHash enableHash = do getProjectCollabLiveR projectHash enableHash = do

View file

@ -17,13 +17,17 @@ module Vervis.Widget.Tracker
( deckNavW ( deckNavW
, loomNavW , loomNavW
, projectNavW , projectNavW
, componentLinkFedW
) )
where where
import Database.Persist.Types import Database.Persist.Types
import Yesod.Core.Widget
import Network.FedURI
import Yesod.Hashids import Yesod.Hashids
import Vervis.Data.Collab
import Vervis.Foundation import Vervis.Foundation
import Vervis.Model import Vervis.Model
import Vervis.Settings import Vervis.Settings
@ -44,3 +48,38 @@ projectNavW :: Entity Project -> Actor -> Widget
projectNavW (Entity projectID project) actor = do projectNavW (Entity projectID project) actor = do
projectHash <- encodeKeyHashid projectID projectHash <- encodeKeyHashid projectID
$(widgetFile "project/widget/nav") $(widgetFile "project/widget/nav")
componentLinkW :: ComponentBy Key -> Actor -> Widget
componentLinkW (ComponentRepo k) actor = do
h <- encodeKeyHashid k
[whamlet|
<a href=@{RepoR h}>
^#{keyHashidText h} #{actorName actor}
|]
componentLinkW (ComponentDeck k) actor = do
h <- encodeKeyHashid k
[whamlet|
<a href=@{DeckR h}>
=#{keyHashidText h} #{actorName actor}
|]
componentLinkW (ComponentLoom k) actor = do
h <- encodeKeyHashid k
[whamlet|
<a href=@{LoomR h}>
+#{keyHashidText h} #{actorName actor}
|]
componentLinkFedW
:: Either (ComponentBy Key, Actor) (Instance, RemoteObject, RemoteActor)
-> Widget
componentLinkFedW (Left (c, a)) = componentLinkW c a
componentLinkFedW (Right (inztance, object, actor)) =
[whamlet|
<a href="#{renderObjURI uActor}">
$maybe name <- remoteActorName actor
#{name}
$nothing
#{renderAuthority $ instanceHost inztance}#{localUriPath $ remoteObjectIdent object}
|]
where
uActor = ObjURI (instanceHost inztance) (remoteObjectIdent object)

View file

@ -54,6 +54,8 @@ module Web.ActivityPub
-- * Content objects -- * Content objects
, Note (..) , Note (..)
, RelationshipProperty (..)
, Relationship (..)
, TicketDependency (..) , TicketDependency (..)
, PatchLocal (..) , PatchLocal (..)
, Patch (..) , Patch (..)
@ -1072,13 +1074,14 @@ instance ActivityPub Note where
<> "content" .= content <> "content" .= content
<> "mediaType" .= ("text/html" :: Text) <> "mediaType" .= ("text/html" :: Text)
data RelationshipProperty = RelDependsOn deriving Eq data RelationshipProperty = RelDependsOn | RelHasCollab deriving Eq
instance FromJSON RelationshipProperty where instance FromJSON RelationshipProperty where
parseJSON = withText "RelationshipProperty" parse parseJSON = withText "RelationshipProperty" parse
where where
parse t parse t
| t == "dependsOn" = pure RelDependsOn | t == "dependsOn" = pure RelDependsOn
| t == "hasCollaborator" = pure RelHasCollab
| otherwise = fail $ "Unrecognized relationship: " ++ T.unpack t | otherwise = fail $ "Unrecognized relationship: " ++ T.unpack t
instance ToJSON RelationshipProperty where instance ToJSON RelationshipProperty where
@ -1086,6 +1089,7 @@ instance ToJSON RelationshipProperty where
toEncoding at = toEncoding at =
toEncoding $ case at of toEncoding $ case at of
RelDependsOn -> "dependsOn" :: Text RelDependsOn -> "dependsOn" :: Text
RelHasCollab -> "hasCollaborator"
data Relationship u = Relationship data Relationship u = Relationship
{ relationshipId :: Maybe (ObjURI u) { relationshipId :: Maybe (ObjURI u)
@ -1096,6 +1100,7 @@ data Relationship u = Relationship
, relationshipAttributedTo :: LocalURI , relationshipAttributedTo :: LocalURI
, relationshipPublished :: Maybe UTCTime , relationshipPublished :: Maybe UTCTime
, relationshipUpdated :: Maybe UTCTime , relationshipUpdated :: Maybe UTCTime
, relationshipInstrument :: Maybe Role
} }
instance ActivityPub Relationship where instance ActivityPub Relationship where
@ -1117,10 +1122,11 @@ instance ActivityPub Relationship where
<*> pure attributedTo <*> pure attributedTo
<*> o .:? "published" <*> o .:? "published"
<*> o .:? "updated" <*> o .:? "updated"
<*> o .:? "instrument"
toSeries authority toSeries authority
(Relationship id_ typs subject property object attributedTo published (Relationship id_ typs subject property object attributedTo published
updated) updated role)
= "id" .=? id_ = "id" .=? id_
<> "type" .= ("Relationship" : typs) <> "type" .= ("Relationship" : typs)
<> "subject" .= subject <> "subject" .= subject
@ -1129,6 +1135,7 @@ instance ActivityPub Relationship where
<> "attributedTo" .= ObjURI authority attributedTo <> "attributedTo" .= ObjURI authority attributedTo
<> "published" .=? published <> "published" .=? published
<> "updated" .=? updated <> "updated" .=? updated
<> "instrument" .=? role
data TicketDependency u = TicketDependency data TicketDependency u = TicketDependency
{ ticketDepId :: Maybe (ObjURI u) { ticketDepId :: Maybe (ObjURI u)
@ -1171,6 +1178,7 @@ instance ActivityPub TicketDependency where
, relationshipAttributedTo = ticketDepAttributedTo td , relationshipAttributedTo = ticketDepAttributedTo td
, relationshipPublished = ticketDepPublished td , relationshipPublished = ticketDepPublished td
, relationshipUpdated = ticketDepUpdated td , relationshipUpdated = ticketDepUpdated td
, relationshipInstrument = Nothing
} }
data PatchLocal = PatchLocal data PatchLocal = PatchLocal

View file

@ -0,0 +1,42 @@
$# This file is part of Vervis.
$#
$# Written in 2016, 2019, 2022, 2023 by fr33domlover <fr33domlover@riseup.net>.
$#
$# ♡ Copying is an act of love. Please copy, reuse and share.
$#
$# The author(s) have dedicated all copyright and related and neighboring
$# rights to this software to the public domain worldwide. This software is
$# distributed without any warranty.
$#
$# You should have received a copy of the CC0 Public Domain Dedication along
$# with this software. If not, see
$# <http://creativecommons.org/publicdomain/zero/1.0/>.
^{projectNavW (Entity projectID project) actor}
<h2>Components
<table>
<tr>
<th>Role
<th>Component
<th>Since
$forall (comp, role, since) <- comps
<tr>
<td>#{show role}
<td>^{componentLinkFedW comp}
<td>#{showDate since}
$# <td>^{buttonW POST "Remove" (ProjectRemoveR projectHash ctID)}
<h2>Component requests in progress
<table>
<tr>
<th>Role
<th>Component
$forall (comp, role) <- drafts
<tr>
<td>#{show role}
<td>^{componentLinkFedW comp}
$#<a href=@{ProjectInviteR projectHash}>Invite…