chore(lms): clean learner icons and sorting

This commit is contained in:
Steffen Jost 2023-08-31 09:55:42 +02:00
parent 9a63bebe1b
commit f7ad290053
5 changed files with 66 additions and 39 deletions

View File

@ -66,7 +66,7 @@ TableLmsResetTries: ELearning Versuche zurücksetzen
LmsStatusBlocked: Durchgefallen wegen zu vieler Fehlversuche LmsStatusBlocked: Durchgefallen wegen zu vieler Fehlversuche
LmsStatusExpired: Durchgefallen nach Fristablauf LmsStatusExpired: Durchgefallen nach Fristablauf
LmsStatusSuccess: E#{nonBreakableDash}Learning bestanden LmsStatusSuccess: E#{nonBreakableDash}Learning bestanden
LmsStatusPlanned: E#{nonBreakableDash}Learning wird gerade eröffnet (nur für Admin sichtbar) LmsStatusPlanned: E#{nonBreakableDash}Learning wird gerade noch eröffnet (nur für Admin sichtbar)
LmsStatusDelay: Hinweis: Statusänderung können in seltenen Fällen mehrere Stunden bis zur Anzeige benötigen. LmsStatusDelay: Hinweis: Statusänderung können in seltenen Fällen mehrere Stunden bis zur Anzeige benötigen.
FilterLmsValid: Aktuell gültig FilterLmsValid: Aktuell gültig
FilterLmsRenewal: Erneuerung anstehend FilterLmsRenewal: Erneuerung anstehend

View File

@ -66,7 +66,7 @@ TableLmsResetTries: Reset elearning attempts
LmsStatusBlocked: Failed after too many attempts LmsStatusBlocked: Failed after too many attempts
LmsStatusExpired: Failed due to expiry LmsStatusExpired: Failed due to expiry
LmsStatusSuccess: Passed LmsStatusSuccess: Passed
LmsStatusPlanned: E#{nonBreakableDash}learning is about to be opened (visible to Admins only) LmsStatusPlanned: E#{nonBreakableDash}learning is about to be opened soon (visible to Admins only)
LmsStatusDelay: Note that status changes may occassionaly require more than a hour to be displayed here. LmsStatusDelay: Note that status changes may occassionaly require more than a hour to be displayed here.
FilterLmsValid: Currently valid FilterLmsValid: Currently valid
FilterLmsRenewal: Renewal due FilterLmsRenewal: Renewal due

View File

@ -105,20 +105,23 @@ mkUserTable _sid qsh qid = do
dbtRowKey = (E.^. LmsUserId) dbtRowKey = (E.^. LmsUserId)
dbtProj = dbtProjId dbtProj = dbtProjId
dbtColonnade = dbColonnade $ mconcat dbtColonnade = dbColonnade $ mconcat
[ sortable (Just csvLmsIdent) (i18nCell MsgTableLmsIdent) $ \(view $ _dbrOutput . _entityVal . _lmsUserIdent . _getLmsIdent -> ident) -> textCell ident [ sortable (Just csvLmsIdent) (i18nCell MsgTableLmsIdent) $ \(view $ _dbrOutput . _entityVal . _lmsUserIdent . _getLmsIdent -> ident) -> textCell ident
, sortable (Just csvLmsPin) (i18nCell MsgTableLmsPin & cellAttrs <>~ [("uw-hide-column-default-hidden",mempty)] , sortable (Just csvLmsPin) (i18nCell MsgTableLmsPin & cellAttrs <>~ [("uw-hide-column-default-hidden",mempty)]
) $ \(view $ _dbrOutput . _entityVal . _lmsUserPin -> pin ) -> textCell pin ) $ \(view $ _dbrOutput . _entityVal . _lmsUserPin -> pin ) -> textCell pin
, sortable (Just csvLmsResetPin) (i18nCell MsgTableLmsResetPin) $ \(view $ _dbrOutput . _entityVal . _lmsUserResetPin -> reset) -> ifIconCell reset IconReset , sortable (Just csvLmsResetPin) (i18nCell MsgTableLmsResetPin) $ \(view $ _dbrOutput . _entityVal . _lmsUserResetPin -> reset) -> ifIconCell reset IconReset
, sortable (Just csvLmsDelete) (i18nCell MsgTableLmsDelete) $ \(view $ _dbrOutput . _entityVal . _lmsUserToDelete cutoff -> del ) -> ifIconCell del IconRemoveUser , sortable (Just csvLmsDelete) (i18nCell MsgTableLmsDelete) $ \(view $ _dbrOutput . _entityVal . _lmsUserToDelete cutoff -> del ) -> ifIconCell del IconRemoveUser
, sortable Nothing (i18nCell MsgTableLmsStaff) $ \(view $ _dbrOutput . _entityVal -> lu) -> iconBoolCell (lmsUserStaff lu) , sortable Nothing (i18nCell MsgTableLmsStaff) $ \(view $ _dbrOutput . _entityVal . _lmsUserStaff -> staff) -> ifIconCell staff IconOK
, sortable Nothing (i18nCell MsgTableLmsResetTries) $ \(view $ _dbrOutput . _entityVal -> lu) -> iconBoolCell (lmsUserToResetTries lu) , sortable (Just csvLmsResetTries)(i18nCell MsgTableLmsResetTries) $ \(view $ _dbrOutput . _entityVal . _lmsUserToResetTries -> reset) -> ifIconCell reset IconResetTries
, sortable Nothing (i18nCell MsgTableLmsLock) $ \(view $ _dbrOutput . _entityVal -> lu) -> ifIconCell (lmsUserToLock lu) IconLocked , sortable (Just csvLmsLock) (i18nCell MsgTableLmsLock) $ \(view $ _dbrOutput . _entityVal . _lmsUserToLock -> lock ) -> ifIconCell lock IconLocked
] ]
dbtSorting = Map.fromList dbtSorting = Map.fromList
[ (csvLmsIdent , SortColumn (E.^. LmsUserIdent)) [ (csvLmsIdent , SortColumn (E.^. LmsUserIdent))
, (csvLmsPin , SortColumn (E.^. LmsUserPin)) , (csvLmsPin , SortColumn (E.^. LmsUserPin))
, (csvLmsResetPin , SortColumn (E.^. LmsUserResetPin)) , (csvLmsResetPin , SortColumn (E.^. LmsUserResetPin))
, (csvLmsDelete , SortColumn (lmsUserToDeleteExpr cutoff)) , (csvLmsDelete , SortColumn (lmsUserToDeleteExpr cutoff))
-- , (csvLmsStaff , E.false) -- currently always false
, (csvLmsResetTries , SortColumn lmsUserToResetTriesExpr)
, (csvLmsLock , SortColumn lmsUserToLockExpr)
] ]
dbtFilter = Map.fromList dbtFilter = Map.fromList
[ (csvLmsIdent , FilterColumn $ E.mkContainsFilterWith LmsIdent (E.^. LmsUserIdent )) [ (csvLmsIdent , FilterColumn $ E.mkContainsFilterWith LmsIdent (E.^. LmsUserIdent ))
@ -160,8 +163,8 @@ getLmsLearnersR sid qsh = do
lmsTable <- runDB $ do lmsTable <- runDB $ do
qid <- getKeyBy404 $ SchoolQualificationShort sid qsh qid <- getKeyBy404 $ SchoolQualificationShort sid qsh
view _2 <$> mkUserTable sid qsh qid view _2 <$> mkUserTable sid qsh qid
siteLayoutMsg MsgMenuLmsUsers $ do siteLayoutMsg MsgMenuLmsLearners $ do
setTitleI MsgMenuLmsUsers setTitleI MsgMenuLmsLearners
lmsTable lmsTable
getLmsLearnersDirectR :: SchoolId -> QualificationShorthand -> Handler TypedContent getLmsLearnersDirectR :: SchoolId -> QualificationShorthand -> Handler TypedContent

View File

@ -23,11 +23,10 @@ module Handler.Utils.LMS
, csvFilenameLmsResult , csvFilenameLmsResult
, csvFilenameLmsReport , csvFilenameLmsReport
, lmsDeletionDate , lmsDeletionDate
, lmsUserToDelete, _lmsUserToDelete , lmsUserToDelete , _lmsUserToDelete , lmsUserToDeleteExpr
, lmsUserToDeleteExpr , lmsUserToResetTries , _lmsUserToResetTries , lmsUserToResetTriesExpr
, lmsUserToResetTries , lmsUserToLock , _lmsUserToLock , lmsUserToLockExpr
, lmsUserToLock , lmsUserStaff , _lmsUserStaff
, lmsUserStaff
, lmsStatusInfoCell , lmsStatusInfoCell
, lmsStatusIcon, lmsUserStatusWidget , lmsStatusIcon, lmsUserStatusWidget
, randomLMSIdent, randomLMSIdentBut , randomLMSIdent, randomLMSIdentBut
@ -152,20 +151,35 @@ lmsUserToDelete _ _ = False
_lmsUserToDelete :: Day -> Getter LmsUser Bool _lmsUserToDelete :: Day -> Getter LmsUser Bool
_lmsUserToDelete cutoff = to $ lmsUserToDelete cutoff _lmsUserToDelete cutoff = to $ lmsUserToDelete cutoff
lmsUserToResetTriesExpr :: E.SqlExpr (Entity LmsUser) -> E.SqlExpr (E.Value Bool)
lmsUserToResetTriesExpr luser = (luser E.^. LmsUserResetTries) E.&&. (luser E.^. LmsUserLocked) E.&&.
((luser E.^. LmsUserStatus) `E.in_` E.justValList [LmsBlocked, LmsExpired])
lmsUserToResetTries :: LmsUser -> Bool lmsUserToResetTries :: LmsUser -> Bool
lmsUserToResetTries LmsUser{..} = lmsUserResetTries && lmsUserLocked && lmsUserToResetTries LmsUser{..} = lmsUserResetTries && lmsUserLocked &&
(lmsUserStatus == Just LmsBlocked || lmsUserStatus == Just LmsExpired) (lmsUserStatus == Just LmsBlocked || lmsUserStatus == Just LmsExpired)
-- only reset blocked learners -- only reset blocked learners
_lmsUserToResetTries :: Getter LmsUser Bool
_lmsUserToResetTries = to lmsUserToResetTries
-- | Answers "Should the LMS lock a user out?" -- | Answers "Should the LMS lock a user out?"
-- Note that LmsUserLocked only logs the current LMS state, not what it should be. -- Note that LmsUserLocked only logs the current LMS state, not what it should be.
lmsUserToLockExpr :: E.SqlExpr (Entity LmsUser) -> E.SqlExpr (E.Value Bool)
lmsUserToLockExpr luser = E.isJust (luser E.^. LmsUserStatus)
lmsUserToLock :: LmsUser -> Bool lmsUserToLock :: LmsUser -> Bool
lmsUserToLock LmsUser{..} = isJust lmsUserStatus -- only open LMS should be accessible lmsUserToLock LmsUser{..} = isJust lmsUserStatus -- only open LMS should be accessible
_lmsUserToLock :: Getter LmsUser Bool
_lmsUserToLock = to lmsUserToLock
lmsUserStaff :: LmsUser -> Bool lmsUserStaff :: LmsUser -> Bool
lmsUserStaff = const False -- legacy, currently ignored lmsUserStaff = const False -- legacy, currently ignored
_lmsUserStaff :: Getter LmsUser Bool
_lmsUserStaff = to lmsUserStaff
-- random generation of LmsIdentifiers, maybe this should be in Model.Types.Lms since length specifications are type-y? -- random generation of LmsIdentifiers, maybe this should be in Model.Types.Lms since length specifications are type-y?
lengthIdent :: Int lengthIdent :: Int
@ -230,7 +244,7 @@ lmsStatusInfoCell extendedInfo auditMonths =
<dd>_{MsgLmsStatusLocked} <dd>_{MsgLmsStatusLocked}
<dt>^{icon IconUnlocked} <dt>^{icon IconUnlocked}
<dd>_{MsgLmsStatusUnlocked} <dd>_{MsgLmsStatusUnlocked}
<dt>^{icon IconUndo} <dt>^{icon IconResetTries}
<dd>_{MsgLmsStatusResetTries} <dd>_{MsgLmsStatusResetTries}
<p> <p>
_{MsgLmsStatusDelay} _{MsgLmsStatusDelay}
@ -242,34 +256,44 @@ lmsStatusIcon LmsExpired{} = IconExpired
lmsStatusIcon _other = IconNotOK lmsStatusIcon _other = IconNotOK
lmsUserStatusWidget :: Bool -> LmsUser -> Widget lmsUserStatusWidget :: Bool -> LmsUser -> Widget
lmsUserStatusWidget isAdmin luser lmsUserStatusWidget adminInfo luser = case luser of
| isAdmin = lmsUserStatusWidgetAux isAdmin luser <> toWidget lockIcon <> toWidget resetIcon LmsUser{lmsUserStatus=Just lStat, lmsUserStatusDay=mbDay} ->
| otherwise = lmsUserStatusWidgetAux isAdmin luser
where
lmsUserStatusWidgetAux _ LmsUser{lmsUserStatus=Just lStat, lmsUserStatusDay=Just aday} =
[whamlet|$newline never [whamlet|$newline never
^{formatTimeW SelFormatDate aday} $maybe aday <- mbDay
^{formatTimeW SelFormatDate aday}
$nothing
--.--.----
\ ^{iconFixed (lmsStatusIcon lStat)} \ ^{iconFixed (lmsStatusIcon lStat)}
$if adminInfo
\ ^{lockIcon}
\ ^{resetIcon}
|] |]
-- previously: IconWaitingForUser for lmsUserStatus==Nothing
lmsUserStatusWidgetAux _ LmsUser{lmsUserNotified=Just d} = LmsUser{lmsUserNotified=Just d} ->
[whamlet|$newline never [whamlet|$newline never
^{formatTimeW SelFormatDate d} ^{formatTimeW SelFormatDate d}
\ ^{iconFixed IconNotificationSent} \ ^{iconFixed IconNotificationSent}
$if adminInfo
\ ^{lockIcon}
\ ^{resetIcon}
|] |]
lmsUserStatusWidgetAux True LmsUser{lmsUserStarted} = -- E-Learning started, but not yet notified; only intended for Admins
[whamlet|$newline never
^{formatTimeW SelFormatDate lmsUserStarted}
\ ^{iconFixed IconPlanned}
|]
lmsUserStatusWidgetAux _ _ = mempty
LmsUser{lmsUserStarted=dstart} | adminInfo -> -- E-Learning started, but not yet notified; only intended for Admins;
[whamlet|$newline never
^{formatTimeW SelFormatDate dstart}
\ ^{iconFixed IconPlanned}
$if adminInfo
\ ^{resetIcon}
|] -- would always display Iconlocked
_ -> mempty
where
lockIcon lockIcon
| lmsUserLocked luser == lmsUserToLock luser = mempty | lmsUserLocked luser == lmsUserToLock luser = mempty
| lmsUserLocked luser = iconFixed IconLocked | lmsUserLocked luser = iconFixed IconLocked
| otherwise = iconFixed IconUnlocked | otherwise = iconFixed IconUnlocked
resetIcon resetIcon
| lmsUserResetTries luser = iconFixed IconUndo | lmsUserResetTries luser = iconFixed IconResetTries
| otherwise = mempty | otherwise = mempty

View File

@ -113,7 +113,7 @@ data Icon
| IconExpired | IconExpired
| IconLocked | IconLocked
| IconUnlocked | IconUnlocked
| IconUndo -- also see IconReset | IconResetTries -- also see IconReset
deriving (Eq, Ord, Enum, Bounded, Show, Read, Generic) deriving (Eq, Ord, Enum, Bounded, Show, Read, Generic)
deriving anyclass (Universe, Finite, NFData) deriving anyclass (Universe, Finite, NFData)
@ -204,7 +204,7 @@ iconText = \case
IconExpired -> "hourglass-end" IconExpired -> "hourglass-end"
IconLocked -> "lock" IconLocked -> "lock"
IconUnlocked -> "lock-open-alt" IconUnlocked -> "lock-open-alt"
IconUndo -> "trash-undo" IconResetTries -> "trash-undo"
nullaryPathPiece ''Icon $ camelToPathPiece' 1 nullaryPathPiece ''Icon $ camelToPathPiece' 1
deriveLift ''Icon deriveLift ''Icon