feat(allocations): explanations & introduce grade-ordinal-proportion
BREAKING CHANGE: influence of grades on allocation priority now relative when priorities are ordinal
This commit is contained in:
parent
6bca64cf5f
commit
ee2e504ffa
@ -143,9 +143,10 @@ user-defaults:
|
|||||||
# This encodes the weight of the lecturer ratings on the same scale as the
|
# This encodes the weight of the lecturer ratings on the same scale as the
|
||||||
# centrally supplied priorities.
|
# centrally supplied priorities.
|
||||||
allocation-grade-scale: 25
|
allocation-grade-scale: 25
|
||||||
# This encodes how many ordinal places lecturer ratings may move students up or
|
# This encodes, as a proportion of the number of places, how many
|
||||||
# down when central priorities are supplied as ordered list.
|
# ordinal places lecturer ratings may move students up or down when
|
||||||
allocation-grade-ordinal-places: 3
|
# central priorities are supplied as ordered list.
|
||||||
|
allocation-grade-ordinal-proportion: 0.075
|
||||||
|
|
||||||
instance-id: "_env:INSTANCE_ID:instance"
|
instance-id: "_env:INSTANCE_ID:instance"
|
||||||
ribbon: "_env:RIBBON:"
|
ribbon: "_env:RIBBON:"
|
||||||
|
|||||||
@ -472,6 +472,10 @@ ul.list--inline
|
|||||||
.deflist__dt
|
.deflist__dt
|
||||||
font-weight: 600
|
font-weight: 600
|
||||||
|
|
||||||
|
.deflist__explanation
|
||||||
|
color: var(--color-fontsec)
|
||||||
|
font-size: 0.9rem
|
||||||
|
|
||||||
.deflist__dd
|
.deflist__dd
|
||||||
font-size: 18px
|
font-size: 18px
|
||||||
margin-bottom: 10px
|
margin-bottom: 10px
|
||||||
|
|||||||
@ -2370,3 +2370,4 @@ AllocationPrioritiesTitle tid@TermId ssh@SchoolId ash@AllocationShorthand: #{tid
|
|||||||
AllocationPrioritiesFile: CSV-Datei
|
AllocationPrioritiesFile: CSV-Datei
|
||||||
AllocationPrioritiesSunk num@Int64: Zentrale Prioritäten für #{num} Bewerber erfolgreich hinterlegt
|
AllocationPrioritiesSunk num@Int64: Zentrale Prioritäten für #{num} Bewerber erfolgreich hinterlegt
|
||||||
AllocationPrioritiesMissing num@Int64: Für #{num} Bewerber ist keine zentrale Priorität hinterlegt, da in der hochgeladenen CSV-Datei die #{pluralDE num "entsprechende Matrikelnummer" "entsprechenden Matrikelnummern"} nicht gefunden #{pluralDE num "wurde" "wurden"}
|
AllocationPrioritiesMissing num@Int64: Für #{num} Bewerber ist keine zentrale Priorität hinterlegt, da in der hochgeladenen CSV-Datei die #{pluralDE num "entsprechende Matrikelnummer" "entsprechenden Matrikelnummern"} nicht gefunden #{pluralDE num "wurde" "wurden"}
|
||||||
|
AllocationMissingPrioritiesIgnored: Bewerber, für die keine zentrale Priorität angegeben wird, werden bei der Vergabe ignoriert!
|
||||||
@ -3028,7 +3028,7 @@ pageActions (AllocationR tid ssh ash AUsersR) = return
|
|||||||
{ navLabel = MsgMenuAllocationPriorities
|
{ navLabel = MsgMenuAllocationPriorities
|
||||||
, navRoute = AllocationR tid ssh ash APriosR
|
, navRoute = AllocationR tid ssh ash APriosR
|
||||||
, navAccess' = return True
|
, navAccess' = return True
|
||||||
, navType = NavTypeLink { navModal = True }
|
, navType = NavTypeLink { navModal = False }
|
||||||
, navQuick' = mempty
|
, navQuick' = mempty
|
||||||
, navForceActive = False
|
, navForceActive = False
|
||||||
}
|
}
|
||||||
|
|||||||
@ -49,8 +49,10 @@ postAPriosR tid ssh ash = do
|
|||||||
AllocationPrioritiesNumeric -> return $(i18nWidgetFile "allocation-priority-explanation/numeric")
|
AllocationPrioritiesNumeric -> return $(i18nWidgetFile "allocation-priority-explanation/numeric")
|
||||||
AllocationPrioritiesOrdinal -> return $(i18nWidgetFile "allocation-priority-explanation/ordinal")
|
AllocationPrioritiesOrdinal -> return $(i18nWidgetFile "allocation-priority-explanation/ordinal")
|
||||||
|
|
||||||
|
ignoreWarningMsg <- messageIconI Warning IconMissingAllocationPriority MsgAllocationMissingPrioritiesIgnored
|
||||||
((priosRes, priosView), priosEnctype) <- runFormPost . renderAForm FormStandard $ (,)
|
((priosRes, priosView), priosEnctype) <- runFormPost . renderAForm FormStandard $ (,)
|
||||||
<$> apopt (explainedSelectionField Nothing (explainOptionList optionsFinite explainAllocationPrioMode)) (fslI MsgAllocationPrioritiesMode) (Just $ bool AllocationPrioritiesOrdinal AllocationPrioritiesNumeric doNumericPrios)
|
<$> apopt (explainedSelectionField Nothing (explainOptionList optionsFinite explainAllocationPrioMode)) (fslI MsgAllocationPrioritiesMode) (Just $ bool AllocationPrioritiesOrdinal AllocationPrioritiesNumeric doNumericPrios)
|
||||||
|
<* aformMessage ignoreWarningMsg
|
||||||
<*> areq fileField (fslI MsgAllocationPrioritiesFile) Nothing
|
<*> areq fileField (fslI MsgAllocationPrioritiesFile) Nothing
|
||||||
|
|
||||||
formResult priosRes $ \(mode, fInfo) -> do
|
formResult priosRes $ \(mode, fInfo) -> do
|
||||||
@ -76,7 +78,11 @@ postAPriosR tid ssh ash = do
|
|||||||
siteLayoutMsg MsgMenuAllocationPriorities $ do
|
siteLayoutMsg MsgMenuAllocationPriorities $ do
|
||||||
setTitleI $ MsgAllocationPrioritiesTitle tid ssh ash
|
setTitleI $ MsgAllocationPrioritiesTitle tid ssh ash
|
||||||
|
|
||||||
wrapForm priosView def
|
let priosForm = wrapForm priosView def
|
||||||
{ formEncoding = priosEnctype
|
{ formEncoding = priosEnctype
|
||||||
, formAction = Just . SomeRoute $ AllocationR tid ssh ash APriosR
|
, formAction = Just . SomeRoute $ AllocationR tid ssh ash APriosR
|
||||||
}
|
}
|
||||||
|
gradeScale <- getsYesod $ view _appAllocationGradeScale
|
||||||
|
gradeOrdinalProportion <- getsYesod $ view _appAllocationGradeOrdinalProportion
|
||||||
|
|
||||||
|
$(i18nWidgetFile "allocation-priorities")
|
||||||
|
|||||||
@ -10,7 +10,7 @@ import Handler.Utils
|
|||||||
import Handler.Utils.Allocation
|
import Handler.Utils.Allocation
|
||||||
|
|
||||||
import qualified Database.Esqueleto as E
|
import qualified Database.Esqueleto as E
|
||||||
import qualified Database.Esqueleto.Utils.TH as E
|
import qualified Database.Esqueleto.Utils as E
|
||||||
|
|
||||||
import qualified Data.Csv as Csv
|
import qualified Data.Csv as Csv
|
||||||
|
|
||||||
@ -103,11 +103,15 @@ instance CsvColumnsExplained AllocationUserTableCsv where
|
|||||||
getAUsersR, postAUsersR :: TermId -> SchoolId -> AllocationShorthand -> Handler Html
|
getAUsersR, postAUsersR :: TermId -> SchoolId -> AllocationShorthand -> Handler Html
|
||||||
getAUsersR = postAUsersR
|
getAUsersR = postAUsersR
|
||||||
postAUsersR tid ssh ash = do
|
postAUsersR tid ssh ash = do
|
||||||
usersTable <- runDB $ do
|
(usersTable, missingPriorities) <- runDB $ do
|
||||||
Entity aId _ <- getBy404 $ TermSchoolAllocationShort tid ssh ash
|
Entity aId _ <- getBy404 $ TermSchoolAllocationShort tid ssh ash
|
||||||
now <- liftIO getCurrentTime
|
now <- liftIO getCurrentTime
|
||||||
resultsDone <- (<= NTop (Just now)) . NTop <$> allocationDone aId
|
resultsDone <- (<= NTop (Just now)) . NTop <$> allocationDone aId
|
||||||
|
|
||||||
|
missingPriorities <- E.selectExists . E.from $ \allocationUser ->
|
||||||
|
E.where_ $ allocationUser E.^. AllocationUserAllocation E.==. E.val aId
|
||||||
|
E.&&. E.isNothing (allocationUser E.^. AllocationUserPriority)
|
||||||
|
|
||||||
csvName <- getMessageRender <*> pure (MsgAllocationUsersCsvName tid ssh ash)
|
csvName <- getMessageRender <*> pure (MsgAllocationUsersCsvName tid ssh ash)
|
||||||
|
|
||||||
let
|
let
|
||||||
@ -220,9 +224,12 @@ postAUsersR tid ssh ash = do
|
|||||||
& defaultSorting [SortAscBy "priority", SortAscBy "user-matriculation"]
|
& defaultSorting [SortAscBy "priority", SortAscBy "user-matriculation"]
|
||||||
& defaultPagesize PagesizeAll
|
& defaultPagesize PagesizeAll
|
||||||
|
|
||||||
dbTableDB' allocationUsersDBTableValidator allocationUsersDBTable
|
usersTable <- dbTableDB' allocationUsersDBTableValidator allocationUsersDBTable
|
||||||
|
return (usersTable, missingPriorities)
|
||||||
|
|
||||||
siteLayoutMsg MsgMenuAllocationUsers $ do
|
siteLayoutMsg MsgMenuAllocationUsers $ do
|
||||||
setTitleI $ MsgAllocationUsersTitle tid ssh ash
|
setTitleI $ MsgAllocationUsersTitle tid ssh ash
|
||||||
|
|
||||||
|
when missingPriorities $
|
||||||
|
notification NotificationBroad =<< messageIconI Warning IconMissingAllocationPriority MsgAllocationMissingPrioritiesIgnored
|
||||||
usersTable
|
usersTable
|
||||||
|
|||||||
@ -119,7 +119,13 @@ computeAllocation allocId cRestr = do
|
|||||||
return ((courseApplicationUser, courseApplicationCourse), (courseApplicationAllocationPriority, courseApplicationRatingPoints))
|
return ((courseApplicationUser, courseApplicationCourse), (courseApplicationAllocationPriority, courseApplicationRatingPoints))
|
||||||
|
|
||||||
gradeScale <- getsYesod $ view _appAllocationGradeScale
|
gradeScale <- getsYesod $ view _appAllocationGradeScale
|
||||||
gradeOrdinalPlaces <- getsYesod $ view _appAllocationGradeOrdinalPlaces
|
gradeOrdinalProportion <- getsYesod $ view _appAllocationGradeOrdinalProportion
|
||||||
|
let ordinalUsers = getSum . flip foldMap users'' $ \(_, prio) -> case prio of
|
||||||
|
AllocationPriorityOrdinal{} -> Sum 1
|
||||||
|
_other -> mempty
|
||||||
|
gradeOrdinalPlaces :: Natural
|
||||||
|
gradeOrdinalPlaces = round . abs $ ordinalUsers * gradeOrdinalProportion
|
||||||
|
|
||||||
let centralNudge user cloneIndex grade = case allocationPrio user of
|
let centralNudge user cloneIndex grade = case allocationPrio user of
|
||||||
AllocationPriorityNumeric{..}
|
AllocationPriorityNumeric{..}
|
||||||
-> let allocationPriorities' = under vector (sortOn Down) allocationPriorities
|
-> let allocationPriorities' = under vector (sortOn Down) allocationPriorities
|
||||||
|
|||||||
@ -125,8 +125,8 @@ data AppSettings = AppSettings
|
|||||||
|
|
||||||
, appTransactionLogIPRetentionTime :: NominalDiffTime
|
, appTransactionLogIPRetentionTime :: NominalDiffTime
|
||||||
|
|
||||||
, appAllocationGradeScale :: Rational
|
, appAllocationGradeScale
|
||||||
, appAllocationGradeOrdinalPlaces :: Natural
|
, appAllocationGradeOrdinalProportion :: Rational
|
||||||
|
|
||||||
, appReloadTemplates :: Bool
|
, appReloadTemplates :: Bool
|
||||||
-- ^ Use the reload version of templates
|
-- ^ Use the reload version of templates
|
||||||
@ -423,7 +423,7 @@ instance FromJSON AppSettings where
|
|||||||
appTransactionLogIPRetentionTime <- o .: "ip-retention-time"
|
appTransactionLogIPRetentionTime <- o .: "ip-retention-time"
|
||||||
|
|
||||||
appAllocationGradeScale <- o .: "allocation-grade-scale" <|> fmap toRational (o .: "allocation-grade-scale" :: Aeson.Parser Scientific)
|
appAllocationGradeScale <- o .: "allocation-grade-scale" <|> fmap toRational (o .: "allocation-grade-scale" :: Aeson.Parser Scientific)
|
||||||
appAllocationGradeOrdinalPlaces <- o .: "allocation-grade-ordinal-places"
|
appAllocationGradeOrdinalProportion <- o .: "allocation-grade-ordinal-proportion" <|> fmap toRational (o .: "allocation-grade-ordinal-proportion" :: Aeson.Parser Scientific)
|
||||||
|
|
||||||
appUserDefaults <- o .: "user-defaults"
|
appUserDefaults <- o .: "user-defaults"
|
||||||
appAuthPWHash <- o .: "auth-pw-hash"
|
appAuthPWHash <- o .: "auth-pw-hash"
|
||||||
|
|||||||
@ -82,6 +82,7 @@ data Icon
|
|||||||
| IconMenuAdmin
|
| IconMenuAdmin
|
||||||
| IconPageActionPrimaryExpand | IconPageActionSecondary
|
| IconPageActionPrimaryExpand | IconPageActionSecondary
|
||||||
| IconBreadcrumbSeparator
|
| IconBreadcrumbSeparator
|
||||||
|
| IconMissingAllocationPriority
|
||||||
deriving (Eq, Ord, Enum, Bounded, Show, Read, Generic, Typeable)
|
deriving (Eq, Ord, Enum, Bounded, Show, Read, Generic, Typeable)
|
||||||
|
|
||||||
iconText :: Icon -> Text
|
iconText :: Icon -> Text
|
||||||
@ -142,6 +143,7 @@ iconText = \case
|
|||||||
IconPageActionPrimaryExpand -> "bars"
|
IconPageActionPrimaryExpand -> "bars"
|
||||||
IconPageActionSecondary -> "ellipsis-h"
|
IconPageActionSecondary -> "ellipsis-h"
|
||||||
IconBreadcrumbSeparator -> "angle-right"
|
IconBreadcrumbSeparator -> "angle-right"
|
||||||
|
IconMissingAllocationPriority -> "empty-set"
|
||||||
|
|
||||||
instance Universe Icon
|
instance Universe Icon
|
||||||
instance Finite Icon
|
instance Finite Icon
|
||||||
|
|||||||
@ -6,7 +6,7 @@ module Utils.Message
|
|||||||
, addMessage, addMessageI, addMessageIHamlet, addMessageFile, addMessageWidget
|
, addMessage, addMessageI, addMessageIHamlet, addMessageFile, addMessageWidget
|
||||||
, statusToUrgencyClass
|
, statusToUrgencyClass
|
||||||
, Message(..)
|
, Message(..)
|
||||||
, messageIconI, messageIconIHamlet, messageIconWidget
|
, messageIconI, messageIconIHamlet, messageIconFile, messageIconWidget
|
||||||
, messageI, messageIHamlet, messageFile, messageWidget, messageTooltip
|
, messageI, messageIHamlet, messageFile, messageWidget, messageTooltip
|
||||||
) where
|
) where
|
||||||
|
|
||||||
@ -178,6 +178,9 @@ addMessageFile mc tPath = [e|addMessageIHamlet mc $(ihamletFile tPath)|]
|
|||||||
messageFile :: MessageStatus -> FilePath -> ExpQ
|
messageFile :: MessageStatus -> FilePath -> ExpQ
|
||||||
messageFile mc tPath = [e|messageIHamlet mc $(ihamletFile tPath)|]
|
messageFile mc tPath = [e|messageIHamlet mc $(ihamletFile tPath)|]
|
||||||
|
|
||||||
|
messageIconFile :: MessageStatus -> Icon -> FilePath -> ExpQ
|
||||||
|
messageIconFile mc mi tPath = [e|messageIHamlet mc mi $(ihamletFile tPath)|]
|
||||||
|
|
||||||
addMessageWidget :: forall m site.
|
addMessageWidget :: forall m site.
|
||||||
( MonadHandler m
|
( MonadHandler m
|
||||||
, HandlerSite m ~ site
|
, HandlerSite m ~ site
|
||||||
|
|||||||
23
templates/i18n/allocation-priorities/de-de-formal.hamlet
Normal file
23
templates/i18n/allocation-priorities/de-de-formal.hamlet
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
$newline never
|
||||||
|
<section>
|
||||||
|
^{priosForm}
|
||||||
|
<section>
|
||||||
|
<dl .deflist>
|
||||||
|
<dt .deflist__dt>
|
||||||
|
Einfluss von Bewertungen bei numerischen Dringlichkeiten
|
||||||
|
<p .deflist__explanation>
|
||||||
|
Dozenten können, durch Hinterlegen von Bewertungen, die Vergabe #
|
||||||
|
in einem Maße beeinflussen, das einer Abweichung der #
|
||||||
|
zentralen Dringlichkeit um plus bzw. minus diesen Wert, #
|
||||||
|
entspricht.
|
||||||
|
<dd .deflist__dd>
|
||||||
|
#{rationalToFixed2 gradeScale}
|
||||||
|
<dt .deflist__dt>
|
||||||
|
Einfluss von Bewertungen bei Dringlichkeiten durch Sortierung
|
||||||
|
<p .deflist__explanation>
|
||||||
|
Dozenten können, durch Hinterlegen von Bewertungen, die #
|
||||||
|
Vergabe in einem Maße beeinflussen, das einer Verschiebung des #
|
||||||
|
Bewerbers (auf- bzw. abwärts) um diese Proportion, in der nach #
|
||||||
|
Dringlichkeit sortierten Bewerberliste, entspricht.
|
||||||
|
<dd .deflist__dd>
|
||||||
|
#{textPercent gradeOrdinalProportion 1}
|
||||||
@ -9,10 +9,15 @@ Alle weiteren Spalten werden als ganze Zahlen interpretiert und #
|
|||||||
kodieren die jeweilige zentrale Dringlichkeit bei der Vergabe der #
|
kodieren die jeweilige zentrale Dringlichkeit bei der Vergabe der #
|
||||||
Plätze. #
|
Plätze. #
|
||||||
|
|
||||||
Hierbei wird die erste Dringlichkeits-Spalte verwendet zur Vergabe des #
|
Größere Zahlen kodieren eine höhere Dringlichkeit. #
|
||||||
jeweils ersten Platzes, die zweite Spalte für den zweiten Platz, usw. #
|
|
||||||
|
|
||||||
Größere Zahlen kodieren eine höhere Dringlichkeit.
|
Hierbei wird die höchste der jeweiligen Dringlichkeiten verwendet zur #
|
||||||
|
Vergabe des jeweils ersten Platzes, die nächst niedrigere für den #
|
||||||
|
zweiten Platz, usw.. #
|
||||||
|
|
||||||
|
Werden für einen Bewerber mehr Plätze in Betracht gezogen, als #
|
||||||
|
Dringlichkeiten für ihn angegeben wurden, so wird hierfür die #
|
||||||
|
niedrigste Dringlichkeit verwendet.
|
||||||
|
|
||||||
<br />
|
<br />
|
||||||
|
|
||||||
|
|||||||
@ -9,8 +9,11 @@ Die zentrale Dringlichkeit ergibt sich ausschließlich anhand der #
|
|||||||
Sortierung der CSV-Datei. #
|
Sortierung der CSV-Datei. #
|
||||||
|
|
||||||
Bewerber, deren Matrikelnummer später in der Datei vorkommt, erhalten #
|
Bewerber, deren Matrikelnummer später in der Datei vorkommt, erhalten #
|
||||||
für alle ihre Plätze eine höhere Dringlichkeit, als Bewerber, deren #
|
eine höhere Dringlichkeit, als Bewerber, deren Matrikelnummern in der #
|
||||||
Matrikelnummern in der Datei früher vorkommen. #
|
Datei früher vorkommen. #
|
||||||
|
|
||||||
|
Für ihren zweiten Platz haben alle Bewerber eine niedrigere #
|
||||||
|
Dringlichkeit als andere Bewerber für ihren ersten Platz, usw..
|
||||||
|
|
||||||
<br />
|
<br />
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user