@@ -602,7 +602,9 @@ protected function assembleModeSelection(): string
602602 '24-7 ' => $ this ->translate ('24/7 ' )
603603 ];
604604
605- $ modeList = new HtmlElement ('ul ' );
605+ $ modeList = new HtmlElement ('ul ' , Attributes::create ([
606+ 'class ' => ['rotation-mode ' , $ this ->disableModeSelection ? 'disabled ' : '' ]
607+ ]));
606608 foreach ($ modes as $ mode => $ label ) {
607609 $ radio = $ this ->createElement ('input ' , 'mode ' , [
608610 'type ' => 'radio ' ,
@@ -684,8 +686,14 @@ protected function assembleModeSelection(): string
684686
685687 $ this ->addHtml (new HtmlElement (
686688 'div ' ,
687- Attributes::create (['class ' => ['rotation-mode ' , $ this ->disableModeSelection ? 'disabled ' : '' ]]),
688- new HtmlElement ('h2 ' , null , Text::create ($ this ->translate ('Mode ' ))),
689+ Attributes::create ([
690+ 'class ' => ['control-group ' ]
691+ ]),
692+ new HtmlElement (
693+ 'div ' ,
694+ Attributes::create (['class ' => 'control-label-group ' ]),
695+ Text::create ($ this ->translate ('Rotation Mode ' ))
696+ ),
689697 $ modeList
690698 ));
691699
@@ -704,6 +712,7 @@ protected function assembleTwentyFourSevenOptions(FieldsetElement $options): Dat
704712 $ options ->addElement ('number ' , 'interval ' , [
705713 'required ' => true ,
706714 'label ' => $ this ->translate ('Handoff every ' ),
715+ 'description ' => $ this ->translate ('Have multiple rotation members take turns after this interval. ' ),
707716 'step ' => 1 ,
708717 'min ' => 1 ,
709718 'value ' => 1 ,
@@ -796,6 +805,7 @@ protected function assemblePartialDayOptions(FieldsetElement $options): DateTime
796805 $ options ->addElement ('number ' , 'interval ' , [
797806 'required ' => true ,
798807 'label ' => $ this ->translate ('Handoff every ' ),
808+ 'description ' => $ this ->translate ('Have multiple rotation members take turns after this interval. ' ),
799809 'step ' => 1 ,
800810 'min ' => 1 ,
801811 'value ' => 1 ,
@@ -912,7 +922,8 @@ protected function assembleMultiDayOptions(FieldsetElement $options): DateTime
912922 'step ' => 1 ,
913923 'min ' => 1 ,
914924 'value ' => 1 ,
915- 'label ' => $ this ->translate ('Handoff every ' )
925+ 'label ' => $ this ->translate ('Handoff every ' ),
926+ 'description ' => $ this ->translate ('Have multiple rotation members take turns after this interval. ' )
916927 ]);
917928
918929 $ timeOptions = $ this ->getTimeOptions ();
@@ -1029,17 +1040,9 @@ protected function assemble()
10291040
10301041 $ this ->addElement ('hidden ' , 'priority ' , ['ignore ' => true ]);
10311042
1032- $ mode = $ this ->assembleModeSelection ();
1033-
1034- $ autoSubmittedBy = $ this ->getRequest ()->getHeader ('X-Icinga-Autosubmittedby ' )[0 ] ?? '' ;
1035- if ($ autoSubmittedBy === 'mode ' ) {
1036- $ this ->clearPopulatedValue ('options ' );
1037- $ this ->clearPopulatedValue ('first_handoff ' );
1038- }
1039-
10401043 $ this ->addElement ('text ' , 'name ' , [
10411044 'required ' => true ,
1042- 'label ' => $ this ->translate ('Title ' ),
1045+ 'label ' => $ this ->translate ('Rotation Name ' ),
10431046 'validators ' => [
10441047 new CallbackValidator (function ($ value , $ validator ) {
10451048 $ rotations = Rotation::on ($ this ->db )
@@ -1051,7 +1054,7 @@ protected function assemble()
10511054 }
10521055
10531056 if ($ rotations ->first () !== null ) {
1054- $ validator ->addMessage ($ this ->translate ('A rotation with this title already exists ' ));
1057+ $ validator ->addMessage ($ this ->translate ('A rotation with this name already exists ' ));
10551058
10561059 return false ;
10571060 }
@@ -1061,6 +1064,73 @@ protected function assemble()
10611064 ]
10621065 ]);
10631066
1067+ $ termValidator = function (array $ terms ) {
1068+ $ contactTerms = [];
1069+ $ groupTerms = [];
1070+ foreach ($ terms as $ term ) {
1071+ /** @var TermInput\Term $term */
1072+ if (strpos ($ term ->getSearchValue (), ': ' ) === false ) {
1073+ // TODO: Auto-correct this to a valid type:id pair, if possible
1074+ $ term ->setMessage ($ this ->translate ('Is not a contact nor a group of contacts ' ));
1075+ continue ;
1076+ }
1077+
1078+ list ($ type , $ id ) = explode (': ' , $ term ->getSearchValue (), 2 );
1079+ if ($ type === 'contact ' ) {
1080+ $ contactTerms [$ id ] = $ term ;
1081+ } elseif ($ type === 'group ' ) {
1082+ $ groupTerms [$ id ] = $ term ;
1083+ }
1084+ }
1085+
1086+ if (! empty ($ contactTerms )) {
1087+ $ contacts = (Contact::on (Database::get ()))
1088+ ->filter (Filter::equal ('id ' , array_keys ($ contactTerms )));
1089+ foreach ($ contacts as $ contact ) {
1090+ $ contactTerms [$ contact ->id ]
1091+ ->setLabel ($ contact ->full_name )
1092+ ->setClass ('contact ' );
1093+ }
1094+ }
1095+
1096+ if (! empty ($ groupTerms )) {
1097+ $ groups = (Contactgroup::on (Database::get ()))
1098+ ->filter (Filter::equal ('id ' , array_keys ($ groupTerms )));
1099+ foreach ($ groups as $ group ) {
1100+ $ groupTerms [$ group ->id ]
1101+ ->setLabel ($ group ->name )
1102+ ->setClass ('group ' );
1103+ }
1104+ }
1105+ };
1106+
1107+ $ members = (new TermInput ('members ' ))
1108+ ->setIgnored ()
1109+ ->setRequired ()
1110+ ->setOrdered ()
1111+ ->setReadOnly ()
1112+ ->setVerticalTermDirection ()
1113+ ->setLabel ($ this ->translate ('Rotation Members ' ))
1114+ ->setSuggestionUrl ($ this ->suggestionUrl ->with (['showCompact ' => true , '_disableLayout ' => 1 ]))
1115+ ->on (TermInput::ON_ENRICH , $ termValidator )
1116+ ->on (TermInput::ON_ADD , $ termValidator )
1117+ ->on (TermInput::ON_SAVE , $ termValidator )
1118+ ->on (TermInput::ON_PASTE , $ termValidator );
1119+ $ this ->addElement ($ members );
1120+
1121+ // TODO: TermInput is not compatible with the new decorators yet: https://github.com/Icinga/ipl-web/pull/317
1122+ $ legacyDecorator = new IcingaFormDecorator ();
1123+ $ members ->setDefaultElementDecorator ($ legacyDecorator );
1124+ $ legacyDecorator ->decorate ($ members );
1125+
1126+ $ mode = $ this ->assembleModeSelection ();
1127+
1128+ $ autoSubmittedBy = $ this ->getRequest ()->getHeader ('X-Icinga-Autosubmittedby ' )[0 ] ?? '' ;
1129+ if ($ autoSubmittedBy === 'mode ' ) {
1130+ $ this ->clearPopulatedValue ('options ' );
1131+ $ this ->clearPopulatedValue ('first_handoff ' );
1132+ }
1133+
10641134 $ this ->addElement ('fieldset ' , 'options ' );
10651135 /** @var FieldsetElement $options */
10661136 $ options = $ this ->getElement ('options ' );
@@ -1098,7 +1168,7 @@ protected function assemble()
10981168 'aria-describedby ' => 'first-handoff-description ' ,
10991169 'min ' => $ earliestHandoff !== null ? $ earliestHandoff ->format ('Y-m-d ' ) : null ,
11001170 'max ' => $ latestHandoff ->format ('Y-m-d ' ),
1101- 'label ' => $ this ->translate ('First Handoff ' ),
1171+ 'label ' => $ this ->translate ('Rotation Start ' ),
11021172 'value ' => $ firstHandoffDefault ,
11031173 'validators ' => [
11041174 new CallbackValidator (
@@ -1110,14 +1180,14 @@ function ($value, $validator) use ($earliestHandoff, $firstHandoff, $latestHando
11101180 );
11111181 if ($ earliestHandoff !== null && $ chosenHandoff < $ earliestHandoff ) {
11121182 $ validator ->addMessage (sprintf (
1113- $ this ->translate ('The first handoff can only happen after %s ' ),
1183+ $ this ->translate ('The rotation can only start after %s ' ),
11141184 $ earliestHandoff ->format ('Y-m-d ' ) // TODO: Use intl here
11151185 ));
11161186
11171187 return false ;
11181188 } elseif ($ chosenHandoff > $ latestHandoff ) {
11191189 $ validator ->addMessage (sprintf (
1120- $ this ->translate ('The first handoff can only happen before %s ' ),
1190+ $ this ->translate ('The rotation can only start before %s ' ),
11211191 $ latestHandoff ->format ('Y-m-d ' ) // TODO: Use intl here
11221192 ));
11231193
@@ -1142,10 +1212,10 @@ function ($value, $validator) use ($earliestHandoff, $firstHandoff, $latestHando
11421212
11431213 $ actualFirstHandoff = $ ruleGenerator ->current ()[0 ]->getStartDate ();
11441214 if ($ actualFirstHandoff < new DateTime ()) {
1145- return $ this ->translate ('The first handoff will happen immediately ' );
1215+ return $ this ->translate ('The rotation will start immediately ' );
11461216 } else {
11471217 return sprintf (
1148- $ this ->translate ('The first handoff will happen on %s ' ),
1218+ $ this ->translate ('The rotation will start on %s ' ),
11491219 (new \IntlDateFormatter (
11501220 \Locale::getDefault (),
11511221 \IntlDateFormatter::MEDIUM ,
@@ -1157,65 +1227,6 @@ function ($value, $validator) use ($earliestHandoff, $firstHandoff, $latestHando
11571227 ));
11581228 }
11591229
1160- $ termValidator = function (array $ terms ) {
1161- $ contactTerms = [];
1162- $ groupTerms = [];
1163- foreach ($ terms as $ term ) {
1164- /** @var TermInput\Term $term */
1165- if (strpos ($ term ->getSearchValue (), ': ' ) === false ) {
1166- // TODO: Auto-correct this to a valid type:id pair, if possible
1167- $ term ->setMessage ($ this ->translate ('Is not a contact nor a group of contacts ' ));
1168- continue ;
1169- }
1170-
1171- list ($ type , $ id ) = explode (': ' , $ term ->getSearchValue (), 2 );
1172- if ($ type === 'contact ' ) {
1173- $ contactTerms [$ id ] = $ term ;
1174- } elseif ($ type === 'group ' ) {
1175- $ groupTerms [$ id ] = $ term ;
1176- }
1177- }
1178-
1179- if (! empty ($ contactTerms )) {
1180- $ contacts = (Contact::on (Database::get ()))
1181- ->filter (Filter::equal ('id ' , array_keys ($ contactTerms )));
1182- foreach ($ contacts as $ contact ) {
1183- $ contactTerms [$ contact ->id ]
1184- ->setLabel ($ contact ->full_name )
1185- ->setClass ('contact ' );
1186- }
1187- }
1188-
1189- if (! empty ($ groupTerms )) {
1190- $ groups = (Contactgroup::on (Database::get ()))
1191- ->filter (Filter::equal ('id ' , array_keys ($ groupTerms )));
1192- foreach ($ groups as $ group ) {
1193- $ groupTerms [$ group ->id ]
1194- ->setLabel ($ group ->name )
1195- ->setClass ('group ' );
1196- }
1197- }
1198- };
1199-
1200- $ members = (new TermInput ('members ' ))
1201- ->setIgnored ()
1202- ->setRequired ()
1203- ->setOrdered ()
1204- ->setReadOnly ()
1205- ->setVerticalTermDirection ()
1206- ->setLabel ($ this ->translate ('Members ' ))
1207- ->setSuggestionUrl ($ this ->suggestionUrl ->with (['showCompact ' => true , '_disableLayout ' => 1 ]))
1208- ->on (TermInput::ON_ENRICH , $ termValidator )
1209- ->on (TermInput::ON_ADD , $ termValidator )
1210- ->on (TermInput::ON_SAVE , $ termValidator )
1211- ->on (TermInput::ON_PASTE , $ termValidator );
1212- $ this ->addElement ($ members );
1213-
1214- // TODO: TermInput is not compatible with the new decorators yet: https://github.com/Icinga/ipl-web/pull/317
1215- $ legacyDecorator = new IcingaFormDecorator ();
1216- $ members ->setDefaultElementDecorator ($ legacyDecorator );
1217- $ legacyDecorator ->decorate ($ members );
1218-
12191230 $ this ->addElement ('submit ' , 'submit ' , [
12201231 'label ' => $ this ->getSubmitLabel ()
12211232 ]);
@@ -1243,7 +1254,7 @@ function ($value, $validator) use ($earliestHandoff, $firstHandoff, $latestHando
12431254 $ this ->getElement ('submit ' )->prependWrapper ((new HtmlDocument ())->setHtmlContent (...$ removeButtons ));
12441255 }
12451256
1246- $ this ->addElement ( $ this -> createCsrfCounterMeasure ( Session::getSession ()->getId () ));
1257+ $ this ->addCsrfCounterMeasure ( Session::getSession ()->getId ());
12471258 }
12481259
12491260 /**
0 commit comments