diff --git a/src/app/config/custom-texts.json b/src/app/config/custom-texts.json
index a34c9196458f483401c5b75388621efc5269fbca..5e85f94a200bfd95bdacf54ff5657b406557313c 100644
--- a/src/app/config/custom-texts.json
+++ b/src/app/config/custom-texts.json
@@ -192,6 +192,10 @@
     "label": "Control: Entsperren",
     "defaultvalue": "Entsperren"
   },
+  "gm_control_unlock_success_warning": {
+    "label": "Wird angezeigt, wenn tests entsperrt wurden",
+    "defaultvalue": "ACHTUNG! Die betreffenden Browser müssen ggf. neu gestartet werden."
+  },
   "gm_control_finish_everything": {
     "label": "Control: Testung beenden",
     "defaultvalue": "Testung beenden"
diff --git a/src/app/group-monitor/group-monitor.component.css b/src/app/group-monitor/group-monitor.component.css
index 12647f3b485e408df1b781e6346004b66c1ed462..301d5f55d47b759fba66c75559dcabe9899e9be7 100644
--- a/src/app/group-monitor/group-monitor.component.css
+++ b/src/app/group-monitor/group-monitor.component.css
@@ -224,28 +224,15 @@ mat-sidenav {
     color: #821123
 }
 
-.alert-warning {
-    border-radius: 4px;
-    box-sizing: border-box;
-    margin: 0 0 0.5em 0;
-    width: 100%;
-    padding: 14px 16px;
-    min-height: 48px;
-    color: hsla(0,0%,100%,.7);
-    background: #821123;
-    display: inline-flex;
-    vertical-align: middle;
-    align-items: center;
-    animation: fade 30s reverse forwards;
+#message-panel alert:first-of-type {
+    background: #b2ff59;
+    animation: fade 7s reverse forwards;
 }
 
-.alert-warning mat-icon {
-    margin-right: 4px;
-}
 
 @keyframes fade {
     0% {
-        opacity: 0;
+        opacity: 0.1;
     }
 
     100% {
diff --git a/src/app/group-monitor/group-monitor.component.html b/src/app/group-monitor/group-monitor.component.html
index 85c6014d74fc3cc8e8d446f7524ee583ff879010..6e9c0a999099f1ff2a109f3aa29502ef00ef6e1e 100644
--- a/src/app/group-monitor/group-monitor.component.html
+++ b/src/app/group-monitor/group-monitor.component.html
@@ -86,41 +86,40 @@
       <h2>{{'Test-Steuerung' | customtext:'gm_controls' | async}}</h2>
 
       <div class="selection-info" *ngIf="gms.sessionsStats$ | async as sessionsStats">
-        <div *ngIf="sessionsStats.differentBookletSpecies > 1; else: singleBookletSpecies">
-          {{
-          'Die verwendeten Booklets sind zu unterschiedlich, um gemeinsam benutzt zu werden.'
-            | customtext:'gm_multiple_booklet_species_warning'
-            | async
-          }}
-        </div>
-        <ng-template #singleBookletSpecies>
-          <mat-slide-toggle
+        <mat-slide-toggle
             color="accent"
             (change)="toggleAlwaysCheckAll($event)"
             [disabled]="!gms.checkingOptions.disableAutoCheckAll"
-            [checked]="!gms.checkingOptions.autoCheckAll"
-          >
-            Einzelauswahl der Sitzungen
-          </mat-slide-toggle>
-        </ng-template>
+            [checked]="gms.checkingOptions.autoCheckAll"
+        >
+          Alle Tests gleichzeitig steuern
+        </mat-slide-toggle>
+        <alert
+            *ngIf="sessionsStats.differentBookletSpecies > 1"
+            level="warning"
+            text="Die verwendeten Booklets sind zu unterschiedlich, um gemeinsam gesteuert zu werden."
+            customtext="gm_multiple_booklet_species_warning"
+        >
+        </alert>
       </div>
 
       <div class="selection-info" *ngIf="displayOptions.manualChecking">
         <ng-container *ngIf="gms.checkedStats$ | async as checkedStats">
-          <ng-container *ngIf="checkedStats.number; else noCheckedSession">
-            {{
-            '%s %s Test%s mit %s Testheft%s ausgewählt.'
-              | customtext:'gm_selection_info'
-              : (checkedStats.all ? ' Alle' : '')
-              : checkedStats.number.toString(10)
-              : (checkedStats.number !== 1 ? 's' : '')
-              : checkedStats.differentBooklets.toString(10)
-              : (checkedStats.differentBooklets !== 1 ? 'en' : '')
-              | async
-            }}
-          </ng-container>
+          <alert
+              *ngIf="checkedStats.number; else noCheckedSession"
+              level="info"
+              customtext="gm_selection_info"
+              text="%s %s Test%s mit %s Testheft%s ausgewählt."
+              [replacements]="[
+                (checkedStats.all ? ' Alle' : ''),
+                checkedStats.number.toString(10),
+                (checkedStats.number !== 1 ? 's' : ''),
+                checkedStats.differentBooklets.toString(10),
+                (checkedStats.differentBooklets !== 1 ? 'en' : '')
+              ]"
+          ></alert>
           <ng-template #noCheckedSession>
-            {{'Kein Test gewählt.' | customtext:'gm_selection_info_none' | async}}
+            <alert level="info" customtext="gm_selection_info_none" text="Kein Test ausgewählt."></alert>
           </ng-template>
         </ng-container>
       </div>
@@ -138,19 +137,10 @@
       </div>
 
       <div class="toolbar-section">
-        <button
-          mat-raised-button
-          class="control"
-          color="primary"
-          (click)="testCommandGoto()"
-          [disabled]="!selectedElement?.element?.blockId"
-        >
+        <button mat-raised-button class="control" color="primary" (click)="testCommandGoto()">
           <mat-icon>arrow_forward</mat-icon>
           {{'Springe zu' | customtext:'gm_control_goto' | async}}
           <span class="emph">{{selectedElement?.element?.blockId}}</span>
-          <span class="emph" *ngIf="!selectedElement?.element?.blockId">
-            {{'Block auswählen!' | customtext:'gm_test_command_no_selected_block' | async}}
-          </span>
         </button>
       </div>
 
@@ -167,10 +157,8 @@
         </button>
       </div>
 
-      <alert customtext="gm_control_unlock_tooltip" text="schnrugl" level="info"></alert>
-
-      <div class="toolbar-section">
-        <alert *ngFor="let m of messages" [text]="m.text" [level]="m.level"></alert>
+      <div id="message-panel" class="toolbar-section">
+        <alert *ngFor="let m of messages" [text]="m.text" [level]="m.level" customtext="m.customtext" [replacements]="m.replacements"></alert>
       </div>
 
       <div class="toolbar-section toolbar-section-bottom">
diff --git a/src/app/group-monitor/group-monitor.component.ts b/src/app/group-monitor/group-monitor.component.ts
index aeccb6d47b943be9715cad8a8a84f71a05b8101f..31176cc628937493cf0832f91c522cbb24afb167 100644
--- a/src/app/group-monitor/group-monitor.component.ts
+++ b/src/app/group-monitor/group-monitor.component.ts
@@ -6,7 +6,7 @@ import { Sort } from '@angular/material/sort';
 import { MatSidenav } from '@angular/material/sidenav';
 import { interval, Observable, Subscription } from 'rxjs';
 import { MatDialog } from '@angular/material/dialog';
-import { ConfirmDialogComponent, ConfirmDialogData } from 'iqb-components';
+import { ConfirmDialogComponent, ConfirmDialogData, CustomtextService } from 'iqb-components';
 import { MatSlideToggleChange } from '@angular/material/slide-toggle';
 import { MatCheckboxChange } from '@angular/material/checkbox';
 import { switchMap } from 'rxjs/operators';
@@ -30,7 +30,8 @@ export class GroupMonitorComponent implements OnInit, OnDestroy {
     private route: ActivatedRoute,
     private bs: BackendService, // TODO move completely to service
     public gms: GroupMonitorService,
-    private router: Router
+    private router: Router,
+    private cts: CustomtextService
   ) {}
 
   ownGroup$: Observable<GroupData>;
@@ -78,24 +79,26 @@ export class GroupMonitorComponent implements OnInit, OnDestroy {
       this.messages.push(this.commandResponseToMessage(commandResponse));
     });
     this.gms.commandResponses$
-      .pipe(switchMap(() => interval(2000)))
+      .pipe(switchMap(() => interval(7000)))
       .subscribe(() => this.messages.shift());
   }
 
   private commandResponseToMessage(commandResponse: CommandResponse): UIMessage {
+    const command = this.cts.getCustomText(`gm_control_${commandResponse.commandType}`) || commandResponse.commandType;
+    const successWarning = this.cts.getCustomText(`gm_control_${commandResponse.commandType}_success_warning`) || '';
     if (!commandResponse.testIds.length) {
       return {
         level: 'warning',
         text: 'Keine Tests Betroffen von: `%s`',
         customtext: 'gm_message_no_session_affected_by_command',
-        replacements: [commandResponse.commandType, commandResponse.testIds.length.toString(10)]
+        replacements: [command, commandResponse.testIds.length.toString(10)]
       };
     }
     return {
-      level: 'warning',
-      text: '`%s` and `%s` tests gesendet!',
+      level: successWarning ? 'warning' : 'info',
+      text: '`%s` an `%s` tests gesendet! %s',
       customtext: 'gm_message_command_sent_n_sessions',
-      replacements: [commandResponse.commandType, commandResponse.testIds.length.toString(10)]
+      replacements: [command, commandResponse.testIds.length.toString(10), successWarning]
     };
   }
 
@@ -187,7 +190,7 @@ export class GroupMonitorComponent implements OnInit, OnDestroy {
       if (confirmed) {
         this.isClosing = true;
         this.gms.finishEverything()
-          .add(() => {
+          .subscribe(() => {
             setTimeout(() => { this.router.navigateByUrl('/r/login'); }, 5000); // go away
           });
       }
@@ -195,22 +198,19 @@ export class GroupMonitorComponent implements OnInit, OnDestroy {
   }
 
   testCommandGoto(): void {
-    this.gms.testCommandGoto(this.selectedElement);
+    if (!this.selectedElement?.element?.blockId) {
+      this.messages.push({
+        level: 'warning',
+        customtext: 'gm_test_command_no_selected_block',
+        text: 'Kein Zielblock ausgewählt'
+      });
+    } else {
+      this.gms.testCommandGoto(this.selectedElement);
+    }
   }
 
   unlockCommand(): void {
     this.gms.testCommandUnlock();
-    //   .subscribe(commandResponse => {
-    //     if (commandResponse.error) {
-    //       const plural = this.gms.sessions.length > 1;
-    //       this.addWarning('reload-some-clients',
-    //         `${plural ? this.gms.sessions.length : 'Ein'} Test${plural ? 's' : ''}
-    //       wurde${plural ? 'n' : ''} entsperrt. ${plural ? 'Die' : 'Der'} Teilnehmer
-    //       ${plural ? 'müssen' : 'muss'} die Webseite aufrufen bzw. neuladen,
-    //       damit ${plural ? 'die' : 'der'} Test${plural ? 's' : ''} wieder aufgenommen werden
-    //       ${plural ? 'können' : 'kann'}!`);
-    //     }
-    //   });
   }
 
   toggleChecked(checked: boolean, session: TestSession): void {
diff --git a/src/app/group-monitor/group-monitor.interfaces.ts b/src/app/group-monitor/group-monitor.interfaces.ts
index a632843833ccc8dec6397629a59d9081044055ae..a6588d89dc53ac572bedc81d59428fbf4851e711 100644
--- a/src/app/group-monitor/group-monitor.interfaces.ts
+++ b/src/app/group-monitor/group-monitor.interfaces.ts
@@ -157,7 +157,7 @@ export interface UIMessage {
   level: 'error' | 'warning' | 'info' | 'success';
   text: string;
   customtext: string;
-  replacements: string[]
+  replacements?: string[]
 }
 
 export interface CommandResponse {
diff --git a/src/app/group-monitor/group-monitor.service.ts b/src/app/group-monitor/group-monitor.service.ts
index 19d25251768a43b67180136c099c726112cd85fe..9cdcbd38dce73750776190fc20bcef7d1761d20a 100644
--- a/src/app/group-monitor/group-monitor.service.ts
+++ b/src/app/group-monitor/group-monitor.service.ts
@@ -1,9 +1,11 @@
 import { Injectable } from '@angular/core';
 import {
-  BehaviorSubject, combineLatest, Observable, Subject, Subscription, zip
+  BehaviorSubject, combineLatest, Observable, Subject, zip
 } from 'rxjs';
 import { Sort } from '@angular/material/sort';
-import { map, switchMap, tap } from 'rxjs/operators';
+import {
+  delay, flatMap, map, switchMap, tap
+} from 'rxjs/operators';
 import { BackendService } from './backend.service';
 import { BookletService } from './booklet.service';
 import { TestSessionService } from './test-session.service';
@@ -18,12 +20,12 @@ import {
 /**
  * func:
  * # checkAll
- * - stop / resume usw. ohne erlaubnis-check! sonst macht alwaysAll keinen Sinn
+ * # stop / resume usw. ohne erlaubnis-check! sonst macht alwaysAll keinen Sinn
  * --> customText und alert kombinieren!
  * - automatisch den nächsten wählen (?)
  * - problem beim markieren
  * tidy:
- * - was geben die commands zurück?
+ * # was geben die commands zurück?
  * - wie wird alles reseted?
  * test
  * polish:
@@ -421,7 +423,7 @@ export class GroupMonitorService {
     };
   }
 
-  finishEverything(): Subscription {
+  finishEverything(): Observable<CommandResponse> {
     // TODO was ist hier mit gefilterten sessions?!
     const getUnlockedConnectedTestIds = () => Object.values(this._sessions$.getValue())
       .filter(session => !TestSessionService.hasState(session.data.testState, 'status', 'locked') &&
@@ -434,9 +436,10 @@ export class GroupMonitorService {
       .filter(session => !TestSessionService.hasState(session.data.testState, 'status', 'locked'))
       .map(session => session.data.testId);
 
-    return this.bs.command('terminate', [], getUnlockedConnectedTestIds()) // kill running tests
-      .subscribe(() => {
-        setTimeout(() => this.bs.lock(this.groupName, getUnlockedTestIds()), 2000); // lock everything
-      });
+    return this.bs.command('terminate', [], getUnlockedConnectedTestIds())
+      .pipe(
+        delay(2000),
+        flatMap(() => this.bs.lock(this.groupName, getUnlockedTestIds()))
+      );
   }
 }