StudyTermCandidates Deletion Buttons

This commit is contained in:
Steffen Jost 2019-03-29 15:24:16 +01:00
parent 7d2dd2efea
commit df0b36a01b
5 changed files with 64 additions and 23 deletions

View File

@ -5,6 +5,9 @@ BtnRegister: Anmelden
BtnDeregister: Abmelden BtnDeregister: Abmelden
BtnHijack: Sitzung übernehmen BtnHijack: Sitzung übernehmen
BtnSave: Speichern BtnSave: Speichern
BtnCandidatesInfer: Studienfachzuordnung automatisch lernen
BtnCandidatesDeleteConflicts: Konflikte löschen
BtnCandidatesDeleteAll: Alle Beobachtungen löschen
Aborted: Abgebrochen Aborted: Abgebrochen
Remarks: Hinweise Remarks: Hinweise
@ -15,6 +18,11 @@ RegisterFrom: Anmeldungen von
RegisterTo: Anmeldungen bis RegisterTo: Anmeldungen bis
DeRegUntil: Abmeldungen bis DeRegUntil: Abmeldungen bis
GenericKey: Schlüssel
GenericShort: Kürzel
GenericIsNew: Neu
GenericHasConflict: Konflikt
SummerTerm year@Integer: Sommersemester #{display year} SummerTerm year@Integer: Sommersemester #{display year}
WinterTerm year@Integer: Wintersemester #{display year}/#{display $ succ year} WinterTerm year@Integer: Wintersemester #{display year}/#{display $ succ year}
SummerTermShort year@Integer: SoSe #{display year} SummerTermShort year@Integer: SoSe #{display year}
@ -439,10 +447,10 @@ StudyFeatureType:
StudyFeatureValid: Aktiv StudyFeatureValid: Aktiv
StudyFeatureUpdate: Abgeglichen StudyFeatureUpdate: Abgeglichen
DegreeKey: Schlüssel Abschluss DegreeKey: Abschlussschlüssel
DegreeName: Abschluss DegreeName: Abschluss
DegreeShort: Abschlusskürzel DegreeShort: Abschlusskürzel
StudyTermsKey: Schlüssel Studiengang StudyTermsKey: Studiengangschlüssel
StudyTermsName: Studiengang StudyTermsName: Studiengang
StudyTermsShort: Studiengangkürzel StudyTermsShort: Studiengangkürzel
StudyTermsChangeSuccess: Zuordnung Abschlüsse aktualisiert StudyTermsChangeSuccess: Zuordnung Abschlüsse aktualisiert
@ -452,6 +460,8 @@ AmbiguousCandidatesRemoved n@Int: #{show n} #{pluralDE n "uneindeutiger Kandidat
RedundantCandidatesRemoved n@Int: #{show n} bereits #{pluralDE n "bekannter Kandidat" "bekannte Kandiaten"} entfernt RedundantCandidatesRemoved n@Int: #{show n} bereits #{pluralDE n "bekannter Kandidat" "bekannte Kandiaten"} entfernt
CandidatesInferred n@Int: #{show n} neue #{pluralDE n "Studiengangszuordnung" "Studiengangszuordnungen"} inferiert CandidatesInferred n@Int: #{show n} neue #{pluralDE n "Studiengangszuordnung" "Studiengangszuordnungen"} inferiert
NoCandidatesInferred: Keine neuen Studienganszuordnungen inferiert NoCandidatesInferred: Keine neuen Studienganszuordnungen inferiert
AllIncidencesDeleted: Alle Beobachtungen wurden gelöscht.
IncidencesDeleted n@Int: #{show n} #{pluralDE n "Beobachtung" "Beobachtungen"} gelöscht
StudyTermIsNew: Neu StudyTermIsNew: Neu
StudyFeatureConflict: Es wurden Konflikte in der Studiengang-Zuordnung gefunden StudyFeatureConflict: Es wurden Konflikte in der Studiengang-Zuordnung gefunden

View File

@ -204,7 +204,7 @@ postAdminTestR = do
buttonAction frag = Just . SomeRoute $ AdminTestR :#: frag buttonAction frag = Just . SomeRoute $ AdminTestR :#: frag
-- The actual call to @massInput@ is comparatively simple: -- The actual call to @massInput@ is comparatively simple:
((miResult, fvInput -> miForm), miEnc) <- runFormPost . identifyForm ("massinput" :: Text) $ massInput (MassInput mkAddForm mkCellForm deleteCell allowAdd buttonAction) "" True Nothing ((miResult, fvInput -> miForm), miEnc) <- runFormPost . identifyForm ("massinput" :: Text) $ massInput (MassInput mkAddForm mkCellForm deleteCell allowAdd buttonAction) "" True Nothing
@ -269,29 +269,34 @@ postAdminErrMsgR = do
-- BEGIN - Buttons needed only for StudyTermCandidateManagement -- BEGIN - Buttons needed only for StudyTermCandidateManagement
data ButtonInferStudyTerms = ButtonInferStudyTerms data ButtonAdminStudyTerms
= BtnCandidatesInfer
| BtnCandidatesDeleteConflicts
| BtnCandidatesDeleteAll
deriving (Enum, Eq, Ord, Bounded, Read, Show, Generic, Typeable) deriving (Enum, Eq, Ord, Bounded, Read, Show, Generic, Typeable)
instance Universe ButtonInferStudyTerms instance Universe ButtonAdminStudyTerms
instance Finite ButtonInferStudyTerms instance Finite ButtonAdminStudyTerms
nullaryPathPiece ''ButtonInferStudyTerms camelToPathPiece nullaryPathPiece ''ButtonAdminStudyTerms camelToPathPiece
embedRenderMessage ''UniWorX ''ButtonAdminStudyTerms id
instance Button UniWorX ButtonInferStudyTerms where instance Button UniWorX ButtonAdminStudyTerms where
btnLabel ButtonInferStudyTerms = "Studienfachzuordnung automatisch lernen" btnClasses BtnCandidatesInfer = [BCIsButton, BCPrimary]
btnClasses ButtonInferStudyTerms = [BCIsButton, BCPrimary] btnClasses BtnCandidatesDeleteConflicts = [BCIsButton, BCDanger]
btnClasses BtnCandidatesDeleteAll = [BCIsButton, BCDanger]
-- END Button needed only here -- END Button needed only here
getAdminFeaturesR, postAdminFeaturesR :: Handler Html getAdminFeaturesR, postAdminFeaturesR :: Handler Html
getAdminFeaturesR = postAdminFeaturesR getAdminFeaturesR = postAdminFeaturesR
postAdminFeaturesR = do postAdminFeaturesR = do
((btnResult, btnWdgt), btnEnctype) <- runFormPost $ identifyForm ("infer-button" :: Text) (buttonForm :: Form ButtonInferStudyTerms) ((btnResult, btnWdgt), btnEnctype) <- runFormPost $ identifyForm ("infer-button" :: Text) (buttonForm :: Form ButtonAdminStudyTerms)
let btnForm = wrapForm btnWdgt def let btnForm = wrapForm btnWdgt def
{ formAction = Just $ SomeRoute AdminFeaturesR { formAction = Just $ SomeRoute AdminFeaturesR
, formEncoding = btnEnctype , formEncoding = btnEnctype
, formSubmit = FormNoSubmit , formSubmit = FormNoSubmit
} }
(infConflicts,infAccepted) <- case btnResult of (infConflicts,infAccepted) <- case btnResult of
FormSuccess ButtonInferStudyTerms -> do FormSuccess BtnCandidatesInfer -> do
(infConflicts, infAmbiguous, infRedundant, infAccepted) <- Candidates.inferHandler (infConflicts, infAmbiguous, infRedundant, infAccepted) <- Candidates.inferHandler
unless (null infAmbiguous) . addMessageI Info . MsgAmbiguousCandidatesRemoved $ length infAmbiguous unless (null infAmbiguous) . addMessageI Info . MsgAmbiguousCandidatesRemoved $ length infAmbiguous
unless (null infRedundant) . addMessageI Info . MsgRedundantCandidatesRemoved $ length infRedundant unless (null infRedundant) . addMessageI Info . MsgRedundantCandidatesRemoved $ length infRedundant
@ -301,6 +306,16 @@ postAdminFeaturesR = do
| otherwise | otherwise
-> addMessageI Success . MsgCandidatesInferred $ length infAccepted -> addMessageI Success . MsgCandidatesInferred $ length infAccepted
return (infConflicts, infAccepted) return (infConflicts, infAccepted)
FormSuccess BtnCandidatesDeleteConflicts -> runDB $ do
confs <- Candidates.conflicts
incis <- Candidates.getIncidencesFor (entityKey <$> confs)
deleteWhere [StudyTermCandidateIncidence <-. (E.unValue <$> incis)]
addMessageI Success $ MsgIncidencesDeleted $ length incis
return ([],[])
FormSuccess BtnCandidatesDeleteAll -> runDB $ do
deleteWhere ([] :: [Filter StudyTermCandidate])
addMessageI Success MsgAllIncidencesDeleted
(, []) <$> Candidates.conflicts
_other -> (, []) <$> runDB Candidates.conflicts _other -> (, []) <$> runDB Candidates.conflicts
( (degreeResult,degreeTable) ( (degreeResult,degreeTable)
@ -308,6 +323,7 @@ postAdminFeaturesR = do
, ((), candidateTable)) <- runDB $ (,,) , ((), candidateTable)) <- runDB $ (,,)
<$> mkDegreeTable <$> mkDegreeTable
<*> mkStudytermsTable (Set.fromList $ map (StudyTermsKey' . fst) infAccepted) <*> mkStudytermsTable (Set.fromList $ map (StudyTermsKey' . fst) infAccepted)
(Set.fromList $ map entityKey infConflicts)
<*> mkCandidateTable <*> mkCandidateTable
-- This needs to happen after calls to `dbTable` so they can short-circuit correctly -- This needs to happen after calls to `dbTable` so they can short-circuit correctly
@ -352,7 +368,7 @@ postAdminFeaturesR = do
dbtRowKey = (E.^. StudyDegreeKey) dbtRowKey = (E.^. StudyDegreeKey)
dbtProj = return dbtProj = return
dbtColonnade = formColonnade $ mconcat dbtColonnade = formColonnade $ mconcat
[ sortable (Just "key") (i18nCell MsgDegreeKey) (numCell . view (_dbrOutput . _entityVal . _studyDegreeKey)) [ sortable (Just "key") (i18nCell MsgGenericKey) (numCell . view (_dbrOutput . _entityVal . _studyDegreeKey))
, sortable (Just "name") (i18nCell MsgDegreeName) (textInputCell _1 (_dbrOutput . _entityVal . _studyDegreeName)) , sortable (Just "name") (i18nCell MsgDegreeName) (textInputCell _1 (_dbrOutput . _entityVal . _studyDegreeName))
, sortable (Just "short") (i18nCell MsgDegreeShort) (textInputCell _2 (_dbrOutput . _entityVal . _studyDegreeShorthand)) , sortable (Just "short") (i18nCell MsgDegreeShort) (textInputCell _2 (_dbrOutput . _entityVal . _studyDegreeShorthand))
, dbRow , dbRow
@ -366,11 +382,12 @@ postAdminFeaturesR = do
dbtFilterUI = mempty dbtFilterUI = mempty
dbtParams = def { dbParamsFormAction = Just . SomeRoute $ AdminFeaturesR :#: ("admin-studydegrees-table-wrapper" :: Text) dbtParams = def { dbParamsFormAction = Just . SomeRoute $ AdminFeaturesR :#: ("admin-studydegrees-table-wrapper" :: Text)
} }
psValidator = def & defaultSorting [SortAscBy "name", SortAscBy "short", SortAscBy "key"] psValidator = def -- & defaultSorting [SortAscBy "name", SortAscBy "short", SortAscBy "key"]
& defaultSorting [SortAscBy "key"]
in dbTable psValidator DBTable{..} in dbTable psValidator DBTable{..}
mkStudytermsTable :: Set (Key StudyTerms) -> DB (FormResult (DBFormResult (Key StudyTerms) (Maybe Text, Maybe Text) (DBRow (Entity StudyTerms))), Widget) mkStudytermsTable :: Set (Key StudyTerms) -> Set (Key StudyTerms) -> DB (FormResult (DBFormResult (Key StudyTerms) (Maybe Text, Maybe Text) (DBRow (Entity StudyTerms))), Widget)
mkStudytermsTable newKeys = mkStudytermsTable newKeys badKeys =
let dbtIdent = "admin-studyterms" :: Text let dbtIdent = "admin-studyterms" :: Text
dbtStyle = def dbtStyle = def
dbtSQLQuery :: E.SqlExpr (Entity StudyTerms) -> E.SqlQuery ( E.SqlExpr (Entity StudyTerms)) dbtSQLQuery :: E.SqlExpr (Entity StudyTerms) -> E.SqlQuery ( E.SqlExpr (Entity StudyTerms))
@ -378,15 +395,17 @@ postAdminFeaturesR = do
dbtRowKey = (E.^. StudyTermsKey) dbtRowKey = (E.^. StudyTermsKey)
dbtProj = return dbtProj = return
dbtColonnade = formColonnade $ mconcat dbtColonnade = formColonnade $ mconcat
[ sortable (Just "key") (i18nCell MsgStudyTermsKey) (numCell . view (_dbrOutput . _entityVal . _studyTermsKey)) [ sortable (Just "key") (i18nCell MsgGenericKey) (numCell . view (_dbrOutput . _entityVal . _studyTermsKey))
, sortable (Just "isnew") (i18nCell MsgStudyTermIsNew) (isNewCell . flip Set.member newKeys . view (_dbrOutput . _entityKey)) , sortable (Just "isnew") (i18nCell MsgGenericIsNew) (isNewCell . flip Set.member newKeys . view (_dbrOutput . _entityKey))
, sortable (Just "name") (i18nCell MsgStudyTermsName) (textInputCell _1 (_dbrOutput . _entityVal . _studyTermsName)) , sortable (Just "isbad") (i18nCell MsgGenericHasConflict) (isBadCell . flip Set.member badKeys . view (_dbrOutput . _entityKey))
, sortable (Just "short") (i18nCell MsgStudyTermsShort) (textInputCell _2 (_dbrOutput . _entityVal . _studyTermsShorthand)) , sortable (Just "name") (i18nCell MsgStudyTermsName) (textInputCell _1 (_dbrOutput . _entityVal . _studyTermsName))
, sortable (Just "short") (i18nCell MsgStudyTermsShort) (textInputCell _2 (_dbrOutput . _entityVal . _studyTermsShorthand))
, dbRow , dbRow
] ]
dbtSorting = Map.fromList dbtSorting = Map.fromList
[ ("key" , SortColumn (E.^. StudyTermsKey)) [ ("key" , SortColumn (E.^. StudyTermsKey))
, ("isnew" , SortColumn (\studyTerm -> studyTerm E.^. StudyTermsId `E.in_` E.valList (Set.toList newKeys))) , ("isnew" , SortColumn (\studyTerm -> studyTerm E.^. StudyTermsId `E.in_` E.valList (Set.toList newKeys)))
, ("isbad" , SortColumn (\studyTerm -> studyTerm E.^. StudyTermsId `E.in_` E.valList (Set.toList badKeys)))
, ("name" , SortColumn (E.^. StudyTermsName)) , ("name" , SortColumn (E.^. StudyTermsName))
, ("short" , SortColumn (E.^. StudyTermsShorthand)) , ("short" , SortColumn (E.^. StudyTermsShorthand))
] ]

View File

@ -57,6 +57,10 @@ sqlCell act = mempty & cellContents .~ lift act
tickmarkCell :: (IsDBTable m a) => Bool -> DBCell m a tickmarkCell :: (IsDBTable m a) => Bool -> DBCell m a
tickmarkCell = cell . toWidget . hasTickmark tickmarkCell = cell . toWidget . hasTickmark
-- | Maybe display an icon for tainted rows
isBadCell :: (IsDBTable m a) => Bool -> DBCell m a
isBadCell = cell . toWidget . isBad
-- | Maybe display a exclamation icon -- | Maybe display a exclamation icon
isNewCell :: (IsDBTable m a) => Bool -> DBCell m a isNewCell :: (IsDBTable m a) => Bool -> DBCell m a
isNewCell = cell . toWidget . isNew isNewCell = cell . toWidget . isNew

View File

@ -180,5 +180,8 @@ conflicts = E.select $ E.from $ \studyTerms -> do
E.where_ $ studyTerms E.^. StudyTermsName E.==. E.just (candidateTwo E.^. StudyTermCandidateName) E.where_ $ studyTerms E.^. StudyTermsName E.==. E.just (candidateTwo E.^. StudyTermCandidateName)
return studyTerms return studyTerms
-- | retrieve all incidence keys having containing a certain @StudyTermKey @
getIncidencesFor :: [Key StudyTerms] -> DB [E.Value TermCandidateIncidence]
getIncidencesFor stks = E.select $ E.distinct $ E.from $ \candidate -> do
E.where_ $ candidate E.^. StudyTermCandidateKey `E.in_` E.valList (unStudyTermsKey <$> stks)
return $ candidate E.^. StudyTermCandidateIncidence

View File

@ -140,8 +140,13 @@ hasTickmark :: Bool -> Markup
hasTickmark True = [shamlet|<i .fas .fa-check>|] hasTickmark True = [shamlet|<i .fas .fa-check>|]
hasTickmark False = mempty hasTickmark False = mempty
isBad :: Bool -> Markup
-- ^ Display an icon that denotes that something™ is bad
isBad True = [shamlet|<i .fas .fa-bolt>|] -- or times?!
isBad False = mempty
isNew :: Bool -> Markup isNew :: Bool -> Markup
isNew True = [shamlet|<i .fas .fa-exclamation>|] isNew True = [shamlet|<i .fas .fa-seedling>|] -- was exclamation
isNew False = mempty isNew False = mempty