fix(corrections-overview): behavioural fixes
This commit is contained in:
parent
1c66f6320a
commit
e10cfe9c58
@ -1223,7 +1223,7 @@ a.breadcrumbs__home
|
|||||||
font-size: 14px
|
font-size: 14px
|
||||||
font-family: monospace
|
font-family: monospace
|
||||||
|
|
||||||
.func-field__wrapper, .allocation-missing-prios, .allocation-users__accept
|
.func-field__wrapper, .allocation-missing-prios, .allocation-users__accept, .corrections-overview__section
|
||||||
max-height: 75vh
|
max-height: 75vh
|
||||||
overflow: auto
|
overflow: auto
|
||||||
|
|
||||||
|
|||||||
@ -107,9 +107,10 @@
|
|||||||
text-align: right
|
text-align: right
|
||||||
position: absolute
|
position: absolute
|
||||||
left: 0px
|
left: 0px
|
||||||
top: 0
|
bottom: 0
|
||||||
width: 50px
|
width: 50px
|
||||||
height: 100%
|
height: 100%
|
||||||
|
max-height: 100vh
|
||||||
z-index: 40
|
z-index: 40
|
||||||
|
|
||||||
&::before
|
&::before
|
||||||
@ -130,9 +131,10 @@
|
|||||||
text-align: right
|
text-align: right
|
||||||
position: absolute
|
position: absolute
|
||||||
right: 0px
|
right: 0px
|
||||||
top: 0
|
bottom: 0
|
||||||
width: 60px
|
width: 60px
|
||||||
height: 100%
|
height: 100%
|
||||||
|
max-height: 100vh
|
||||||
transition: all .3s ease
|
transition: all .3s ease
|
||||||
z-index: 40
|
z-index: 40
|
||||||
|
|
||||||
|
|||||||
@ -32,6 +32,7 @@ BtnLecInvDecline: Ablehnen
|
|||||||
BtnCorrInvAccept: Annehmen
|
BtnCorrInvAccept: Annehmen
|
||||||
BtnCorrInvDecline: Ablehnen
|
BtnCorrInvDecline: Ablehnen
|
||||||
BtnSubmissionsAssign: Abgaben automatisch zuteilen
|
BtnSubmissionsAssign: Abgaben automatisch zuteilen
|
||||||
|
BtnSubmissionsAssignAll: Abgaben automatisch zuteilen
|
||||||
BtnAllocationCompute: Vergabe berechnen
|
BtnAllocationCompute: Vergabe berechnen
|
||||||
BtnAllocationAccept: Vergabe akzeptieren
|
BtnAllocationAccept: Vergabe akzeptieren
|
||||||
BtnSystemMessageHide: Verstecken
|
BtnSystemMessageHide: Verstecken
|
||||||
@ -633,6 +634,7 @@ NrSubmissionsNotCorrected: Unkorrigiert
|
|||||||
NrSubmissionsNotCorrectedShort: Unkg.
|
NrSubmissionsNotCorrectedShort: Unkg.
|
||||||
CorrectionTime: Korrekturdauer
|
CorrectionTime: Korrekturdauer
|
||||||
AssignSubmissionsRandomWarning: Die Zuteilungsvorschau kann von der tatsächlichen Zuteilung abweichen, wenn mehrere Blätter auf einmal zugeteilt werden, da beim Ausgleich der Kontigente nur bereits zugeteilte Abgaben berücksichtigt werden. Da es ein randomisierte Prozess ist, kann es auch bei einzelnen Blättern gerinfgügige Abweichungen geben.
|
AssignSubmissionsRandomWarning: Die Zuteilungsvorschau kann von der tatsächlichen Zuteilung abweichen, wenn mehrere Blätter auf einmal zugeteilt werden, da beim Ausgleich der Kontigente nur bereits zugeteilte Abgaben berücksichtigt werden. Da es ein randomisierte Prozess ist, kann es auch bei einzelnen Blättern gerinfgügige Abweichungen geben.
|
||||||
|
AssignSubmissionsAssignableSheets: Korrekturen verteilen für:
|
||||||
|
|
||||||
CorrectionsUploaded num@Int64: #{num} Korrekturen wurden gespeichert:
|
CorrectionsUploaded num@Int64: #{num} Korrekturen wurden gespeichert:
|
||||||
NoCorrectionsUploaded: In der hochgeladenen Datei wurden keine Korrekturen gefunden.
|
NoCorrectionsUploaded: In der hochgeladenen Datei wurden keine Korrekturen gefunden.
|
||||||
|
|||||||
@ -32,6 +32,7 @@ BtnLecInvDecline: Decline
|
|||||||
BtnCorrInvAccept: Accept
|
BtnCorrInvAccept: Accept
|
||||||
BtnCorrInvDecline: Decline
|
BtnCorrInvDecline: Decline
|
||||||
BtnSubmissionsAssign: Assign submissions automatically
|
BtnSubmissionsAssign: Assign submissions automatically
|
||||||
|
BtnSubmissionsAssignAll: Automatically distribute corrections
|
||||||
BtnAllocationCompute: Compute allocation
|
BtnAllocationCompute: Compute allocation
|
||||||
BtnAllocationAccept: Accept allocation
|
BtnAllocationAccept: Accept allocation
|
||||||
BtnSystemMessageHide: Hide
|
BtnSystemMessageHide: Hide
|
||||||
@ -631,6 +632,7 @@ NrSubmissionsNotCorrected: Not corrected
|
|||||||
NrSubmissionsNotCorrectedShort: N.corr.
|
NrSubmissionsNotCorrectedShort: N.corr.
|
||||||
CorrectionTime: Correction time
|
CorrectionTime: Correction time
|
||||||
AssignSubmissionsRandomWarning: The assignment preview might be different from the actual assignment if multiple sheets are being distributed. This is due to the fact that only assigned submissions are considered when handling corrector-deficits. Due to this being a randomised process small differences are also possible for a single sheet.
|
AssignSubmissionsRandomWarning: The assignment preview might be different from the actual assignment if multiple sheets are being distributed. This is due to the fact that only assigned submissions are considered when handling corrector-deficits. Due to this being a randomised process small differences are also possible for a single sheet.
|
||||||
|
AssignSubmissionsAssignableSheets: Distribute corrections for:
|
||||||
|
|
||||||
CorrectionsUploaded num: Successfully saved #{num} #{pluralEN num "correction" "corrections"}:
|
CorrectionsUploaded num: Successfully saved #{num} #{pluralEN num "correction" "corrections"}:
|
||||||
NoCorrectionsUploaded: No corrections could be found within the uploaded file.
|
NoCorrectionsUploaded: No corrections could be found within the uploaded file.
|
||||||
|
|||||||
@ -4,7 +4,7 @@ module Handler.Submission.Assign
|
|||||||
, getSAssignR, postSAssignR
|
, getSAssignR, postSAssignR
|
||||||
) where
|
) where
|
||||||
|
|
||||||
import Import hiding (link)
|
import Import hiding (link, unzip)
|
||||||
|
|
||||||
import Handler.Utils hiding (colSchool)
|
import Handler.Utils hiding (colSchool)
|
||||||
import Handler.Utils.Corrections
|
import Handler.Utils.Corrections
|
||||||
@ -12,7 +12,7 @@ import Handler.Utils.Submission
|
|||||||
|
|
||||||
import Data.List as List (foldl, foldr)
|
import Data.List as List (foldl, foldr)
|
||||||
import qualified Data.Set as Set
|
import qualified Data.Set as Set
|
||||||
import Data.Map.Strict ((!))
|
import Data.Map.Strict ((!), (!?))
|
||||||
import qualified Data.Map.Strict as Map
|
import qualified Data.Map.Strict as Map
|
||||||
|
|
||||||
import qualified Data.Text as Text
|
import qualified Data.Text as Text
|
||||||
@ -20,6 +20,8 @@ import qualified Data.CaseInsensitive as CI
|
|||||||
|
|
||||||
import qualified Database.Esqueleto as E
|
import qualified Database.Esqueleto as E
|
||||||
|
|
||||||
|
import Data.List.NonEmpty (unzip)
|
||||||
|
|
||||||
|
|
||||||
getSubAssignR, postSubAssignR :: TermId -> SchoolId -> CourseShorthand -> SheetName -> CryptoFileNameSubmission -> Handler Html
|
getSubAssignR, postSubAssignR :: TermId -> SchoolId -> CourseShorthand -> SheetName -> CryptoFileNameSubmission -> Handler Html
|
||||||
getSubAssignR = postSubAssignR
|
getSubAssignR = postSubAssignR
|
||||||
@ -56,15 +58,6 @@ postSubAssignR tid ssh csh shn cID = do
|
|||||||
$(widgetFile "submission-assign")
|
$(widgetFile "submission-assign")
|
||||||
|
|
||||||
|
|
||||||
data ButtonSubmissionsAssign = BtnSubmissionsAssign
|
|
||||||
deriving (Enum, Eq, Ord, Bounded, Read, Show, Generic, Typeable)
|
|
||||||
instance Universe ButtonSubmissionsAssign
|
|
||||||
instance Finite ButtonSubmissionsAssign
|
|
||||||
nullaryPathPiece ''ButtonSubmissionsAssign camelToPathPiece
|
|
||||||
embedRenderMessage ''UniWorX ''ButtonSubmissionsAssign id
|
|
||||||
instance Button UniWorX ButtonSubmissionsAssign where
|
|
||||||
btnClasses BtnSubmissionsAssign = [BCIsButton, BCPrimary]
|
|
||||||
|
|
||||||
getCAssignR, postCAssignR :: TermId -> SchoolId -> CourseShorthand -> Handler Html
|
getCAssignR, postCAssignR :: TermId -> SchoolId -> CourseShorthand -> Handler Html
|
||||||
getCAssignR = postCAssignR
|
getCAssignR = postCAssignR
|
||||||
postCAssignR tid ssh csh = do
|
postCAssignR tid ssh csh = do
|
||||||
@ -77,35 +70,22 @@ postSAssignR tid ssh csh shn = do
|
|||||||
(shid,cid) <- runDB $ fetchSheetIdCourseId tid ssh csh shn
|
(shid,cid) <- runDB $ fetchSheetIdCourseId tid ssh csh shn
|
||||||
assignHandler tid ssh csh cid [shid]
|
assignHandler tid ssh csh cid [shid]
|
||||||
|
|
||||||
{- TODO: Feature:
|
|
||||||
make distivt buttons for each sheet, so that users see which sheet will be assigned.
|
|
||||||
Currently this information is available within the page heading!
|
|
||||||
|
|
||||||
Stub:
|
|
||||||
data ButtonCorrectionsAssign = BtnCorrectionsAssignAll | BtnCorrectionsAssignSheet SheetName
|
|
||||||
deriving (Enum, Eq, Ord, Bounded, Read, Show, Generic, Typeable)
|
|
||||||
instance Button UniWorX ButtonCorrectionsAssign
|
|
||||||
-- Are those needed any more?
|
|
||||||
instance Universe ButtonCorrectionsAssign
|
|
||||||
instance Finite ButtonCorrectionsAssign
|
|
||||||
nullaryPathPiece ''ButtonCorrectionsAssign camelToPathPiece
|
|
||||||
embedRenderMessage ''UniWorX ''ButtonCorrectionsAssign id
|
|
||||||
instance Button UniWorX ButtonCorrectionsAssign where
|
|
||||||
btnClasses BtnCorrectionsAssign = [BCIsButton, BCPrimary]
|
|
||||||
-- use runButtonForm' instead later on
|
|
||||||
-}
|
|
||||||
|
|
||||||
assignHandler :: TermId -> SchoolId -> CourseShorthand -> CourseId -> [SheetId] -> Handler Html
|
assignHandler :: TermId -> SchoolId -> CourseShorthand -> CourseId -> [SheetId] -> Handler Html
|
||||||
assignHandler tid ssh csh cid assignSids = do
|
assignHandler tid ssh csh cid assignSids = do
|
||||||
-- evaluate form first, since it affects DB action
|
currentRoute <- fromMaybe (error "assignHandler called from 404-handler") <$> liftHandler getCurrentRoute
|
||||||
(btnWdgt, btnResult) <- runButtonForm FIDAssignSubmissions
|
|
||||||
|
|
||||||
-- gather data
|
-- gather data
|
||||||
(orderedSheetNames, assignSheetNames, nrParticipants, groupsPossible, infoMap, correctorMap, assignment) <- runDB $ do
|
(orderedSheetNames, assignSheetNames, nrParticipants, groupsPossible, infoMap, correctorMap, assignment, ((btnViews, btnCsrf), btnEncoding)) <- runDB $ do
|
||||||
-- cid <- getKeyBy404 $ TermSchoolCourseShort tid ssh csh
|
-- cid <- getKeyBy404 $ TermSchoolCourseShort tid ssh csh
|
||||||
nrParticipants <- count [CourseParticipantCourse ==. cid, CourseParticipantState ==. CourseParticipantActive ]
|
nrParticipants <- count [CourseParticipantCourse ==. cid, CourseParticipantState ==. CourseParticipantActive ]
|
||||||
|
|
||||||
sheetList <- selectList [SheetCourse ==. cid] [Desc SheetActiveTo, Desc SheetActiveFrom]
|
sheetList <- selectList [SheetCourse ==. cid] [Desc SheetActiveTo, Desc SheetActiveFrom]
|
||||||
|
assignSids' <- if
|
||||||
|
| null assignSids -> -- assignAll; we distinguish assignSids' here avoid useless Alerts
|
||||||
|
selectKeysList [SheetCourse ==. cid] [Asc SheetActiveTo]
|
||||||
|
| otherwise -> return $ filter (`elem` map entityKey sheetList) assignSids
|
||||||
|
|
||||||
let orderedSheetNames = fmap (\(Entity _ Sheet{sheetName}) -> sheetName) sheetList
|
let orderedSheetNames = fmap (\(Entity _ Sheet{sheetName}) -> sheetName) sheetList
|
||||||
sheets = entities2map sheetList
|
sheets = entities2map sheetList
|
||||||
sheetIds = Map.keys sheets
|
sheetIds = Map.keys sheets
|
||||||
@ -114,6 +94,12 @@ assignHandler tid ssh csh cid assignSids = do
|
|||||||
let foldFun (Entity _ Sheet{sheetGrouping=sgr}) acc = acc || sgr /= NoGroups
|
let foldFun (Entity _ Sheet{sheetGrouping=sgr}) acc = acc || sgr /= NoGroups
|
||||||
in List.foldr foldFun False sheetList
|
in List.foldr foldFun False sheetList
|
||||||
assignSheetNames = fmap sheetName $ mapMaybe (\sid -> Map.lookup sid sheets) assignSids
|
assignSheetNames = fmap sheetName $ mapMaybe (\sid -> Map.lookup sid sheets) assignSids
|
||||||
|
assignSheetNames' = fmap sheetName $ mapMaybe (\sid -> Map.lookup sid sheets) assignSids'
|
||||||
|
|
||||||
|
assignButtons = Map.fromSet (maybe BtnSubmissionsAssignAll BtnSubmissionsAssign) $ Set.fromList . bool (Nothing :) id (null sheetList) $ map Just assignSheetNames'
|
||||||
|
|
||||||
|
((btnResult, btnViews'), btnEncoding) <- runFormPost . identifyForm FIDAssignSubmissions $ \csrf ->
|
||||||
|
fmap (over _1 (asum . fmap (hoistMaybe =<<)) . over _2 (, csrf) . unzip) . for assignButtons $ \btn -> mopt (buttonField btn) "" Nothing
|
||||||
|
|
||||||
-- plan or assign unassigned submissions for given sheets
|
-- plan or assign unassigned submissions for given sheets
|
||||||
let buildA :: (Map SheetName ((Set SubmissionId, Set SubmissionId), Map (Maybe UserId) Int, Map UserId Rational)) -> SheetId -> DB (Map SheetName ((Set SubmissionId, Set SubmissionId), Map (Maybe UserId) Int, Map UserId Rational))
|
let buildA :: (Map SheetName ((Set SubmissionId, Set SubmissionId), Map (Maybe UserId) Int, Map UserId Rational)) -> SheetId -> DB (Map SheetName ((Set SubmissionId, Set SubmissionId), Map (Maybe UserId) Int, Map UserId Rational))
|
||||||
@ -128,24 +114,29 @@ assignHandler tid ssh csh cid assignSids = do
|
|||||||
ignoreExceptions (SubmissionsNotFound _sids_not_found) = return mempty -- cannot happen, since last argument to planSubmissions is Nothing
|
ignoreExceptions (SubmissionsNotFound _sids_not_found) = return mempty -- cannot happen, since last argument to planSubmissions is Nothing
|
||||||
(plan,deficit) <- lift $ handle ignoreExceptions $ planSubmissions sid Nothing
|
(plan,deficit) <- lift $ handle ignoreExceptions $ planSubmissions sid Nothing
|
||||||
guard $ not $ null plan -- only proceed if there is a plan for this sheet
|
guard $ not $ null plan -- only proceed if there is a plan for this sheet
|
||||||
-- implement assignment plan
|
status@(sub_ok, sub_fail) <- fmap fold . formResultMaybe btnResult $ \btn -> lift . maybeT (return Nothing) $ do
|
||||||
status <- lift $ case btnResult of
|
guard $ case btn of
|
||||||
Nothing -> return (Set.empty, Set.empty)
|
BtnSubmissionsAssignAll -> True
|
||||||
(Just BtnSubmissionsAssign) -> do
|
BtnSubmissionsAssign shn' -> shn' == shn
|
||||||
status@(sub_ok,sub_fail) <- writeSubmissionPlan plan
|
|
||||||
let nr_ok = olength sub_ok
|
status@(sub_ok,sub_fail) <- lift $ writeSubmissionPlan plan
|
||||||
nr_fail = olength sub_fail
|
let nr_ok = olength sub_ok
|
||||||
alert_ok = toMaybe (nr_ok > 0) $ SomeMessage $ MsgUpdatedSheetCorrectorsAutoAssigned nr_ok
|
nr_fail = olength sub_fail
|
||||||
alert_fail = toMaybe (nr_fail > 0) $ SomeMessage $ MsgUpdatedSheetCorrectorsAutoFailed nr_fail
|
alert_ok = toMaybe (nr_ok > 0) $ SomeMessage $ MsgUpdatedSheetCorrectorsAutoAssigned nr_ok
|
||||||
msg_status = bool Success Error $ nr_fail > 0
|
alert_fail = toMaybe (nr_fail > 0) $ SomeMessage $ MsgUpdatedSheetCorrectorsAutoFailed nr_fail
|
||||||
msg_header = SomeMessage $ shn <> ":"
|
msg_status = bool Success Error $ nr_fail > 0
|
||||||
when (nr_ok > 0 || nr_fail > 0) $
|
msg_header = SomeMessage $ shn <> ":"
|
||||||
addMessageI msg_status $ UniWorXMessages $ msg_header : catMaybes [alert_ok, alert_fail]
|
if | nr_ok > 0 || nr_fail > 0 -> do
|
||||||
return status
|
addMessageI msg_status $ UniWorXMessages $ msg_header : catMaybes [alert_ok, alert_fail]
|
||||||
return $ Map.insert shn (status, countMapElems plan, deficit) acc
|
return $ Just status
|
||||||
assignSids' <- if null assignSids -- assignAll; we distinguish assignSids' here avoid useless Alerts
|
| otherwise -> do
|
||||||
then selectKeysList [SheetCourse ==. cid] [Asc SheetActiveTo]
|
addMessageI Error $ MsgSheetsUnassignable $ CI.original shn
|
||||||
else return assignSids
|
return Nothing
|
||||||
|
if | null sub_ok && null sub_fail ->
|
||||||
|
return $ Map.insert shn (status, countMapElems plan, deficit) acc
|
||||||
|
| otherwise -> do
|
||||||
|
(plan', deficit') <- lift $ handle ignoreExceptions $ planSubmissions sid Nothing
|
||||||
|
return $ Map.insert shn (status, countMapElems plan', deficit') acc
|
||||||
assignment <- foldM buildA Map.empty assignSids'
|
assignment <- foldM buildA Map.empty assignSids'
|
||||||
|
|
||||||
correctors <- E.select . E.from $ \(corrector `E.InnerJoin` user) -> do
|
correctors <- E.select . E.from $ \(corrector `E.InnerJoin` user) -> do
|
||||||
@ -202,7 +193,7 @@ assignHandler tid ssh csh cid assignSids = do
|
|||||||
}
|
}
|
||||||
in Map.insertWith (Map.unionWith (<>)) shnm cinf m
|
in Map.insertWith (Map.unionWith (<>)) shnm cinf m
|
||||||
|
|
||||||
return (orderedSheetNames, assignSheetNames, nrParticipants, groupsPossible, infoMap, correctorMap, assignment)
|
return (orderedSheetNames, assignSheetNames, nrParticipants, groupsPossible, infoMap, correctorMap, assignment, (btnViews', btnEncoding))
|
||||||
|
|
||||||
let -- infoMap :: Map SheetName (Map (Maybe UserId) CorrectionInfo) -- repeated here for easier reference
|
let -- infoMap :: Map SheetName (Map (Maybe UserId) CorrectionInfo) -- repeated here for easier reference
|
||||||
-- create aggregate maps
|
-- create aggregate maps
|
||||||
@ -268,14 +259,39 @@ assignHandler tid ssh csh cid assignSids = do
|
|||||||
showAvgsDays :: Maybe NominalDiffTime -> Integer -> Text
|
showAvgsDays :: Maybe NominalDiffTime -> Integer -> Text
|
||||||
showAvgsDays Nothing _ = mempty
|
showAvgsDays Nothing _ = mempty
|
||||||
showAvgsDays (Just dt) n = formatDiffDays $ dt / fromIntegral n
|
showAvgsDays (Just dt) n = formatDiffDays $ dt / fromIntegral n
|
||||||
let headingShort
|
let headingShort = MsgMenuCorrectionsAssign
|
||||||
| 0 < Map.size assignment = MsgMenuCorrectionsAssignSheet $ Text.intercalate ", " $ fmap CI.original $ Map.keys assignment
|
headingLong = prependCourseTitle tid ssh csh MsgMenuCorrectionsAssign
|
||||||
| otherwise = MsgMenuCorrectionsAssign
|
|
||||||
headingLong = prependCourseTitle tid ssh csh MsgMenuCorrectionsAssign
|
|
||||||
|
|
||||||
unassignableSheets = filter (\shn -> Map.notMember shn assignment) assignSheetNames
|
unassignableSheets = filter (\shn -> Map.notMember shn assignment) assignSheetNames
|
||||||
unless (null unassignableSheets) $ addMessageI Warning $ MsgSheetsUnassignable $ Text.intercalate ", " $ fmap CI.original unassignableSheets
|
unless (null unassignableSheets) $ addMessageI Warning $ MsgSheetsUnassignable $ Text.intercalate ", " $ fmap CI.original unassignableSheets
|
||||||
|
|
||||||
siteLayoutMsg headingShort $ do
|
siteLayoutMsg headingShort $ do
|
||||||
setTitleI headingLong
|
setTitleI headingLong
|
||||||
$(widgetFile "corrections-overview")
|
|
||||||
|
let doWrap wdgt
|
||||||
|
| null btnViews = wdgt
|
||||||
|
| otherwise = wrapForm (toWidget btnCsrf <> wdgt) def
|
||||||
|
{ formAction = Just . SomeRoute $ currentRoute
|
||||||
|
, formEncoding = btnEncoding
|
||||||
|
, formSubmit = FormNoSubmit
|
||||||
|
}
|
||||||
|
sheetBtnViews = Map.fromList [ (shn, btn) | (Just shn, btn) <- Map.toList btnViews, shn `elem` assignSheetNames' ]
|
||||||
|
assignSheetNames' = Map.keys $ Map.filter (\(_, new, _) -> any (> 0) $ Map.delete Nothing new) assignment
|
||||||
|
|
||||||
|
doWrap $(widgetFile "corrections-overview")
|
||||||
|
|
||||||
|
|
||||||
|
data ButtonSubmissionsAssign
|
||||||
|
= BtnSubmissionsAssign SheetName
|
||||||
|
| BtnSubmissionsAssignAll
|
||||||
|
deriving (Eq, Ord, Read, Show, Generic, Typeable)
|
||||||
|
derivePathPiece ''ButtonSubmissionsAssign (camelToPathPiece' 2) "--"
|
||||||
|
|
||||||
|
instance RenderMessage UniWorX ButtonSubmissionsAssign where
|
||||||
|
renderMessage f ls = \case
|
||||||
|
BtnSubmissionsAssign _ -> mr MsgBtnSubmissionsAssign
|
||||||
|
BtnSubmissionsAssignAll -> mr MsgBtnSubmissionsAssignAll
|
||||||
|
where mr = renderMessage f ls
|
||||||
|
|
||||||
|
instance Button UniWorX ButtonSubmissionsAssign where
|
||||||
|
btnClasses _ = [BCIsButton, BCPrimary]
|
||||||
|
|||||||
@ -2,146 +2,176 @@ $newline never
|
|||||||
<section>
|
<section>
|
||||||
<h2>_{MsgCorrectionSheets}
|
<h2>_{MsgCorrectionSheets}
|
||||||
|
|
||||||
_{MsgCourseParticipants nrParticipants}
|
<p>
|
||||||
<table .table .table--striped .table--hover>
|
_{MsgCourseParticipants nrParticipants}
|
||||||
<tr .table__row .table__row--head>
|
|
||||||
<th .table__th rowspan=2>_{MsgSheet}
|
<div .scrolltable .scrolltable--bordered .corrections-overview__section>
|
||||||
$if groupsPossible
|
<table .table .table--striped .table--hover>
|
||||||
<th .table__th rowspan=2>_{MsgNrSubmittorsTotal}
|
<tr .table__row .table__row--head>
|
||||||
<th .table__th rowspan=2>_{MsgNrSubmissionsTotal}
|
<th .table__th rowspan=2>_{MsgSheet}
|
||||||
<th .table__th colspan=2>_{MsgNrSubmissionsNotAssigned}
|
$if groupsPossible
|
||||||
<th .table__th rowspan=2>_{MsgNrSubmissionsNotCorrected}
|
<th .table__th rowspan=2>_{MsgNrSubmittorsTotal}
|
||||||
<th .table__th colspan=3>_{MsgCorrectionTime}
|
<th .table__th rowspan=2>_{MsgNrSubmissionsTotal}
|
||||||
<tr .table__row .table__row--head>
|
<th .table__th colspan=2>_{MsgNrSubmissionsNotAssigned}
|
||||||
<th .table__th>
|
<th .table__th rowspan=2>_{MsgNrSubmissionsNotCorrected}
|
||||||
<th .table__th>_{MsgGenericNumChange}
|
<th .table__th colspan=3>_{MsgCorrectionTime}
|
||||||
<th .table__th>_{MsgGenericMin}
|
<tr .table__row .table__row--head>
|
||||||
<th .table__th>_{MsgGenericAvg}
|
<th .table__th>
|
||||||
<th .table__th>_{MsgGenericMax}
|
<th .table__th>_{MsgGenericNumChange}
|
||||||
$# Always iterate over orderedSheetNames for consistent sorting! Newest first, except in this table
|
<th .table__th>_{MsgGenericMin}
|
||||||
$forall sheetName <- reverse orderedSheetNames
|
<th .table__th>_{MsgGenericAvg}
|
||||||
$maybe CorrectionInfo{ciSubmittors, ciSubmissions, ciAssigned, ciCorrected, ciMin, ciTot, ciMax} <- Map.lookup sheetName sheetMap
|
<th .table__th>_{MsgGenericMax}
|
||||||
<tr .table__row>
|
$# Always iterate over orderedSheetNames for consistent sorting! Newest first, except in this table
|
||||||
<td .table__td>^{simpleLink (toWidget sheetName) (CSheetR tid ssh csh sheetName SSubsR)}
|
$forall sheetName <- reverse orderedSheetNames
|
||||||
$if groupsPossible
|
$maybe CorrectionInfo{ciSubmittors, ciSubmissions, ciAssigned, ciCorrected, ciMin, ciTot, ciMax} <- Map.lookup sheetName sheetMap
|
||||||
<td .table__td>#{ciSubmittors}
|
<tr .table__row>
|
||||||
<td .table__td>#{ciSubmissions}
|
<td .table__td>^{simpleLink (toWidget sheetName) (CSheetR tid ssh csh sheetName SSubsR)}
|
||||||
$maybe ((splus,sfailed),_,_) <- Map.lookup sheetName assignment
|
$if groupsPossible
|
||||||
$if 0 < Set.size sfailed
|
<td .table__td>#{ciSubmittors}
|
||||||
<td .table__td>#{ciSubmissions - ciAssigned}
|
<td .table__td>#{ciSubmissions}
|
||||||
<td .table__td .alert-danger>(-#{show (Set.size splus)}, failed: #{show (Set.size sfailed)})
|
$maybe ((splus,sfailed),_,_) <- Map.lookup sheetName assignment
|
||||||
$elseif 0 < Set.size splus
|
$if 0 < Set.size sfailed
|
||||||
<td .table__td>#{ciSubmissions - ciAssigned}
|
<td .table__td>#{ciSubmissions - ciAssigned}
|
||||||
<td .table__td .alert-info>(-#{show (Set.size splus)})
|
<td .table__td .alert-danger>(-#{show (Set.size splus)}, failed: #{show (Set.size sfailed)})
|
||||||
$else
|
$elseif 0 < Set.size splus
|
||||||
|
<td .table__td>#{ciSubmissions - ciAssigned}
|
||||||
|
<td .table__td .alert-info>(-#{show (Set.size splus)})
|
||||||
|
$else
|
||||||
|
<td .table__td>#{ciSubmissions - ciAssigned}
|
||||||
|
<td .table__td>
|
||||||
|
$nothing
|
||||||
<td .table__td>#{ciSubmissions - ciAssigned}
|
<td .table__td>#{ciSubmissions - ciAssigned}
|
||||||
<td .table__td>
|
<td .table__td>
|
||||||
$nothing
|
<td .table__td>#{ciSubmissions - ciCorrected}
|
||||||
<td .table__td>#{ciSubmissions - ciAssigned}
|
<td .table__td>#{showDiffDays ciMin}
|
||||||
<td .table__td>
|
<td .table__td>#{showAvgsDays ciTot ciCorrected}
|
||||||
<td .table__td>#{ciSubmissions - ciCorrected}
|
<td .table__td>#{showDiffDays ciMax}
|
||||||
<td .table__td>#{showDiffDays ciMin}
|
|
||||||
<td .table__td>#{showAvgsDays ciTot ciCorrected}
|
|
||||||
<td .table__td>#{showDiffDays ciMax}
|
|
||||||
|
|
||||||
<section>
|
<section>
|
||||||
<h2>_{MsgCorrectionCorrectors}
|
<h2>_{MsgCorrectionCorrectors}
|
||||||
|
|
||||||
<table .table .table--striped .table--hover>
|
<div .scrolltable .scrolltable--bordered>
|
||||||
<tr .table__row .table__row--head>
|
<table .table .table--striped .table--hover>
|
||||||
<th .table__th rowspan=2>_{MsgCorrector}
|
|
||||||
<th .table__th colspan=2>_{MsgGenericAll}
|
|
||||||
<th .table__th rowspan=2>_{MsgCorDeficitProportion}
|
|
||||||
<th .table__th colspan=3>_{MsgCorrectionTime}
|
|
||||||
|
|
||||||
$# Always iterate over orderedSheetNames for consistent sorting! Newest first, except in this table
|
|
||||||
$forall shn <- orderedSheetNames
|
|
||||||
<th .table__th colspan=5>
|
|
||||||
^{simpleLink (toWidget shn) (CSheetR tid ssh csh shn SShowR)}
|
|
||||||
<tr .table__row .table__row--head>
|
|
||||||
<th .table__th>_{MsgNrSubmissionsTotal}
|
|
||||||
<th .table__th>_{MsgNrSubmissionsNotCorrected}
|
|
||||||
<th .table__th>_{MsgGenericMin}
|
|
||||||
<th .table__th>_{MsgGenericAvg}
|
|
||||||
<th .table__th>_{MsgGenericMax}
|
|
||||||
$# Always iterate over orderedSheetNames for consistent sorting! Newest first, except in this table
|
|
||||||
$forall _shn <- orderedSheetNames
|
|
||||||
<th .table__th>_{MsgCorProportion}
|
|
||||||
<th .table__th>_{MsgNrSubmissionsTotalShort}
|
|
||||||
<th .table__th>_{MsgGenericNumChange}
|
|
||||||
<th .table__th>_{MsgNrSubmissionsNotCorrectedShort}
|
|
||||||
<th .table__th>_{MsgGenericAvg}
|
|
||||||
$forall (CorrectionInfo{ciCorrector, ciSubmissions=ciSubmissionsNr, ciCorrected, ciMin, ciTot, ciMax}) <- corrInfos
|
|
||||||
$with (nameW,loadM, name) <- getCorrector ciCorrector
|
|
||||||
$# TODO: User proper Tooltips instead of title attribute here, once Tooltips work with tables
|
|
||||||
<tr .table__row title="#{name}">
|
|
||||||
<td .table__td>^{nameW}
|
|
||||||
<td .table__td>#{ciSubmissionsNr}
|
|
||||||
$with total <- ciSubmissions corrMapSum
|
|
||||||
$if total > 0
|
|
||||||
\ (#{textPercent' True 0 ciSubmissionsNr total})
|
|
||||||
<td .table__td .heated style="--hotness: #{heat ciSubmissionsNr ciCorrected}">#{ciSubmissionsNr - ciCorrected}
|
|
||||||
<td .table__td>
|
|
||||||
$maybe deficit <- getCorrDeficit ciCorrector
|
|
||||||
#{rationalToFixed3 deficit}
|
|
||||||
<td .table__td>#{showDiffDays ciMin}
|
|
||||||
<td .table__td>#{showAvgsDays ciTot ciCorrected}
|
|
||||||
<td .table__td>#{showDiffDays ciMax}
|
|
||||||
$# Always iterate over orderedSheetNames for consistent sorting! Newest first, except in this table
|
|
||||||
$forall shn <- orderedSheetNames
|
|
||||||
$maybe CorrectionInfo{ciSubmissions=sheetSubmissionsNr} <- Map.lookup shn sheetMap
|
|
||||||
<td .table__td>
|
|
||||||
$maybe SheetCorrector{sheetCorrectorLoad, sheetCorrectorState} <- Map.lookup shn loadM
|
|
||||||
#{showCompactCorrectorLoad sheetCorrectorLoad sheetCorrectorState}
|
|
||||||
$if sheetCorrectorState == CorrectorNormal
|
|
||||||
$maybe Load{byProportion=total} <- Map.lookup shn sheetLoad
|
|
||||||
$if total > 0
|
|
||||||
\ (#{textPercent' True 0 (byProportion sheetCorrectorLoad) total})
|
|
||||||
$maybe CorrectionInfo{ciSubmissions,ciCorrected,ciTot} <- getCorrSheetStatus ciCorrector shn
|
|
||||||
<td .table__td>#{ciSubmissions}
|
|
||||||
$if sheetSubmissionsNr > 0
|
|
||||||
\ (#{textPercent' True 0 ciSubmissions sheetSubmissionsNr})
|
|
||||||
$maybe nrNew <- getCorrNewAssignment ciCorrector shn
|
|
||||||
$# <td .table__td>#{ciAssigned} `ciSubmissions` is here always identical to `ciAssigned` and also works for `ciCorrector == Nothing`. ciAssigned only useful in aggregate maps like `sheetMap`
|
|
||||||
<td .table__td .alert-info>(+#{nrNew})
|
|
||||||
$nothing
|
|
||||||
<td .table__td>
|
|
||||||
<td .table__td .heated style="--hotness: #{heat ciSubmissions ciCorrected}">#{ciSubmissions - ciCorrected}
|
|
||||||
<td .table__td>#{showAvgsDays ciTot ciCorrected}
|
|
||||||
$nothing
|
|
||||||
<td .table__td>
|
|
||||||
<td .table__td>
|
|
||||||
<td .table__td>
|
|
||||||
<td .table__td>
|
|
||||||
$if not (null orderedSheetNames)
|
|
||||||
<tr .table__row>
|
|
||||||
<td .table__th>Σ
|
|
||||||
$with ciSubmissionsNr <- ciSubmissions corrMapSum
|
|
||||||
$with ciCorrectedNr <- ciCorrected corrMapSum
|
|
||||||
<td .table__th>#{ciSubmissionsNr}
|
|
||||||
<td .table__td .heated style="--hotness: #{heat ciSubmissionsNr ciCorrectedNr}">#{ciSubmissionsNr - ciCorrectedNr}
|
|
||||||
<td .table__th>#{ciCorrected corrMapSum}
|
|
||||||
<td .table__th>#{showDiffDays (ciMin corrMapSum)}
|
|
||||||
<td .table__th>#{showAvgsDays (ciTot corrMapSum) (ciCorrected corrMapSum)}
|
|
||||||
<td .table__th>#{showDiffDays (ciMax corrMapSum)}
|
|
||||||
$# Always iterate over orderedSheetNames for consistent sorting! Newest first, except in this table
|
|
||||||
$forall shn <- orderedSheetNames
|
|
||||||
$maybe CorrectionInfo{ciSubmissions} <- Map.lookup shn sheetMap
|
|
||||||
<td .table__th>#{getLoadSum shn}
|
|
||||||
<td .table__th>#{ciSubmissions}
|
|
||||||
<td .table__td colspan=3>^{simpleLinkI (SomeMessage MsgMenuCorrectorsChange) (CSheetR tid ssh csh shn SEditR)}
|
|
||||||
|
|
||||||
<tr .table__row .table__row--head>
|
<tr .table__row .table__row--head>
|
||||||
<th>
|
<th .table__th rowspan=2>_{MsgCorrector}
|
||||||
<th colspan=2>
|
<th .table__th colspan=2>_{MsgGenericAll}
|
||||||
<th>
|
<th .table__th rowspan=2>_{MsgCorDeficitProportion}
|
||||||
<th colspan=3>
|
<th .table__th colspan=3>_{MsgCorrectionTime}
|
||||||
|
|
||||||
$# Always iterate over orderedSheetNames for consistent sorting! Newest first, except in this table
|
$# Always iterate over orderedSheetNames for consistent sorting! Newest first, except in this table
|
||||||
$forall shn <- orderedSheetNames
|
$forall shn <- orderedSheetNames
|
||||||
<th .table__th colspan=5>
|
<th .table__th colspan=5>
|
||||||
^{simpleLink (toWidget shn) (CSheetR tid ssh csh shn SShowR)}
|
^{simpleLink (toWidget shn) (CSheetR tid ssh csh shn SShowR)}
|
||||||
|
<tr .table__row .table__row--head>
|
||||||
|
<th .table__th>_{MsgNrSubmissionsTotal}
|
||||||
|
<th .table__th>_{MsgNrSubmissionsNotCorrected}
|
||||||
|
<th .table__th>_{MsgGenericMin}
|
||||||
|
<th .table__th>_{MsgGenericAvg}
|
||||||
|
<th .table__th>_{MsgGenericMax}
|
||||||
|
$# Always iterate over orderedSheetNames for consistent sorting! Newest first, except in this table
|
||||||
|
$forall _shn <- orderedSheetNames
|
||||||
|
<th .table__th>_{MsgCorProportion}
|
||||||
|
<th .table__th>_{MsgNrSubmissionsTotalShort}
|
||||||
|
<th .table__th>_{MsgGenericNumChange}
|
||||||
|
<th .table__th>_{MsgNrSubmissionsNotCorrectedShort}
|
||||||
|
<th .table__th>_{MsgGenericAvg}
|
||||||
|
$forall (CorrectionInfo{ciCorrector, ciSubmissions=ciSubmissionsNr, ciCorrected, ciMin, ciTot, ciMax}) <- corrInfos
|
||||||
|
$with (nameW,loadM, name) <- getCorrector ciCorrector
|
||||||
|
$# TODO: User proper Tooltips instead of title attribute here, once Tooltips work with tables
|
||||||
|
<tr .table__row title="#{name}">
|
||||||
|
<td .table__td>^{nameW}
|
||||||
|
<td .table__td>#{ciSubmissionsNr}
|
||||||
|
$with total <- ciSubmissions corrMapSum
|
||||||
|
$if total > 0
|
||||||
|
\ (#{textPercent' True 0 ciSubmissionsNr total})
|
||||||
|
<td .table__td .heated style="--hotness: #{heat ciSubmissionsNr ciCorrected}">#{ciSubmissionsNr - ciCorrected}
|
||||||
|
<td .table__td>
|
||||||
|
$maybe deficit <- getCorrDeficit ciCorrector
|
||||||
|
#{rationalToFixed3 deficit}
|
||||||
|
<td .table__td>#{showDiffDays ciMin}
|
||||||
|
<td .table__td>#{showAvgsDays ciTot ciCorrected}
|
||||||
|
<td .table__td>#{showDiffDays ciMax}
|
||||||
|
$# Always iterate over orderedSheetNames for consistent sorting! Newest first, except in this table
|
||||||
|
$forall shn <- orderedSheetNames
|
||||||
|
$maybe CorrectionInfo{ciSubmissions=sheetSubmissionsNr} <- Map.lookup shn sheetMap
|
||||||
|
<td .table__td>
|
||||||
|
$maybe SheetCorrector{sheetCorrectorLoad, sheetCorrectorState} <- Map.lookup shn loadM
|
||||||
|
#{showCompactCorrectorLoad sheetCorrectorLoad sheetCorrectorState}
|
||||||
|
$if sheetCorrectorState == CorrectorNormal
|
||||||
|
$maybe Load{byProportion=total} <- Map.lookup shn sheetLoad
|
||||||
|
$if total > 0
|
||||||
|
\ (#{textPercent' True 0 (byProportion sheetCorrectorLoad) total})
|
||||||
|
$maybe CorrectionInfo{ciSubmissions,ciCorrected,ciTot} <- getCorrSheetStatus ciCorrector shn
|
||||||
|
<td .table__td>#{ciSubmissions}
|
||||||
|
$if sheetSubmissionsNr > 0
|
||||||
|
\ (#{textPercent' True 0 ciSubmissions sheetSubmissionsNr})
|
||||||
|
$maybe nrNew <- getCorrNewAssignment ciCorrector shn
|
||||||
|
$# <td .table__td>#{ciAssigned} `ciSubmissions` is here always identical to `ciAssigned` and also works for `ciCorrector == Nothing`. ciAssigned only useful in aggregate maps like `sheetMap`
|
||||||
|
<td .table__td .alert-info>(+#{nrNew})
|
||||||
|
$nothing
|
||||||
|
<td .table__td>
|
||||||
|
<td .table__td .heated style="--hotness: #{heat ciSubmissions ciCorrected}">#{ciSubmissions - ciCorrected}
|
||||||
|
<td .table__td>#{showAvgsDays ciTot ciCorrected}
|
||||||
|
$nothing
|
||||||
|
<td .table__td>
|
||||||
|
<td .table__td>
|
||||||
|
<td .table__td>
|
||||||
|
<td .table__td>
|
||||||
|
$if not (null orderedSheetNames)
|
||||||
|
<tr .table__row>
|
||||||
|
<td .table__th>Σ
|
||||||
|
$with ciSubmissionsNr <- ciSubmissions corrMapSum
|
||||||
|
$with ciCorrectedNr <- ciCorrected corrMapSum
|
||||||
|
<td .table__th>#{ciSubmissionsNr}
|
||||||
|
<td .table__td .heated style="--hotness: #{heat ciSubmissionsNr ciCorrectedNr}">#{ciSubmissionsNr - ciCorrectedNr}
|
||||||
|
<td .table__th>#{ciCorrected corrMapSum}
|
||||||
|
<td .table__th>#{showDiffDays (ciMin corrMapSum)}
|
||||||
|
<td .table__th>#{showAvgsDays (ciTot corrMapSum) (ciCorrected corrMapSum)}
|
||||||
|
<td .table__th>#{showDiffDays (ciMax corrMapSum)}
|
||||||
|
$# Always iterate over orderedSheetNames for consistent sorting! Newest first, except in this table
|
||||||
|
$forall shn <- orderedSheetNames
|
||||||
|
$maybe CorrectionInfo{ciSubmissions} <- Map.lookup shn sheetMap
|
||||||
|
<td .table__th>#{getLoadSum shn}
|
||||||
|
<td .table__th>#{ciSubmissions}
|
||||||
|
<td .table__td colspan=3>^{simpleLinkI (SomeMessage MsgMenuCorrectorsChange) (CSheetR tid ssh csh shn SEditR)}
|
||||||
|
|
||||||
^{btnWdgt}
|
$if not (null assignment)
|
||||||
|
<tr .table__row>
|
||||||
|
<td>
|
||||||
|
<td colspan=2>
|
||||||
|
<td>
|
||||||
|
<td colspan=3>
|
||||||
|
$# Always iterate over orderedSheetNames for consistent sorting! Newest first, except in this table
|
||||||
|
$forall shn <- orderedSheetNames
|
||||||
|
<td .table__td colspan=5>
|
||||||
|
$maybe btnView <- sheetBtnViews !? shn
|
||||||
|
$if has (ix shn) assignment
|
||||||
|
^{fvWidget btnView}
|
||||||
|
|
||||||
|
<tr .table__row .table__row--head>
|
||||||
|
<td>
|
||||||
|
<td colspan=2>
|
||||||
|
<td>
|
||||||
|
<td colspan=3>
|
||||||
|
$# Always iterate over orderedSheetNames for consistent sorting! Newest first, except in this table
|
||||||
|
$forall shn <- orderedSheetNames
|
||||||
|
<td .table__th colspan=5>
|
||||||
|
^{simpleLink (toWidget shn) (CSheetR tid ssh csh shn SShowR)}
|
||||||
|
|
||||||
|
<p .explanation>
|
||||||
|
_{MsgAssignSubmissionsRandomWarning}
|
||||||
|
|
||||||
|
$if not (null assignment)
|
||||||
|
$maybe btnView <- btnViews !? Nothing
|
||||||
|
<section>
|
||||||
|
<p>
|
||||||
|
_{MsgAssignSubmissionsAssignableSheets}
|
||||||
|
<div .corrections-overview__section>
|
||||||
|
<ul>
|
||||||
|
$forall shn <- assignSheetNames'
|
||||||
|
<li>
|
||||||
|
<a href=@{CSheetR tid ssh csh shn SShowR}>
|
||||||
|
#{shn}
|
||||||
|
<p>
|
||||||
|
^{fvWidget btnView}
|
||||||
|
|
||||||
<section>
|
|
||||||
<p>_{MsgAssignSubmissionsRandomWarning}
|
|
||||||
|
|||||||
Reference in New Issue
Block a user