Implement ticket class params

This commit is contained in:
fr33domlover 2020-01-05 14:33:10 +00:00
parent 8fc5e4b3c1
commit d01bc5bad7
10 changed files with 156 additions and 20 deletions

View file

@ -335,6 +335,12 @@ TicketParamEnum
UniqueTicketParamEnum ticket field value UniqueTicketParamEnum ticket field value
TicketParamClass
ticket TicketId
field WorkflowFieldId
UniqueTicketParamClass ticket field
Ticket Ticket
project ProjectId project ProjectId
number Int number Int

View file

@ -0,0 +1,5 @@
TicketParamClass
ticket TicketId
field WorkflowFieldId
UniqueTicketParamClass ticket field

View file

@ -1,6 +1,6 @@
{- This file is part of Vervis. {- This file is part of Vervis.
- -
- Written in 2016, 2019 by fr33domlover <fr33domlover@riseup.net>. - Written in 2016, 2019, 2020 by fr33domlover <fr33domlover@riseup.net>.
- -
- Copying is an act of love. Please copy, reuse and share. - Copying is an act of love. Please copy, reuse and share.
- -
@ -27,7 +27,8 @@ where
import Control.Applicative (liftA2, liftA3) import Control.Applicative (liftA2, liftA3)
import Control.Monad.IO.Class (liftIO) import Control.Monad.IO.Class (liftIO)
import Control.Monad.Trans.Class (lift) import Control.Monad.Trans.Class (lift)
import Data.Maybe (catMaybes, mapMaybe) import Data.Bool
import Data.Maybe
import Data.Text (Text) import Data.Text (Text)
import Data.Time.Calendar (Day (..)) import Data.Time.Calendar (Day (..))
import Data.Time.Clock (getCurrentTime, UTCTime (..)) import Data.Time.Clock (getCurrentTime, UTCTime (..))
@ -53,6 +54,7 @@ data NewTicket = NewTicket
, ntDesc :: Text , ntDesc :: Text
, ntTParams :: [(WorkflowFieldId, Text)] , ntTParams :: [(WorkflowFieldId, Text)]
, ntEParams :: [(WorkflowFieldId, WorkflowEnumCtorId)] , ntEParams :: [(WorkflowFieldId, WorkflowEnumCtorId)]
, ntCParams :: [WorkflowFieldId]
} }
fieldSettings :: Text -> Bool -> FieldSettings App fieldSettings :: Text -> Bool -> FieldSettings App
@ -92,9 +94,18 @@ efield (Entity fid f) =
then Just <$> areq sel sets Nothing then Just <$> areq sel sets Nothing
else aopt sel sets Nothing else aopt sel sets Nothing
cfield :: Entity WorkflowField -> AForm Handler (Maybe WorkflowFieldId)
cfield (Entity fid f) =
let sets = fieldSettings (workflowFieldName f) (workflowFieldRequired f)
mkval False = Nothing
mkval True = Just fid
in if workflowFieldRequired f
then mkval <$> areq checkBoxField sets Nothing
else mkval . fromMaybe False <$> aopt checkBoxField sets Nothing
newTicketForm :: WorkflowId -> Form NewTicket newTicketForm :: WorkflowId -> Form NewTicket
newTicketForm wid html = do newTicketForm wid html = do
(tfs, efs) <- lift $ runDB $ do (tfs, efs, cfs) <- lift $ runDB $ do
tfs <- selectList tfs <- selectList
[ WorkflowFieldWorkflow ==. wid [ WorkflowFieldWorkflow ==. wid
, WorkflowFieldType ==. WFTText , WorkflowFieldType ==. WFTText
@ -108,7 +119,14 @@ newTicketForm wid html = do
, WorkflowFieldFilterNew ==. True , WorkflowFieldFilterNew ==. True
] ]
[] []
return (tfs, efs) cfs <- selectList
[ WorkflowFieldWorkflow ==. wid
, WorkflowFieldType ==. WFTClass
, WorkflowFieldEnm ==. Nothing
, WorkflowFieldFilterNew ==. True
]
[]
return (tfs, efs, cfs)
flip renderDivs html $ NewTicket flip renderDivs html $ NewTicket
<$> (sanitizeBalance <$> areq textField "Title*" Nothing) <$> (sanitizeBalance <$> areq textField "Title*" Nothing)
<*> ( maybe "" (T.filter (/= '\r') . unTextarea) <$> <*> ( maybe "" (T.filter (/= '\r') . unTextarea) <$>
@ -116,6 +134,7 @@ newTicketForm wid html = do
) )
<*> (catMaybes <$> traverse tfield tfs) <*> (catMaybes <$> traverse tfield tfs)
<*> (fmap catMaybes $ sequenceA $ mapMaybe efield efs) <*> (fmap catMaybes $ sequenceA $ mapMaybe efield efs)
<*> (catMaybes <$> traverse cfield cfs)
editTicketContentAForm :: Ticket -> AForm Handler Ticket editTicketContentAForm :: Ticket -> AForm Handler Ticket
editTicketContentAForm ticket = Ticket editTicketContentAForm ticket = Ticket
@ -172,6 +191,13 @@ eEditField (TicketEnumParam (WorkflowFieldSummary fid _ name req _ _) e mv) =
then Just <$> areq sel sets (tepvVal <$> mv) then Just <$> areq sel sets (tepvVal <$> mv)
else aopt sel sets (Just . tepvVal <$> mv) else aopt sel sets (Just . tepvVal <$> mv)
cEditField
:: TicketClassParam
-> AForm Handler (Maybe TicketParamClassId, Maybe WorkflowFieldId)
cEditField (TicketClassParam (WorkflowFieldSummary fid _ name req _ _) mv) =
let sets = fieldSettings name req
in (mv,) . bool Nothing (Just fid) <$> areq checkBoxField sets (Just $ isJust mv)
editableField :: Ticket -> WorkflowFieldSummary -> Bool editableField :: Ticket -> WorkflowFieldSummary -> Bool
editableField t f = editableField t f =
not (wfsConstant f) && not (wfsConstant f) &&
@ -194,22 +220,30 @@ editTicketContentForm
, Maybe (WorkflowFieldId, WorkflowEnumCtorId) , Maybe (WorkflowFieldId, WorkflowEnumCtorId)
) )
] ]
, [ ( Maybe TicketParamClassId
, Maybe WorkflowFieldId
)
]
) )
editTicketContentForm tid t wid html = do editTicketContentForm tid t wid html = do
(tfs, efs) <- (tfs, efs, cfs) <-
lift $ runDB $ lift $ runDB $
liftA2 (,) liftA3 (,,)
( filter (editableField t . ttpField) <$> ( filter (editableField t . ttpField) <$>
getTicketTextParams tid wid getTicketTextParams tid wid
) )
( filter (editableField t . tepField) <$> ( filter (editableField t . tepField) <$>
getTicketEnumParams tid wid getTicketEnumParams tid wid
) )
( filter (editableField t . tcpField) <$>
getTicketClasses tid wid
)
flip renderDivs html $ flip renderDivs html $
liftA3 (,,) (,,,)
(editTicketContentAForm t) <$> editTicketContentAForm t
(traverse tEditField tfs) <*> traverse tEditField tfs
(traverse eEditField efs) <*> traverse eEditField efs
<*> traverse cEditField cfs
assignTicketAForm :: PersonId -> ProjectId -> AForm Handler PersonId assignTicketAForm :: PersonId -> ProjectId -> AForm Handler PersonId
assignTicketAForm pid jid = assignTicketAForm pid jid =

View file

@ -667,13 +667,13 @@ postTicketsR shr prj = do
runDB $ sharerIdent <$> getJust (personIdent p) runDB $ sharerIdent <$> getJust (personIdent p)
enum <- runExceptT $ do enum <- runExceptT $ do
NewTicket title desc tparams eparams <- NewTicket title desc tparams eparams cparams <-
case result of case result of
FormMissing -> throwE "Field(s) missing." FormMissing -> throwE "Field(s) missing."
FormFailure _l -> FormFailure _l ->
throwE "Ticket submission failed, see errors below." throwE "Ticket submission failed, see errors below."
FormSuccess nt -> return nt FormSuccess nt -> return nt
unless (null tparams && null eparams) $ unless (null tparams && null eparams && null cparams) $
throwE "Custom param support currently disabled" throwE "Custom param support currently disabled"
{- {-
let mktparam (fid, v) = TicketParamText let mktparam (fid, v) = TicketParamText

View file

@ -166,7 +166,8 @@ getTicketR :: ShrIdent -> PrjIdent -> Int -> Handler TypedContent
getTicketR shar proj num = do getTicketR shar proj num = do
mpid <- maybeAuthId mpid <- maybeAuthId
( wshr, wfl, ( wshr, wfl,
author, massignee, mcloser, ticket, tparams, eparams, deps, rdeps) <- author, massignee, mcloser, ticket, tparams, eparams, cparams,
deps, rdeps) <-
runDB $ do runDB $ do
(jid, wshr, wid, wfl) <- do (jid, wshr, wid, wfl) <- do
Entity s sharer <- getBy404 $ UniqueSharer shar Entity s sharer <- getBy404 $ UniqueSharer shar
@ -217,6 +218,7 @@ getTicketR shar proj num = do
Nothing -> return Nothing Nothing -> return Nothing
tparams <- getTicketTextParams tid wid tparams <- getTicketTextParams tid wid
eparams <- getTicketEnumParams tid wid eparams <- getTicketEnumParams tid wid
cparams <- getTicketClasses tid wid
deps <- E.select $ E.from $ \ (dep `E.InnerJoin` t) -> do deps <- E.select $ E.from $ \ (dep `E.InnerJoin` t) -> do
E.on $ dep E.^. TicketDependencyChild E.==. t E.^. TicketId E.on $ dep E.^. TicketDependencyChild E.==. t E.^. TicketId
E.where_ $ dep E.^. TicketDependencyParent E.==. E.val tid E.where_ $ dep E.^. TicketDependencyParent E.==. E.val tid
@ -227,7 +229,7 @@ getTicketR shar proj num = do
return t return t
return return
( wshr, wfl ( wshr, wfl
, author, massignee, mcloser, ticket, tparams, eparams , author, massignee, mcloser, ticket, tparams, eparams, cparams
, deps, rdeps , deps, rdeps
) )
encodeHid <- getEncodeKeyHashid encodeHid <- getEncodeKeyHashid
@ -310,7 +312,7 @@ putTicketR shar proj num = do
((result, widget), enctype) <- ((result, widget), enctype) <-
runFormPost $ editTicketContentForm tid ticket wid runFormPost $ editTicketContentForm tid ticket wid
case result of case result of
FormSuccess (ticket', tparams, eparams) -> do FormSuccess (ticket', tparams, eparams, cparams) -> do
newDescHtml <- newDescHtml <-
case renderPandocMarkdown $ ticketSource ticket' of case renderPandocMarkdown $ ticketSource ticket' of
Left err -> do Left err -> do
@ -346,6 +348,13 @@ putTicketR shar proj num = do
update aid [TicketParamEnumValue =. v] update aid [TicketParamEnumValue =. v]
) )
eupd eupd
let (cdel, cins, _ckeep) = partitionMaybePairs cparams
deleteWhere [TicketParamClassId <-. cdel]
let mkcparam fid = TicketParamClass
{ ticketParamClassTicket = tid
, ticketParamClassField = fid
}
insertMany_ $ map mkcparam cins
setMessage "Ticket updated." setMessage "Ticket updated."
redirect $ TicketR shar proj num redirect $ TicketR shar proj num
FormMissing -> do FormMissing -> do

View file

@ -1224,6 +1224,8 @@ changes hLocal ctx =
, renameUnique "WorkflowEnum" "UniqueWorkflowFieldEnum" "UniqueWorkflowEnum" , renameUnique "WorkflowEnum" "UniqueWorkflowFieldEnum" "UniqueWorkflowEnum"
-- 183 -- 183
, renameUnique "WorkflowEnumCtor" "UniqueWorkflowFieldEnumCtor" "UniqueWorkflowEnumCtor" , renameUnique "WorkflowEnumCtor" "UniqueWorkflowFieldEnumCtor" "UniqueWorkflowEnumCtor"
-- 184
, addEntities model_2020_01_05
] ]
migrateDB migrateDB

View file

@ -1,6 +1,6 @@
{- This file is part of Vervis. {- This file is part of Vervis.
- -
- Written in 2018, 2019 by fr33domlover <fr33domlover@riseup.net>. - Written in 2018, 2019, 2020 by fr33domlover <fr33domlover@riseup.net>.
- -
- Copying is an act of love. Please copy, reuse and share. - Copying is an act of love. Please copy, reuse and share.
- -
@ -138,6 +138,7 @@ module Vervis.Migration.Model
, UnfetchedRemoteActor159 , UnfetchedRemoteActor159
, RemoteCollection159Generic (..) , RemoteCollection159Generic (..)
, RemoteCollection159 , RemoteCollection159
, model_2020_01_05
) )
where where
@ -277,3 +278,6 @@ makeEntitiesMigration "152"
makeEntitiesMigration "159" makeEntitiesMigration "159"
$(modelFile "migrations/2019_11_05_remote_actor_ident.model") $(modelFile "migrations/2019_11_05_remote_actor_ident.model")
model_2020_01_05 :: [Entity SqlBackend]
model_2020_01_05 = $(schema "2020_01_05")

View file

@ -1,6 +1,6 @@
{- This file is part of Vervis. {- This file is part of Vervis.
- -
- Written in 2016 by fr33domlover <fr33domlover@riseup.net>. - Written in 2016, 2020 by fr33domlover <fr33domlover@riseup.net>.
- -
- Copying is an act of love. Please copy, reuse and share. - Copying is an act of love. Please copy, reuse and share.
- -
@ -26,7 +26,7 @@ data WorkflowScope = WSSharer | WSPublic | WSFeatured
derivePersistField "WorkflowScope" derivePersistField "WorkflowScope"
data WorkflowFieldType = WFTText | WFTEnum data WorkflowFieldType = WFTText | WFTEnum | WFTClass
deriving (Eq, Show, Read, Bounded, Enum) deriving (Eq, Show, Read, Bounded, Enum)
derivePersistField "WorkflowFieldType" derivePersistField "WorkflowFieldType"

View file

@ -1,6 +1,6 @@
{- This file is part of Vervis. {- This file is part of Vervis.
- -
- Written in 2016, 2018, 2019 by fr33domlover <fr33domlover@riseup.net>. - Written in 2016, 2018, 2019, 2020 by fr33domlover <fr33domlover@riseup.net>.
- -
- Copying is an act of love. Please copy, reuse and share. - Copying is an act of love. Please copy, reuse and share.
- -
@ -25,6 +25,8 @@ module Vervis.Ticket
, TicketEnumParamValue (..) , TicketEnumParamValue (..)
, TicketEnumParam (..) , TicketEnumParam (..)
, getTicketEnumParams , getTicketEnumParams
, TicketClassParam (..)
, getTicketClasses
) )
where where
@ -314,3 +316,68 @@ getTicketEnumParams tid wid = fmap (map toEParam) $
, c ?. WorkflowEnumCtorId , c ?. WorkflowEnumCtorId
, c ?. WorkflowEnumCtorName , c ?. WorkflowEnumCtorName
) )
data TicketClassParam = TicketClassParam
{ tcpField :: WorkflowFieldSummary
, tcpValue :: Maybe TicketParamClassId
}
toCParam
:: ( Value WorkflowFieldId
, Value FldIdent
, Value Text
, Value Bool
, Value Bool
, Value Bool
, Value Bool
, Value Bool
, Value (Maybe TicketParamClassId)
)
-> TicketClassParam
toCParam
( Value fid
, Value fld
, Value name
, Value req
, Value con
, Value new
, Value todo
, Value closed
, Value mp
) = TicketClassParam
{ tcpField = WorkflowFieldSummary
{ wfsId = fid
, wfsIdent = fld
, wfsName = name
, wfsRequired = req
, wfsConstant = con
, wfsFilter = WorkflowFieldFilter
{ wffNew = new
, wffTodo = todo
, wffClosed = closed
}
}
, tcpValue = mp
}
getTicketClasses :: TicketId -> WorkflowId -> AppDB [TicketClassParam]
getTicketClasses tid wid = fmap (map toCParam) $
select $ from $ \ (p `RightOuterJoin` f) -> do
on $
p ?. TicketParamClassField ==. just (f ^. WorkflowFieldId) &&.
p ?. TicketParamClassTicket ==. just (val tid)
where_ $
f ^. WorkflowFieldWorkflow ==. val wid &&.
f ^. WorkflowFieldType ==. val WFTClass &&.
isNothing (f ^. WorkflowFieldEnm)
return
( f ^. WorkflowFieldId
, f ^. WorkflowFieldIdent
, f ^. WorkflowFieldName
, f ^. WorkflowFieldRequired
, f ^. WorkflowFieldConstant
, f ^. WorkflowFieldFilterNew
, f ^. WorkflowFieldFilterTodo
, f ^. WorkflowFieldFilterClosed
, p ?. TicketParamClassId
)

View file

@ -1,6 +1,6 @@
$# This file is part of Vervis. $# This file is part of Vervis.
$# $#
$# Written in 2016, 2018, 2019 by fr33domlover <fr33domlover@riseup.net>. $# Written in 2016, 2018, 2019, 2020 by fr33domlover <fr33domlover@riseup.net>.
$# $#
$# ♡ Copying is an act of love. Please copy, reuse and share. $# ♡ Copying is an act of love. Please copy, reuse and share.
$# $#
@ -134,6 +134,15 @@ $if ticketStatus ticket /= TSClosed
NO VALUE FOR REQUIRED FIELD NO VALUE FOR REQUIRED FIELD
$else $else
(none) (none)
$forall TicketClassParam field mvalue <- cparams
<li .#{relevant $ wfsFilter field}>
<a href=@{WorkflowFieldR wshr wfl $ wfsIdent field}>
#{wfsName field}
:
$maybe _tpcid <- mvalue
Yes
$nothing
No
<p> <p>
^{buttonW DELETE "Delete this ticket" (TicketR shar proj num)} ^{buttonW DELETE "Delete this ticket" (TicketR shar proj num)}