diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/content/ExamForm.java b/src/main/java/ch/ethz/seb/sebserver/gui/content/ExamForm.java
index ac72efe3..cde95596 100644
--- a/src/main/java/ch/ethz/seb/sebserver/gui/content/ExamForm.java
+++ b/src/main/java/ch/ethz/seb/sebserver/gui/content/ExamForm.java
@@ -31,17 +31,20 @@ import ch.ethz.seb.sebserver.gbl.util.Result;
 import ch.ethz.seb.sebserver.gui.content.action.ActionDefinition;
 import ch.ethz.seb.sebserver.gui.form.FormBuilder;
 import ch.ethz.seb.sebserver.gui.form.FormHandle;
-import ch.ethz.seb.sebserver.gui.form.PageFormService;
 import ch.ethz.seb.sebserver.gui.service.ResourceService;
 import ch.ethz.seb.sebserver.gui.service.i18n.I18nSupport;
 import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey;
-import ch.ethz.seb.sebserver.gui.service.page.PageAction;
 import ch.ethz.seb.sebserver.gui.service.page.PageContext;
 import ch.ethz.seb.sebserver.gui.service.page.PageContext.AttributeKeys;
-import ch.ethz.seb.sebserver.gui.service.page.PageUtils;
+import ch.ethz.seb.sebserver.gui.service.page.PageService;
+import ch.ethz.seb.sebserver.gui.service.page.PageService.PageActionBuilder;
 import ch.ethz.seb.sebserver.gui.service.page.TemplateComposer;
 import ch.ethz.seb.sebserver.gui.service.page.event.ActionEvent;
+import ch.ethz.seb.sebserver.gui.service.page.impl.PageAction;
+import ch.ethz.seb.sebserver.gui.service.page.impl.PageUtils;
 import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestService;
+import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.exam.ActivateExam;
+import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.exam.DeactivateExam;
 import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.exam.DeleteIndicator;
 import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.exam.GetExam;
 import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.exam.GetIndicators;
@@ -62,7 +65,7 @@ public class ExamForm implements TemplateComposer {
 
     private static final Logger log = LoggerFactory.getLogger(ExamForm.class);
 
-    private final PageFormService pageFormService;
+    private final PageService pageService;
     private final ResourceService resourceService;
 
     private final static LocTextKey listTitleKey =
@@ -77,10 +80,10 @@ public class ExamForm implements TemplateComposer {
             new LocTextKey("sebserver.exam.indicator.list.pleaseSelect");
 
     protected ExamForm(
-            final PageFormService pageFormService,
+            final PageService pageService,
             final ResourceService resourceService) {
 
-        this.pageFormService = pageFormService;
+        this.pageService = pageService;
         this.resourceService = resourceService;
     }
 
@@ -88,7 +91,7 @@ public class ExamForm implements TemplateComposer {
     public void compose(final PageContext pageContext) {
         final CurrentUser currentUser = this.resourceService.getCurrentUser();
         final RestService restService = this.resourceService.getRestService();
-        final WidgetFactory widgetFactory = this.pageFormService.getWidgetFactory();
+        final WidgetFactory widgetFactory = this.pageService.getWidgetFactory();
         final I18nSupport i18nSupport = this.resourceService.getI18nSupport();
 
         final UserInfo user = currentUser.get();
@@ -131,7 +134,7 @@ public class ExamForm implements TemplateComposer {
         final boolean modifyGrant = userGrantCheck.m();
 
         // The Exam form
-        final FormHandle<Exam> formHandle = this.pageFormService.getBuilder(
+        final FormHandle<Exam> formHandle = this.pageService.formBuilder(
                 formContext.copyOf(content), 4)
                 .readonly(readonly)
                 .putStaticValueIf(isNotNew,
@@ -204,34 +207,36 @@ public class ExamForm implements TemplateComposer {
                         ? restService.getRestCall(ImportAsExam.class)
                         : restService.getRestCall(SaveExam.class));
 
+        final PageActionBuilder actionBuilder = this.pageService.pageActionBuilder(formContext
+                .clearEntityKeys()
+                .removeAttribute(AttributeKeys.IMPORT_FROM_QUIZZ_DATA));
         // propagate content actions to action-pane
-        formContext.clearEntityKeys()
-                .removeAttribute(AttributeKeys.IMPORT_FROM_QUIZZ_DATA)
+        actionBuilder
 
-                .createAction(ActionDefinition.EXAM_MODIFY)
+                .newAction(ActionDefinition.EXAM_MODIFY)
                 .withEntityKey(entityKey)
                 .publishIf(() -> modifyGrant && readonly)
 
-                .createAction(ActionDefinition.EXAM_SAVE)
+                .newAction(ActionDefinition.EXAM_SAVE)
                 .withExec(formHandle::processFormSave)
+                .ignoreMoveAwayFromEdit()
                 .publishIf(() -> !readonly && modifyGrant)
 
-                .createAction(ActionDefinition.EXAM_CANCEL_MODIFY)
+                .newAction(ActionDefinition.EXAM_CANCEL_MODIFY)
                 .withEntityKey(entityKey)
                 .withAttribute(AttributeKeys.IMPORT_FROM_QUIZZ_DATA, String.valueOf(importFromQuizData))
-                .withExec(ExamForm::cancelModify)
-                .withConfirm("sebserver.overall.action.modify.cancel.confirm")
+                .withExec(this::cancelModify)
                 .publishIf(() -> !readonly)
 
-                .createAction(ActionDefinition.EXAM_DEACTIVATE)
+                .newAction(ActionDefinition.EXAM_DEACTIVATE)
                 .withEntityKey(entityKey)
-                .withExec(restService::activation)
+                .withSimpleRestCall(restService, DeactivateExam.class)
                 .withConfirm(PageUtils.confirmDeactivation(exam, restService))
                 .publishIf(() -> writeGrant && readonly && exam.isActive())
 
-                .createAction(ActionDefinition.EXAM_ACTIVATE)
+                .newAction(ActionDefinition.EXAM_ACTIVATE)
                 .withEntityKey(entityKey)
-                .withExec(restService::activation)
+                .withSimpleRestCall(restService, ActivateExam.class)
                 .publishIf(() -> writeGrant && readonly && !exam.isActive());
 
         // additional data in read-only view
@@ -244,7 +249,7 @@ public class ExamForm implements TemplateComposer {
                     listTitleKey);
 
             final EntityTable<Indicator> indicatorTable =
-                    widgetFactory.entityTableBuilder(restService.getRestCall(GetIndicators.class))
+                    this.pageService.entityTableBuilder(restService.getRestCall(GetIndicators.class))
                             .withEmptyMessage(new LocTextKey("sebserver.exam.indicator.list.empty"))
                             .withPaging(3)
                             .withColumn(new ColumnDefinition<>(
@@ -265,19 +270,18 @@ public class ExamForm implements TemplateComposer {
 
                             .compose(content);
 
-            formContext.clearEntityKeys()
-                    .removeAttribute(AttributeKeys.IMPORT_FROM_QUIZZ_DATA)
+            actionBuilder
 
-                    .createAction(ActionDefinition.EXAM_INDICATOR_NEW)
+                    .newAction(ActionDefinition.EXAM_INDICATOR_NEW)
                     .withParentEntityKey(entityKey)
                     .publishIf(() -> modifyGrant)
 
-                    .createAction(ActionDefinition.EXAM_INDICATOR_MODIFY_FROM_LIST)
+                    .newAction(ActionDefinition.EXAM_INDICATOR_MODIFY_FROM_LIST)
                     .withParentEntityKey(entityKey)
                     .withSelect(indicatorTable::getSelection, PageAction::applySingleSelection, emptySelectionTextKey)
                     .publishIf(() -> modifyGrant && indicatorTable.hasAnyContent())
 
-                    .createAction(ActionDefinition.EXAM_INDICATOR_DELETE_FROM_LIST)
+                    .newAction(ActionDefinition.EXAM_INDICATOR_DELETE_FROM_LIST)
                     .withEntityKey(entityKey)
                     .withSelect(indicatorTable::getSelection, this::deleteSelectedIndicator, emptySelectionTextKey)
                     .publishIf(() -> modifyGrant && indicatorTable.hasAnyContent());
@@ -338,17 +342,20 @@ public class ExamForm implements TemplateComposer {
                 .toString();
     }
 
-    public static PageAction cancelModify(final PageAction action) {
+    private PageAction cancelModify(final PageAction action) {
         final boolean importFromQuizData = BooleanUtils.toBoolean(
                 action.pageContext().getAttribute(AttributeKeys.IMPORT_FROM_QUIZZ_DATA));
         if (importFromQuizData) {
-            final PageContext pageContext = action.pageContext();
-            final PageAction activityHomeAction = pageContext.createAction(ActionDefinition.QUIZ_DISCOVERY_VIEW_LIST);
-            action.pageContext().firePageEvent(new ActionEvent(activityHomeAction, false));
+            final PageActionBuilder actionBuilder = this.pageService.pageActionBuilder(action.pageContext());
+            final PageAction activityHomeAction = actionBuilder
+                    .newAction(ActionDefinition.QUIZ_DISCOVERY_VIEW_LIST)
+                    .create();
+            this.pageService.firePageEvent(new ActionEvent(activityHomeAction), action.pageContext());
             return activityHomeAction;
         }
 
-        return PageAction.onEmptyEntityKeyGoToActivityHome(action);
+        this.pageService.onEmptyEntityKeyGoTo(action, ActionDefinition.EXAM_VIEW_LIST);
+        return action;
     }
 
 }
diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/content/ExamList.java b/src/main/java/ch/ethz/seb/sebserver/gui/content/ExamList.java
index 6b8bd199..6d0de6f7 100644
--- a/src/main/java/ch/ethz/seb/sebserver/gui/content/ExamList.java
+++ b/src/main/java/ch/ethz/seb/sebserver/gui/content/ExamList.java
@@ -28,9 +28,11 @@ import ch.ethz.seb.sebserver.gui.content.action.ActionDefinition;
 import ch.ethz.seb.sebserver.gui.service.ResourceService;
 import ch.ethz.seb.sebserver.gui.service.i18n.I18nSupport;
 import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey;
-import ch.ethz.seb.sebserver.gui.service.page.PageAction;
 import ch.ethz.seb.sebserver.gui.service.page.PageContext;
+import ch.ethz.seb.sebserver.gui.service.page.PageService;
+import ch.ethz.seb.sebserver.gui.service.page.PageService.PageActionBuilder;
 import ch.ethz.seb.sebserver.gui.service.page.TemplateComposer;
+import ch.ethz.seb.sebserver.gui.service.page.impl.PageAction;
 import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestService;
 import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.exam.GetExams;
 import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser;
@@ -46,7 +48,7 @@ import ch.ethz.seb.sebserver.gui.widget.WidgetFactory;
 @GuiProfile
 public class ExamList implements TemplateComposer {
 
-    private final WidgetFactory widgetFactory;
+    private final PageService pageService;
     private final ResourceService resourceService;
     private final int pageSize;
 
@@ -67,11 +69,11 @@ public class ExamList implements TemplateComposer {
             new TableFilterAttribute(CriteriaType.DATE, QuizData.FILTER_ATTR_START_TIME);
 
     protected ExamList(
-            final WidgetFactory widgetFactory,
+            final PageService pageService,
             final ResourceService resourceService,
             @Value("${sebserver.gui.list.page.size}") final Integer pageSize) {
 
-        this.widgetFactory = widgetFactory;
+        this.pageService = pageService;
         this.resourceService = resourceService;
         this.pageSize = (pageSize != null) ? pageSize : 20;
 
@@ -88,20 +90,23 @@ public class ExamList implements TemplateComposer {
 
     @Override
     public void compose(final PageContext pageContext) {
+
+        final WidgetFactory widgetFactory = this.pageService.getWidgetFactory();
         final CurrentUser currentUser = this.resourceService.getCurrentUser();
         final RestService restService = this.resourceService.getRestService();
         final I18nSupport i18nSupport = this.resourceService.getI18nSupport();
 
         // content page layout with title
-        final Composite content = this.widgetFactory.defaultPageLayout(
+        final Composite content = widgetFactory.defaultPageLayout(
                 pageContext.getParent(),
                 new LocTextKey("sebserver.exam.list.title"));
 
         final boolean isSEBAdmin = currentUser.get().hasRole(UserRole.SEB_SERVER_ADMIN);
+        final PageActionBuilder actionBuilder = this.pageService.pageActionBuilder(pageContext.clearEntityKeys());
 
         // table
         final EntityTable<Exam> table =
-                this.widgetFactory.entityTableBuilder(restService.getRestCall(GetExams.class))
+                this.pageService.entityTableBuilder(restService.getRestCall(GetExams.class))
                         .withEmptyMessage(new LocTextKey("sebserver.exam.list.empty"))
                         .withPaging(this.pageSize)
                         .withColumnIf(() -> isSEBAdmin,
@@ -136,23 +141,23 @@ public class ExamList implements TemplateComposer {
                                 columnTitleTypeKey,
                                 this::examTypeName,
                                 true))
-                        .withDefaultAction(pageContext
-                                .clearEntityKeys()
-                                .createAction(ActionDefinition.EXAM_VIEW_FROM_LIST))
+                        .withDefaultAction(actionBuilder
+                                .newAction(ActionDefinition.EXAM_VIEW_FROM_LIST)
+                                .create())
                         .compose(content);
 
         // propagate content actions to action-pane
         final GrantCheck userGrant = currentUser.grantCheck(EntityType.EXAM);
-        pageContext.clearEntityKeys()
+        actionBuilder
 
-                .createAction(ActionDefinition.EXAM_IMPORT)
+                .newAction(ActionDefinition.EXAM_IMPORT)
                 .publishIf(userGrant::im)
 
-                .createAction(ActionDefinition.EXAM_VIEW_FROM_LIST)
+                .newAction(ActionDefinition.EXAM_VIEW_FROM_LIST)
                 .withSelect(table::getSelection, PageAction::applySingleSelection, emptySelectionTextKey)
                 .publishIf(table::hasAnyContent)
 
-                .createAction(ActionDefinition.EXAM_MODIFY_FROM_LIST)
+                .newAction(ActionDefinition.EXAM_MODIFY_FROM_LIST)
                 .withSelect(table::getSelection, PageAction::applySingleSelection, emptySelectionTextKey)
                 .publishIf(() -> userGrant.im() && table.hasAnyContent());
 
diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/content/IndicatorForm.java b/src/main/java/ch/ethz/seb/sebserver/gui/content/IndicatorForm.java
index e8ca555f..43653236 100644
--- a/src/main/java/ch/ethz/seb/sebserver/gui/content/IndicatorForm.java
+++ b/src/main/java/ch/ethz/seb/sebserver/gui/content/IndicatorForm.java
@@ -23,11 +23,10 @@ import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
 import ch.ethz.seb.sebserver.gui.content.action.ActionDefinition;
 import ch.ethz.seb.sebserver.gui.form.FormBuilder;
 import ch.ethz.seb.sebserver.gui.form.FormHandle;
-import ch.ethz.seb.sebserver.gui.form.PageFormService;
 import ch.ethz.seb.sebserver.gui.service.ResourceService;
 import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey;
-import ch.ethz.seb.sebserver.gui.service.page.PageAction;
 import ch.ethz.seb.sebserver.gui.service.page.PageContext;
+import ch.ethz.seb.sebserver.gui.service.page.PageService;
 import ch.ethz.seb.sebserver.gui.service.page.TemplateComposer;
 import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestService;
 import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.exam.GetExam;
@@ -43,21 +42,21 @@ public class IndicatorForm implements TemplateComposer {
 
     private static final Logger log = LoggerFactory.getLogger(IndicatorForm.class);
 
-    private final PageFormService pageFormService;
+    private final PageService pageService;
     private final ResourceService resourceService;
 
     protected IndicatorForm(
-            final PageFormService pageFormService,
+            final PageService pageService,
             final ResourceService resourceService) {
 
-        this.pageFormService = pageFormService;
+        this.pageService = pageService;
         this.resourceService = resourceService;
     }
 
     @Override
     public void compose(final PageContext pageContext) {
         final RestService restService = this.resourceService.getRestService();
-        final WidgetFactory widgetFactory = this.pageFormService.getWidgetFactory();
+        final WidgetFactory widgetFactory = this.pageService.getWidgetFactory();
         final EntityKey entityKey = pageContext.getEntityKey();
         final EntityKey parentEntityKey = pageContext.getParentEntityKey();
         final boolean isNew = entityKey == null;
@@ -97,7 +96,7 @@ public class IndicatorForm implements TemplateComposer {
                 formContext.getParent(),
                 titleKey);
 
-        final FormHandle<Indicator> formHandle = this.pageFormService.getBuilder(
+        final FormHandle<Indicator> formHandle = this.pageService.formBuilder(
                 formContext.copyOf(content), 4)
                 .readonly(isReadonly)
                 .putStaticValueIf(() -> !isNew,
@@ -136,16 +135,19 @@ public class IndicatorForm implements TemplateComposer {
                         : restService.getRestCall(SaveIndicator.class));
 
         // propagate content actions to action-pane
-        formContext.clearEntityKeys()
-                .createAction(ActionDefinition.EXAM_INDICATOR_SAVE)
+        this.pageService.pageActionBuilder(formContext.clearEntityKeys())
+
+                .newAction(ActionDefinition.EXAM_INDICATOR_SAVE)
                 .withEntityKey(parentEntityKey)
                 .withExec(formHandle::processFormSave)
+                .ignoreMoveAwayFromEdit()
                 .publishIf(() -> !isReadonly)
 
-                .createAction(ActionDefinition.EXAM_INDICATOR_CANCEL_MODIFY)
+                .newAction(ActionDefinition.EXAM_INDICATOR_CANCEL_MODIFY)
                 .withEntityKey(parentEntityKey)
-                .withExec(PageAction::onEmptyEntityKeyGoToActivityHome)
-                .withConfirm("sebserver.overall.action.modify.cancel.confirm")
+                .withExec(action -> this.pageService.onEmptyEntityKeyGoTo(
+                        action,
+                        ActionDefinition.EXAM_VIEW_LIST))
                 .publishIf(() -> !isReadonly);
 
     }
diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/content/InstitutionForm.java b/src/main/java/ch/ethz/seb/sebserver/gui/content/InstitutionForm.java
index 68b9d8a6..340af3b1 100644
--- a/src/main/java/ch/ethz/seb/sebserver/gui/content/InstitutionForm.java
+++ b/src/main/java/ch/ethz/seb/sebserver/gui/content/InstitutionForm.java
@@ -26,14 +26,15 @@ import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
 import ch.ethz.seb.sebserver.gui.content.action.ActionDefinition;
 import ch.ethz.seb.sebserver.gui.form.FormBuilder;
 import ch.ethz.seb.sebserver.gui.form.FormHandle;
-import ch.ethz.seb.sebserver.gui.form.PageFormService;
 import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey;
-import ch.ethz.seb.sebserver.gui.service.page.PageAction;
 import ch.ethz.seb.sebserver.gui.service.page.PageContext;
-import ch.ethz.seb.sebserver.gui.service.page.PageUtils;
+import ch.ethz.seb.sebserver.gui.service.page.PageService;
 import ch.ethz.seb.sebserver.gui.service.page.TemplateComposer;
+import ch.ethz.seb.sebserver.gui.service.page.impl.PageUtils;
 import ch.ethz.seb.sebserver.gui.service.remote.SebClientConfigDownload;
 import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestService;
+import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.institution.ActivateInstitution;
+import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.institution.DeactivateInstitution;
 import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.institution.GetInstitution;
 import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.institution.NewInstitution;
 import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.institution.SaveInstitution;
@@ -48,18 +49,18 @@ public class InstitutionForm implements TemplateComposer {
 
     private static final Logger log = LoggerFactory.getLogger(InstitutionForm.class);
 
-    private final PageFormService pageFormService;
+    private final PageService pageService;
     private final RestService restService;
     private final CurrentUser currentUser;
     private final SebClientConfigDownload sebClientConfigDownload;
 
     protected InstitutionForm(
-            final PageFormService pageFormService,
+            final PageService pageService,
             final RestService restService,
             final CurrentUser currentUser,
             final SebClientConfigDownload sebClientConfigDownload) {
 
-        this.pageFormService = pageFormService;
+        this.pageService = pageService;
         this.restService = restService;
         this.currentUser = currentUser;
         this.sebClientConfigDownload = sebClientConfigDownload;
@@ -68,7 +69,7 @@ public class InstitutionForm implements TemplateComposer {
     @Override
     public void compose(final PageContext pageContext) {
 
-        final WidgetFactory widgetFactory = this.pageFormService.getWidgetFactory();
+        final WidgetFactory widgetFactory = this.pageService.getWidgetFactory();
         final EntityKey entityKey = pageContext.getEntityKey();
         final boolean isNew = entityKey == null;
         // get data or create new. Handle error if happen
@@ -114,7 +115,7 @@ public class InstitutionForm implements TemplateComposer {
                 titleKey);
 
         // The Institution form
-        final FormHandle<Institution> formHandle = this.pageFormService.getBuilder(
+        final FormHandle<Institution> formHandle = this.pageService.formBuilder(
                 formContext.copyOf(content), 4)
                 .readonly(isReadonly)
                 .putStaticValueIf(() -> !isNew,
@@ -139,20 +140,20 @@ public class InstitutionForm implements TemplateComposer {
 
         // propagate content actions to action-pane
         final UrlLauncher urlLauncher = RWT.getClient().getService(UrlLauncher.class);
-        formContext.clearEntityKeys()
+        this.pageService.pageActionBuilder(formContext.clearEntityKeys())
 
-                .createAction(ActionDefinition.INSTITUTION_NEW)
+                .newAction(ActionDefinition.INSTITUTION_NEW)
                 .publishIf(() -> writeGrant && isReadonly)
 
-                .createAction(ActionDefinition.USER_ACCOUNT_NEW)
+                .newAction(ActionDefinition.USER_ACCOUNT_NEW)
                 .withParentEntityKey(entityKey)
                 .publishIf(() -> userWriteGrant && isReadonly && institution.isActive())
 
-                .createAction(ActionDefinition.INSTITUTION_MODIFY)
+                .newAction(ActionDefinition.INSTITUTION_MODIFY)
                 .withEntityKey(entityKey)
                 .publishIf(() -> modifyGrant && isReadonly)
 
-                .createAction(ActionDefinition.INSTITUTION_EXPORT_SEB_CONFIG)
+                .newAction(ActionDefinition.INSTITUTION_EXPORT_SEB_CONFIG)
                 .withEntityKey(entityKey)
                 .withExec(action -> {
                     final String downloadURL = this.sebClientConfigDownload.downloadSEBClientConfigURL(
@@ -162,26 +163,28 @@ public class InstitutionForm implements TemplateComposer {
                 })
                 .publishIf(() -> sebConfigWriteGrant && isReadonly && institution.isActive())
 
-                .createAction(ActionDefinition.INSTITUTION_DEACTIVATE)
+                .newAction(ActionDefinition.INSTITUTION_DEACTIVATE)
                 .withEntityKey(entityKey)
-                .withExec(this.restService::activation)
+                .withSimpleRestCall(this.restService, DeactivateInstitution.class)
                 .withConfirm(PageUtils.confirmDeactivation(institution, this.restService))
                 .publishIf(() -> writeGrant && isReadonly && institution.isActive())
 
-                .createAction(ActionDefinition.INSTITUTION_ACTIVATE)
+                .newAction(ActionDefinition.INSTITUTION_ACTIVATE)
                 .withEntityKey(entityKey)
-                .withExec(this.restService::activation)
+                .withSimpleRestCall(this.restService, ActivateInstitution.class)
                 .publishIf(() -> writeGrant && isReadonly && !institution.isActive())
 
-                .createAction(ActionDefinition.INSTITUTION_SAVE)
+                .newAction(ActionDefinition.INSTITUTION_SAVE)
                 .withEntityKey(entityKey)
                 .withExec(formHandle::processFormSave)
+                .ignoreMoveAwayFromEdit()
                 .publishIf(() -> !isReadonly)
 
-                .createAction(ActionDefinition.INSTITUTION_CANCEL_MODIFY)
+                .newAction(ActionDefinition.INSTITUTION_CANCEL_MODIFY)
                 .withEntityKey(entityKey)
-                .withExec(PageAction::onEmptyEntityKeyGoToActivityHome)
-                .withConfirm("sebserver.overall.action.modify.cancel.confirm")
+                .withExec(action -> this.pageService.onEmptyEntityKeyGoTo(
+                        action,
+                        ActionDefinition.INSTITUTION_VIEW_LIST))
                 .publishIf(() -> !isReadonly);
     }
 
diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/content/InstitutionList.java b/src/main/java/ch/ethz/seb/sebserver/gui/content/InstitutionList.java
index bef5ba1e..2a74e35f 100644
--- a/src/main/java/ch/ethz/seb/sebserver/gui/content/InstitutionList.java
+++ b/src/main/java/ch/ethz/seb/sebserver/gui/content/InstitutionList.java
@@ -18,16 +18,17 @@ import ch.ethz.seb.sebserver.gbl.model.institution.Institution;
 import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
 import ch.ethz.seb.sebserver.gui.content.action.ActionDefinition;
 import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey;
-import ch.ethz.seb.sebserver.gui.service.page.PageAction;
 import ch.ethz.seb.sebserver.gui.service.page.PageContext;
+import ch.ethz.seb.sebserver.gui.service.page.PageService;
+import ch.ethz.seb.sebserver.gui.service.page.PageService.PageActionBuilder;
 import ch.ethz.seb.sebserver.gui.service.page.TemplateComposer;
+import ch.ethz.seb.sebserver.gui.service.page.impl.PageAction;
 import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestService;
 import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.institution.GetInstitutions;
 import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser;
 import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser.GrantCheck;
 import ch.ethz.seb.sebserver.gui.table.ColumnDefinition;
 import ch.ethz.seb.sebserver.gui.table.EntityTable;
-import ch.ethz.seb.sebserver.gui.widget.WidgetFactory;
 
 @Lazy
 @Component
@@ -47,29 +48,32 @@ public class InstitutionList implements TemplateComposer {
     private static final LocTextKey EMPTY_SELECTION_TEXT_KEY =
             new LocTextKey("sebserver.institution.info.pleaseSelect");
 
-    private final WidgetFactory widgetFactory;
+    private final PageService pageService;
     private final RestService restService;
     private final CurrentUser currentUser;
 
     protected InstitutionList(
-            final WidgetFactory widgetFactory,
+            final PageService pageService,
             final RestService restService,
             final CurrentUser currentUser) {
 
-        this.widgetFactory = widgetFactory;
+        this.pageService = pageService;
         this.restService = restService;
         this.currentUser = currentUser;
     }
 
     @Override
     public void compose(final PageContext pageContext) {
-        final Composite content = this.widgetFactory.defaultPageLayout(
+        final Composite content = this.pageService.getWidgetFactory().defaultPageLayout(
                 pageContext.getParent(),
                 TITLE_TEXT_KEY);
 
+        final PageActionBuilder pageActionBuilder =
+                this.pageService.pageActionBuilder(pageContext.clearEntityKeys());
+
         // table
         final EntityTable<Institution> table =
-                this.widgetFactory.entityTableBuilder(this.restService.getRestCall(GetInstitutions.class))
+                this.pageService.entityTableBuilder(this.restService.getRestCall(GetInstitutions.class))
                         .withEmptyMessage(EMPTY_LIST_TEXT_KEY)
                         .withPaging(3)
                         .withColumn(new ColumnDefinition<>(
@@ -87,27 +91,28 @@ public class InstitutionList implements TemplateComposer {
                                 ACTIVE_TEXT_KEY,
                                 entity -> entity.active,
                                 true))
-                        .withDefaultAction(pageContext
-                                .clearEntityKeys()
-                                .createAction(ActionDefinition.INSTITUTION_VIEW_FROM_LIST))
+                        .withDefaultAction(pageActionBuilder
+                                .newAction(ActionDefinition.INSTITUTION_VIEW_FROM_LIST)
+                                .create())
                         .compose(content);
 
         // propagate content actions to action-pane
         final GrantCheck instGrant = this.currentUser.grantCheck(EntityType.INSTITUTION);
         final GrantCheck userGrant = this.currentUser.grantCheck(EntityType.USER);
-        pageContext.clearEntityKeys()
 
-                .createAction(ActionDefinition.INSTITUTION_NEW)
+        pageActionBuilder
+
+                .newAction(ActionDefinition.INSTITUTION_NEW)
                 .publishIf(instGrant::w)
 
-                .createAction(ActionDefinition.USER_ACCOUNT_NEW)
+                .newAction(ActionDefinition.USER_ACCOUNT_NEW)
                 .publishIf(userGrant::w)
 
-                .createAction(ActionDefinition.INSTITUTION_VIEW_FROM_LIST)
+                .newAction(ActionDefinition.INSTITUTION_VIEW_FROM_LIST)
                 .withSelect(table::getSelection, PageAction::applySingleSelection, EMPTY_SELECTION_TEXT_KEY)
                 .publishIf(() -> table.hasAnyContent())
 
-                .createAction(ActionDefinition.INSTITUTION_MODIFY_FROM_LIST)
+                .newAction(ActionDefinition.INSTITUTION_MODIFY_FROM_LIST)
                 .withSelect(table::getSelection, PageAction::applySingleSelection, EMPTY_SELECTION_TEXT_KEY)
                 .publishIf(() -> instGrant.m() && table.hasAnyContent());
         ;
diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/content/LmsSetupForm.java b/src/main/java/ch/ethz/seb/sebserver/gui/content/LmsSetupForm.java
index b7640ef7..040d70b7 100644
--- a/src/main/java/ch/ethz/seb/sebserver/gui/content/LmsSetupForm.java
+++ b/src/main/java/ch/ethz/seb/sebserver/gui/content/LmsSetupForm.java
@@ -30,16 +30,19 @@ import ch.ethz.seb.sebserver.gbl.util.Result;
 import ch.ethz.seb.sebserver.gui.content.action.ActionDefinition;
 import ch.ethz.seb.sebserver.gui.form.FormBuilder;
 import ch.ethz.seb.sebserver.gui.form.FormHandle;
-import ch.ethz.seb.sebserver.gui.form.PageFormService;
 import ch.ethz.seb.sebserver.gui.service.ResourceService;
 import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey;
-import ch.ethz.seb.sebserver.gui.service.page.PageAction;
 import ch.ethz.seb.sebserver.gui.service.page.PageContext;
+import ch.ethz.seb.sebserver.gui.service.page.PageContext.AttributeKeys;
 import ch.ethz.seb.sebserver.gui.service.page.PageMessageException;
-import ch.ethz.seb.sebserver.gui.service.page.PageUtils;
+import ch.ethz.seb.sebserver.gui.service.page.PageService;
 import ch.ethz.seb.sebserver.gui.service.page.TemplateComposer;
+import ch.ethz.seb.sebserver.gui.service.page.impl.PageAction;
+import ch.ethz.seb.sebserver.gui.service.page.impl.PageUtils;
 import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestService;
 import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.institution.GetInstitution;
+import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.lmssetup.ActivateLmsSetup;
+import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.lmssetup.DeactivateLmsSetup;
 import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.lmssetup.GetLmsSetup;
 import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.lmssetup.NewLmsSetup;
 import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.lmssetup.SaveLmsSetup;
@@ -55,14 +58,14 @@ public class LmsSetupForm implements TemplateComposer {
 
     private static final Logger log = LoggerFactory.getLogger(LmsSetupForm.class);
 
-    private final PageFormService pageFormService;
+    private final PageService pageService;
     private final ResourceService resourceService;
 
     protected LmsSetupForm(
-            final PageFormService pageFormService,
+            final PageService pageService,
             final ResourceService resourceService) {
 
-        this.pageFormService = pageFormService;
+        this.pageService = pageService;
         this.resourceService = resourceService;
     }
 
@@ -70,7 +73,7 @@ public class LmsSetupForm implements TemplateComposer {
     public void compose(final PageContext pageContext) {
         final CurrentUser currentUser = this.resourceService.getCurrentUser();
         final RestService restService = this.resourceService.getRestService();
-        final WidgetFactory widgetFactory = this.pageFormService.getWidgetFactory();
+        final WidgetFactory widgetFactory = this.pageService.getWidgetFactory();
 
         final UserInfo user = currentUser.get();
         final EntityKey entityKey = pageContext.getEntityKey();
@@ -122,7 +125,7 @@ public class LmsSetupForm implements TemplateComposer {
 
         // The LMS Setup form
         final LmsType lmsType = lmsSetup.getLmsType();
-        final FormHandle<LmsSetup> formHandle = this.pageFormService.getBuilder(
+        final FormHandle<LmsSetup> formHandle = this.pageService.formBuilder(
                 formContext.copyOf(content), 4)
                 .readonly(readonly)
                 .putStaticValueIf(isNotNew,
@@ -174,49 +177,58 @@ public class LmsSetupForm implements TemplateComposer {
         ;
 
         // propagate content actions to action-pane
-        formContext.clearEntityKeys()
+        this.pageService.pageActionBuilder(formContext.clearEntityKeys())
 
-                .createAction(ActionDefinition.LMS_SETUP_NEW)
+                .newAction(ActionDefinition.LMS_SETUP_NEW)
                 .publishIf(() -> writeGrant && readonly && institutionActive)
 
-                .createAction(ActionDefinition.LMS_SETUP_MODIFY)
+                .newAction(ActionDefinition.LMS_SETUP_MODIFY)
                 .withEntityKey(entityKey)
                 .publishIf(() -> modifyGrant && readonly && institutionActive)
 
-                .createAction(ActionDefinition.LMS_SETUP_TEST)
+                .newAction(ActionDefinition.LMS_SETUP_TEST)
                 .withEntityKey(entityKey)
                 .withExec(action -> this.testLmsSetup(action, formHandle))
                 .publishIf(() -> modifyGrant && isNotNew.getAsBoolean() && institutionActive)
 
-                .createAction(ActionDefinition.LMS_SETUP_DEACTIVATE)
+                .newAction(ActionDefinition.LMS_SETUP_DEACTIVATE)
                 .withEntityKey(entityKey)
-                .withExec(restService::activation)
+                .withSimpleRestCall(restService, DeactivateLmsSetup.class)
                 .withConfirm(PageUtils.confirmDeactivation(lmsSetup, restService))
                 .publishIf(() -> writeGrant && readonly && institutionActive && lmsSetup.isActive())
 
-                .createAction(ActionDefinition.LMS_SETUP_ACTIVATE)
+                .newAction(ActionDefinition.LMS_SETUP_ACTIVATE)
                 .withEntityKey(entityKey)
                 .withExec(action -> activate(action, formHandle))
                 .publishIf(() -> writeGrant && readonly && institutionActive && !lmsSetup.isActive())
 
-                .createAction(ActionDefinition.LMS_SETUP_SAVE)
+                .newAction(ActionDefinition.LMS_SETUP_SAVE)
                 .withEntityKey(entityKey)
                 .withExec(formHandle::processFormSave)
+                .ignoreMoveAwayFromEdit()
                 .publishIf(() -> !readonly)
 
-                .createAction(ActionDefinition.LMS_SETUP_CANCEL_MODIFY)
+                .newAction(ActionDefinition.LMS_SETUP_CANCEL_MODIFY)
                 .withEntityKey(entityKey)
-                .withExec(PageAction::onEmptyEntityKeyGoToActivityHome)
-                .withConfirm("sebserver.overall.action.modify.cancel.confirm")
+                .withExec(action -> this.pageService.onEmptyEntityKeyGoTo(
+                        action,
+                        ActionDefinition.LMS_SETUP_VIEW_LIST))
                 .publishIf(() -> !readonly);
     }
 
     /** Save and test connection before activation */
     private PageAction activate(final PageAction action, final FormHandle<LmsSetup> formHandle) {
-        final RestService restService = this.resourceService.getRestService();
+        // first test the LMS Setup. If this fails the action execution will stops
         final PageAction testLmsSetup = this.testLmsSetup(action, formHandle);
-        final PageAction activation = restService.activation(testLmsSetup);
-        return activation;
+        // if LMS Setup test was successful, the activation action applies
+        this.resourceService.getRestService().getBuilder(ActivateLmsSetup.class)
+                .withURIVariable(
+                        API.PARAM_MODEL_ID,
+                        action.pageContext().getAttribute(AttributeKeys.ENTITY_ID))
+                .call()
+                .onErrorDo(t -> action.pageContext().notifyError(t));
+
+        return testLmsSetup;
     }
 
     /** LmsSetup test action implementation */
diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/content/LmsSetupList.java b/src/main/java/ch/ethz/seb/sebserver/gui/content/LmsSetupList.java
index db066f6b..f64d6bcd 100644
--- a/src/main/java/ch/ethz/seb/sebserver/gui/content/LmsSetupList.java
+++ b/src/main/java/ch/ethz/seb/sebserver/gui/content/LmsSetupList.java
@@ -25,9 +25,11 @@ import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
 import ch.ethz.seb.sebserver.gui.content.action.ActionDefinition;
 import ch.ethz.seb.sebserver.gui.service.ResourceService;
 import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey;
-import ch.ethz.seb.sebserver.gui.service.page.PageAction;
 import ch.ethz.seb.sebserver.gui.service.page.PageContext;
+import ch.ethz.seb.sebserver.gui.service.page.PageService;
+import ch.ethz.seb.sebserver.gui.service.page.PageService.PageActionBuilder;
 import ch.ethz.seb.sebserver.gui.service.page.TemplateComposer;
+import ch.ethz.seb.sebserver.gui.service.page.impl.PageAction;
 import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestService;
 import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.lmssetup.GetLmsSetups;
 import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser;
@@ -63,16 +65,16 @@ public class LmsSetupList implements TemplateComposer {
             new TableFilterAttribute(CriteriaType.TEXT, Entity.FILTER_ATTR_NAME);
     private final TableFilterAttribute typeFilter;
 
-    private final WidgetFactory widgetFactory;
+    private final PageService pageService;
     private final ResourceService resourceService;
     private final int pageSize;
 
     protected LmsSetupList(
-            final WidgetFactory widgetFactory,
+            final PageService pageService,
             final ResourceService resourceService,
             @Value("${sebserver.gui.list.page.size}") final Integer pageSize) {
 
-        this.widgetFactory = widgetFactory;
+        this.pageService = pageService;
         this.resourceService = resourceService;
         this.pageSize = (pageSize != null) ? pageSize : 20;
 
@@ -89,20 +91,21 @@ public class LmsSetupList implements TemplateComposer {
 
     @Override
     public void compose(final PageContext pageContext) {
+        final WidgetFactory widgetFactory = this.pageService.getWidgetFactory();
         final CurrentUser currentUser = this.resourceService.getCurrentUser();
         final RestService restService = this.resourceService.getRestService();
 
         // content page layout with title
-        final Composite content = this.widgetFactory.defaultPageLayout(
+        final Composite content = widgetFactory.defaultPageLayout(
                 pageContext.getParent(),
                 TITLE_TEXT_KEY);
 
         final boolean isSEBAdmin = currentUser.get().hasRole(UserRole.SEB_SERVER_ADMIN);
+        final PageActionBuilder actionBuilder = this.pageService.pageActionBuilder(pageContext.clearEntityKeys());
 
         // table
-
         final EntityTable<LmsSetup> table =
-                this.widgetFactory.entityTableBuilder(restService.getRestCall(GetLmsSetups.class))
+                this.pageService.entityTableBuilder(restService.getRestCall(GetLmsSetups.class))
                         .withEmptyMessage(EMPTY_LIST_TEXT_KEY)
                         .withPaging(this.pageSize)
                         .withColumnIf(() -> isSEBAdmin,
@@ -129,23 +132,23 @@ public class LmsSetupList implements TemplateComposer {
                                 ACTIVITY_TEXT_KEY,
                                 entity -> entity.active,
                                 true))
-                        .withDefaultAction(pageContext
-                                .clearEntityKeys()
-                                .createAction(ActionDefinition.LMS_SETUP_VIEW_FROM_LIST))
+                        .withDefaultAction(actionBuilder
+                                .newAction(ActionDefinition.LMS_SETUP_VIEW_FROM_LIST)
+                                .create())
                         .compose(content);
 
         // propagate content actions to action-pane
         final GrantCheck userGrant = currentUser.grantCheck(EntityType.LMS_SETUP);
-        pageContext.clearEntityKeys()
+        actionBuilder
 
-                .createAction(ActionDefinition.LMS_SETUP_NEW)
+                .newAction(ActionDefinition.LMS_SETUP_NEW)
                 .publishIf(userGrant::iw)
 
-                .createAction(ActionDefinition.LMS_SETUP_VIEW_FROM_LIST)
+                .newAction(ActionDefinition.LMS_SETUP_VIEW_FROM_LIST)
                 .withSelect(table::getSelection, PageAction::applySingleSelection, EMPTY_SELECTION_TEXT_KEY)
                 .publishIf(() -> table.hasAnyContent())
 
-                .createAction(ActionDefinition.LMS_SETUP_MODIFY_FROM_LIST)
+                .newAction(ActionDefinition.LMS_SETUP_MODIFY_FROM_LIST)
                 .withSelect(table::getSelection, PageAction::applySingleSelection, EMPTY_SELECTION_TEXT_KEY)
                 .publishIf(() -> userGrant.im() && table.hasAnyContent());
 
diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/content/MainPage.java b/src/main/java/ch/ethz/seb/sebserver/gui/content/MainPage.java
index 654bfe45..9f70bad2 100644
--- a/src/main/java/ch/ethz/seb/sebserver/gui/content/MainPage.java
+++ b/src/main/java/ch/ethz/seb/sebserver/gui/content/MainPage.java
@@ -26,11 +26,11 @@ import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
 import ch.ethz.seb.sebserver.gui.content.activity.ActivitiesPane;
 import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey;
 import ch.ethz.seb.sebserver.gui.service.page.PageContext;
+import ch.ethz.seb.sebserver.gui.service.page.PageService;
 import ch.ethz.seb.sebserver.gui.service.page.TemplateComposer;
 import ch.ethz.seb.sebserver.gui.service.page.event.ActionEvent;
 import ch.ethz.seb.sebserver.gui.service.page.event.ActionEventListener;
 import ch.ethz.seb.sebserver.gui.service.page.event.PageEventListener;
-import ch.ethz.seb.sebserver.gui.service.page.impl.MainPageState;
 import ch.ethz.seb.sebserver.gui.widget.WidgetFactory;
 import ch.ethz.seb.sebserver.gui.widget.WidgetFactory.ImageIcon;
 
@@ -41,8 +41,6 @@ public class MainPage implements TemplateComposer {
 
     static final Logger log = LoggerFactory.getLogger(MainPage.class);
 
-    public static final String ATTR_MAIN_PAGE_STATE = "MAIN_PAGE_STATE";
-
     private static final int ACTIVITY_PANE_WEIGHT = 15;
     private static final int CONTENT_PANE_WEIGHT = 65;
     private static final int ACTION_PANE_WEIGHT = 20;
@@ -54,14 +52,19 @@ public class MainPage implements TemplateComposer {
     private static final int[] OPENED_SASH_WEIGHTS = new int[] { 0, 100, 0 };
 
     private final WidgetFactory widgetFactory;
+    private final PageService pageStateService;
+
+    public MainPage(
+            final WidgetFactory widgetFactory,
+            final PageService pageStateService) {
 
-    public MainPage(final WidgetFactory widgetFactory) {
         this.widgetFactory = widgetFactory;
+        this.pageStateService = pageStateService;
     }
 
     @Override
     public void compose(final PageContext pageContext) {
-        MainPageState.clear();
+        this.pageStateService.clear();
 
         final Composite parent = pageContext.getParent();
         parent.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
@@ -123,7 +126,7 @@ public class MainPage implements TemplateComposer {
         contentObjects.setData(
                 PageEventListener.LISTENER_ATTRIBUTE_KEY,
                 new ContentActionEventListener(event -> pageContext.composerService().compose(
-                        event.action.definition.contentPaneComposer,
+                        event.action.definition.targetState.contentPaneComposer(),
                         event.action.pageContext().copyOf(contentObjects)), 2));
 
         final Composite actionPane = new Composite(mainSash, SWT.NONE);
@@ -134,7 +137,7 @@ public class MainPage implements TemplateComposer {
         actionPane.setData(
                 PageEventListener.LISTENER_ATTRIBUTE_KEY,
                 new ContentActionEventListener(event -> pageContext.composerService().compose(
-                        event.action.definition.actionPaneComposer,
+                        event.action.definition.targetState.actionPaneComposer(),
                         event.action.pageContext().copyOf(actionPane)), 1));
 
         pageContext.composerService().compose(
diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/content/QuizDiscoveryList.java b/src/main/java/ch/ethz/seb/sebserver/gui/content/QuizDiscoveryList.java
index 05713140..91ecbe44 100644
--- a/src/main/java/ch/ethz/seb/sebserver/gui/content/QuizDiscoveryList.java
+++ b/src/main/java/ch/ethz/seb/sebserver/gui/content/QuizDiscoveryList.java
@@ -22,15 +22,16 @@ import ch.ethz.seb.sebserver.gbl.model.institution.LmsSetup;
 import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
 import ch.ethz.seb.sebserver.gui.content.action.ActionDefinition;
 import ch.ethz.seb.sebserver.gui.form.FormBuilder;
-import ch.ethz.seb.sebserver.gui.form.PageFormService;
 import ch.ethz.seb.sebserver.gui.service.ResourceService;
 import ch.ethz.seb.sebserver.gui.service.i18n.I18nSupport;
 import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey;
-import ch.ethz.seb.sebserver.gui.service.page.ModalInputDialog;
-import ch.ethz.seb.sebserver.gui.service.page.PageAction;
 import ch.ethz.seb.sebserver.gui.service.page.PageContext;
 import ch.ethz.seb.sebserver.gui.service.page.PageContext.AttributeKeys;
+import ch.ethz.seb.sebserver.gui.service.page.PageService;
+import ch.ethz.seb.sebserver.gui.service.page.PageService.PageActionBuilder;
 import ch.ethz.seb.sebserver.gui.service.page.TemplateComposer;
+import ch.ethz.seb.sebserver.gui.service.page.impl.ModalInputDialog;
+import ch.ethz.seb.sebserver.gui.service.page.impl.PageAction;
 import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestService;
 import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.quiz.GetQuizzes;
 import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser;
@@ -70,17 +71,16 @@ public class QuizDiscoveryList implements TemplateComposer {
     // dependencies
     private final WidgetFactory widgetFactory;
     private final ResourceService resourceService;
-    private final PageFormService pageFormService;
+    private final PageService pageService;
     private final int pageSize;
 
     protected QuizDiscoveryList(
-            final PageFormService pageFormService,
-            final WidgetFactory widgetFactory,
+            final PageService pageService,
             final ResourceService resourceService,
             @Value("${sebserver.gui.list.page.size}") final Integer pageSize) {
 
-        this.pageFormService = pageFormService;
-        this.widgetFactory = widgetFactory;
+        this.pageService = pageService;
+        this.widgetFactory = pageService.getWidgetFactory();
         this.resourceService = resourceService;
         this.pageSize = (pageSize != null) ? pageSize : 20;
 
@@ -101,9 +101,11 @@ public class QuizDiscoveryList implements TemplateComposer {
                 pageContext.getParent(),
                 TITLE_TEXT_KEY);
 
+        final PageActionBuilder actionBuilder = this.pageService.pageActionBuilder(pageContext.clearEntityKeys());
+
         // table
         final EntityTable<QuizData> table =
-                this.widgetFactory.entityTableBuilder(restService.getRestCall(GetQuizzes.class))
+                this.pageService.entityTableBuilder(restService.getRestCall(GetQuizzes.class))
                         .withEmptyMessage(EMPTY_LIST_TEXT_KEY)
                         .withPaging(this.pageSize)
                         .withColumn(new ColumnDefinition<>(
@@ -133,22 +135,22 @@ public class QuizDiscoveryList implements TemplateComposer {
                                         i18nSupport.getUsersTimeZoneTitleSuffix()),
                                 quizData -> quizData.endTime,
                                 true))
-                        .withDefaultAction(t -> pageContext
-                                .clearEntityKeys()
-                                .createAction(ActionDefinition.QUIZ_DISCOVERY_SHOW_DETAILS)
+                        .withDefaultAction(t -> actionBuilder
+                                .newAction(ActionDefinition.QUIZ_DISCOVERY_SHOW_DETAILS)
                                 .withExec(action -> this.showDetails(action, t.getSelectedROWData()))
-                                .noEventPropagation())
+                                .noEventPropagation()
+                                .create())
                         .compose(content);
 
         // propagate content actions to action-pane
         final GrantCheck lmsSetupGrant = currentUser.grantCheck(EntityType.LMS_SETUP);
         final GrantCheck examGrant = currentUser.grantCheck(EntityType.EXAM);
-        pageContext.clearEntityKeys()
+        actionBuilder
 
-                .createAction(ActionDefinition.LMS_SETUP_NEW)
+                .newAction(ActionDefinition.LMS_SETUP_NEW)
                 .publishIf(lmsSetupGrant::iw)
 
-                .createAction(ActionDefinition.QUIZ_DISCOVERY_SHOW_DETAILS)
+                .newAction(ActionDefinition.QUIZ_DISCOVERY_SHOW_DETAILS)
                 .withSelect(
                         table::getSelection,
                         action -> this.showDetails(action, table.getSelectedROWData()),
@@ -156,7 +158,7 @@ public class QuizDiscoveryList implements TemplateComposer {
                 .noEventPropagation()
                 .publishIf(table::hasAnyContent)
 
-                .createAction(ActionDefinition.QUIZ_DISCOVERY_EXAM_IMPORT)
+                .newAction(ActionDefinition.QUIZ_DISCOVERY_EXAM_IMPORT)
                 .withSelect(
                         table::getSelection,
                         action -> this.importQuizData(action, table),
@@ -195,7 +197,7 @@ public class QuizDiscoveryList implements TemplateComposer {
 
     private void createDetailsForm(final QuizData quizData, final PageContext pc) {
         this.widgetFactory.labelSeparator(pc.getParent());
-        this.pageFormService.getBuilder(pc, 4)
+        this.pageService.formBuilder(pc, 4)
                 .readonly(true)
                 .addField(FormBuilder.singleSelection(
                         QuizData.QUIZ_ATTR_LMS_SETUP_ID,
diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/content/UserAccountChangePasswordForm.java b/src/main/java/ch/ethz/seb/sebserver/gui/content/UserAccountChangePasswordForm.java
index dd3bb323..1c46e2c9 100644
--- a/src/main/java/ch/ethz/seb/sebserver/gui/content/UserAccountChangePasswordForm.java
+++ b/src/main/java/ch/ethz/seb/sebserver/gui/content/UserAccountChangePasswordForm.java
@@ -23,12 +23,12 @@ import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
 import ch.ethz.seb.sebserver.gui.content.action.ActionDefinition;
 import ch.ethz.seb.sebserver.gui.form.FormBuilder;
 import ch.ethz.seb.sebserver.gui.form.FormHandle;
-import ch.ethz.seb.sebserver.gui.form.PageFormService;
 import ch.ethz.seb.sebserver.gui.service.i18n.I18nSupport;
 import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey;
-import ch.ethz.seb.sebserver.gui.service.page.PageAction;
 import ch.ethz.seb.sebserver.gui.service.page.PageContext;
+import ch.ethz.seb.sebserver.gui.service.page.PageService;
 import ch.ethz.seb.sebserver.gui.service.page.TemplateComposer;
+import ch.ethz.seb.sebserver.gui.service.page.impl.PageAction;
 import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestService;
 import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.useraccount.ChangePassword;
 import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.useraccount.GetUserAccount;
@@ -46,27 +46,26 @@ import ch.ethz.seb.sebserver.gui.widget.WidgetFactory;
  * password that is also required must match the administrators current password. */
 public class UserAccountChangePasswordForm implements TemplateComposer {
 
-    private final PageFormService pageFormService;
+    private final PageService pageService;
     private final RestService restService;
     private final CurrentUser currentUser;
     private final I18nSupport i18nSupport;
 
     protected UserAccountChangePasswordForm(
-            final PageFormService pageFormService,
+            final PageService pageService,
             final RestService restService,
-            final CurrentUser currentUser,
-            final I18nSupport i18nSupport) {
+            final CurrentUser currentUser) {
 
-        this.pageFormService = pageFormService;
+        this.pageService = pageService;
         this.restService = restService;
         this.currentUser = currentUser;
-        this.i18nSupport = i18nSupport;
+        this.i18nSupport = pageService.getI18nSupport();
     }
 
     @Override
     public void compose(final PageContext pageContext) {
 
-        final WidgetFactory widgetFactory = this.pageFormService.getWidgetFactory();
+        final WidgetFactory widgetFactory = this.pageService.getWidgetFactory();
         final EntityKey entityKey = pageContext.getEntityKey();
 
         final UserInfo userInfo = this.restService
@@ -82,7 +81,7 @@ public class UserAccountChangePasswordForm implements TemplateComposer {
         final boolean ownAccount = this.currentUser.get().uuid.equals(entityKey.getModelId());
 
         // The Password Change form
-        final FormHandle<UserInfo> formHandle = this.pageFormService.getBuilder(
+        final FormHandle<UserInfo> formHandle = this.pageService.formBuilder(
                 pageContext.copyOf(content), 4)
                 .readonly(false)
                 .putStaticValueIf(() -> entityKey != null,
@@ -103,9 +102,11 @@ public class UserAccountChangePasswordForm implements TemplateComposer {
                         .withCondition(() -> entityKey != null))
                 .buildFor(this.restService.getRestCall(ChangePassword.class));
 
-        pageContext.createAction(ActionDefinition.USER_ACCOUNT_CHANGE_PASSOWRD_SAVE)
+        this.pageService.pageActionBuilder(pageContext)
+
+                .newAction(ActionDefinition.USER_ACCOUNT_CHANGE_PASSOWRD_SAVE)
                 .withExec(action -> {
-                    formHandle.processFormSave(action);
+                    final PageAction saveAction = formHandle.processFormSave(action);
                     if (ownAccount) {
                         // NOTE: in this case the user changed the password of the own account
                         //       this should cause an logout with specified message that password change
@@ -118,12 +119,15 @@ public class UserAccountChangePasswordForm implements TemplateComposer {
                                 SWT.ERROR);
                         error.open(null);
                     }
-                    return null;
+                    return saveAction;
                 })
+                .ignoreMoveAwayFromEdit()
                 .publish()
-                .createAction(ActionDefinition.USER_ACCOUNT_CANCEL_MODIFY)
-                .withExec(PageAction::onEmptyEntityKeyGoToActivityHome)
-                .withConfirm("sebserver.overall.action.modify.cancel.confirm")
+
+                .newAction(ActionDefinition.USER_ACCOUNT_CANCEL_MODIFY)
+                .withExec(action -> this.pageService.onEmptyEntityKeyGoTo(
+                        action,
+                        ActionDefinition.USER_ACCOUNT_VIEW_LIST))
                 .publish();
     }
 
diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/content/UserAccountForm.java b/src/main/java/ch/ethz/seb/sebserver/gui/content/UserAccountForm.java
index 51c5977f..b98fa088 100644
--- a/src/main/java/ch/ethz/seb/sebserver/gui/content/UserAccountForm.java
+++ b/src/main/java/ch/ethz/seb/sebserver/gui/content/UserAccountForm.java
@@ -31,15 +31,17 @@ import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
 import ch.ethz.seb.sebserver.gui.content.action.ActionDefinition;
 import ch.ethz.seb.sebserver.gui.form.FormBuilder;
 import ch.ethz.seb.sebserver.gui.form.FormHandle;
-import ch.ethz.seb.sebserver.gui.form.PageFormService;
 import ch.ethz.seb.sebserver.gui.service.ResourceService;
 import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey;
-import ch.ethz.seb.sebserver.gui.service.page.PageAction;
 import ch.ethz.seb.sebserver.gui.service.page.PageContext;
-import ch.ethz.seb.sebserver.gui.service.page.PageUtils;
+import ch.ethz.seb.sebserver.gui.service.page.PageService;
 import ch.ethz.seb.sebserver.gui.service.page.TemplateComposer;
+import ch.ethz.seb.sebserver.gui.service.page.impl.PageAction;
+import ch.ethz.seb.sebserver.gui.service.page.impl.PageUtils;
 import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestService;
 import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.institution.GetInstitution;
+import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.useraccount.ActivateUserAccount;
+import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.useraccount.DeactivateUserAccount;
 import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.useraccount.GetUserAccount;
 import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.useraccount.NewUserAccount;
 import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.useraccount.SaveUserAccount;
@@ -54,14 +56,14 @@ public class UserAccountForm implements TemplateComposer {
 
     private static final Logger log = LoggerFactory.getLogger(UserAccountForm.class);
 
-    private final PageFormService pageFormService;
+    private final PageService pageService;
     private final ResourceService resourceService;
 
     protected UserAccountForm(
-            final PageFormService pageFormService,
+            final PageService pageService,
             final ResourceService resourceService) {
 
-        this.pageFormService = pageFormService;
+        this.pageService = pageService;
         this.resourceService = resourceService;
     }
 
@@ -69,7 +71,7 @@ public class UserAccountForm implements TemplateComposer {
     public void compose(final PageContext pageContext) {
         final CurrentUser currentUser = this.resourceService.getCurrentUser();
         final RestService restService = this.resourceService.getRestService();
-        final WidgetFactory widgetFactory = this.pageFormService.getWidgetFactory();
+        final WidgetFactory widgetFactory = this.pageService.getWidgetFactory();
 
         final UserInfo user = currentUser.get();
         final EntityKey entityKey = pageContext.getEntityKey();
@@ -127,7 +129,7 @@ public class UserAccountForm implements TemplateComposer {
                 titleKey);
 
         // The UserAccount form
-        final FormHandle<UserInfo> formHandle = this.pageFormService.getBuilder(
+        final FormHandle<UserInfo> formHandle = this.pageService.formBuilder(
                 formContext.copyOf(content), 4)
                 .readonly(readonly)
                 .putStaticValueIf(isNotNew,
@@ -187,46 +189,48 @@ public class UserAccountForm implements TemplateComposer {
                         : restService.getRestCall(SaveUserAccount.class));
 
         // propagate content actions to action-pane
-        formContext.clearEntityKeys()
+        this.pageService.pageActionBuilder(formContext.clearEntityKeys())
 
-                .createAction(ActionDefinition.USER_ACCOUNT_NEW)
+                .newAction(ActionDefinition.USER_ACCOUNT_NEW)
                 .publishIf(() -> writeGrant && readonly && institutionActive)
 
-                .createAction(ActionDefinition.USER_ACCOUNT_MODIFY)
+                .newAction(ActionDefinition.USER_ACCOUNT_MODIFY)
                 .withEntityKey(entityKey)
                 .publishIf(() -> modifyGrant && readonly && institutionActive)
 
-                .createAction(ActionDefinition.USER_ACCOUNT_CHANGE_PASSOWRD)
+                .newAction(ActionDefinition.USER_ACCOUNT_CHANGE_PASSOWRD)
                 .withEntityKey(entityKey)
                 .publishIf(() -> modifyGrant && readonly && institutionActive && userAccount.isActive())
 
-                .createAction(ActionDefinition.USER_ACCOUNT_DEACTIVATE)
+                .newAction(ActionDefinition.USER_ACCOUNT_DEACTIVATE)
                 .withEntityKey(entityKey)
-                .withExec(restService::activation)
+                .withSimpleRestCall(restService, DeactivateUserAccount.class)
                 .withConfirm(PageUtils.confirmDeactivation(userAccount, restService))
                 .publishIf(() -> writeGrant && readonly && institutionActive && userAccount.isActive())
 
-                .createAction(ActionDefinition.USER_ACCOUNT_ACTIVATE)
+                .newAction(ActionDefinition.USER_ACCOUNT_ACTIVATE)
                 .withEntityKey(entityKey)
-                .withExec(restService::activation)
+                .withSimpleRestCall(restService, ActivateUserAccount.class)
                 .publishIf(() -> writeGrant && readonly && institutionActive && !userAccount.isActive())
 
-                .createAction(ActionDefinition.USER_ACCOUNT_SAVE)
+                .newAction(ActionDefinition.USER_ACCOUNT_SAVE)
                 .withEntityKey(entityKey)
                 .withExec(action -> {
-                    final PageAction postChanges = formHandle.processFormSave(action);
+                    final PageAction saveAction = formHandle.processFormSave(action);
                     if (ownAccount) {
                         currentUser.refresh();
                         pageContext.forwardToMainPage();
                     }
-                    return postChanges;
+                    return saveAction;
                 })
+                .ignoreMoveAwayFromEdit()
                 .publishIf(() -> !readonly)
 
-                .createAction(ActionDefinition.USER_ACCOUNT_CANCEL_MODIFY)
+                .newAction(ActionDefinition.USER_ACCOUNT_CANCEL_MODIFY)
                 .withEntityKey(entityKey)
-                .withExec(PageAction::onEmptyEntityKeyGoToActivityHome)
-                .withConfirm("sebserver.overall.action.modify.cancel.confirm")
+                .withExec(action -> this.pageService.onEmptyEntityKeyGoTo(
+                        action,
+                        ActionDefinition.USER_ACCOUNT_VIEW_LIST))
                 .publishIf(() -> !readonly);
     }
 
diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/content/UserAccountList.java b/src/main/java/ch/ethz/seb/sebserver/gui/content/UserAccountList.java
index b949df49..2b835e9b 100644
--- a/src/main/java/ch/ethz/seb/sebserver/gui/content/UserAccountList.java
+++ b/src/main/java/ch/ethz/seb/sebserver/gui/content/UserAccountList.java
@@ -26,9 +26,11 @@ import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
 import ch.ethz.seb.sebserver.gui.content.action.ActionDefinition;
 import ch.ethz.seb.sebserver.gui.service.ResourceService;
 import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey;
-import ch.ethz.seb.sebserver.gui.service.page.PageAction;
 import ch.ethz.seb.sebserver.gui.service.page.PageContext;
+import ch.ethz.seb.sebserver.gui.service.page.PageService;
+import ch.ethz.seb.sebserver.gui.service.page.PageService.PageActionBuilder;
 import ch.ethz.seb.sebserver.gui.service.page.TemplateComposer;
+import ch.ethz.seb.sebserver.gui.service.page.impl.PageAction;
 import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestService;
 import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.useraccount.GetUserAccounts;
 import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser;
@@ -73,16 +75,16 @@ public class UserAccountList implements TemplateComposer {
     private final TableFilterAttribute languageFilter;
 
     // dependencies
-    private final WidgetFactory widgetFactory;
+    private final PageService pageService;
     private final ResourceService resourceService;
     private final int pageSize;
 
     protected UserAccountList(
-            final WidgetFactory widgetFactory,
+            final PageService pageService,
             final ResourceService resourceService,
             @Value("${sebserver.gui.list.page.size}") final Integer pageSize) {
 
-        this.widgetFactory = widgetFactory;
+        this.pageService = pageService;
         this.resourceService = resourceService;
         this.pageSize = (pageSize != null) ? pageSize : 20;
 
@@ -99,17 +101,19 @@ public class UserAccountList implements TemplateComposer {
 
     @Override
     public void compose(final PageContext pageContext) {
+        final WidgetFactory widgetFactory = this.pageService.getWidgetFactory();
         final CurrentUser currentUser = this.resourceService.getCurrentUser();
         final RestService restService = this.resourceService.getRestService();
         // content page layout with title
-        final Composite content = this.widgetFactory.defaultPageLayout(
+        final Composite content = widgetFactory.defaultPageLayout(
                 pageContext.getParent(),
                 TITLE_TEXT_KEY);
 
         final BooleanSupplier isSEBAdmin = () -> currentUser.get().hasRole(UserRole.SEB_SERVER_ADMIN);
+        final PageActionBuilder actionBuilder = this.pageService.pageActionBuilder(pageContext.clearEntityKeys());
 
         // table
-        final EntityTable<UserInfo> table = this.widgetFactory.entityTableBuilder(
+        final EntityTable<UserInfo> table = this.pageService.entityTableBuilder(
                 restService.getRestCall(GetUserAccounts.class))
 
                 .withEmptyMessage(new LocTextKey("sebserver.useraccount.list.empty"))
@@ -150,30 +154,30 @@ public class UserAccountList implements TemplateComposer {
                         ACTIVE_TEXT_KEY,
                         entity -> entity.active,
                         true))
-                .withDefaultAction(pageContext
-                        .clearEntityKeys()
-                        .createAction(ActionDefinition.USER_ACCOUNT_VIEW_FROM_LIST))
+                .withDefaultAction(actionBuilder
+                        .newAction(ActionDefinition.USER_ACCOUNT_VIEW_FROM_LIST)
+                        .create())
                 .compose(content);
 
         // propagate content actions to action-pane
         final GrantCheck userGrant = currentUser.grantCheck(EntityType.USER);
-        pageContext.clearEntityKeys()
+        actionBuilder
 
-                .createAction(ActionDefinition.USER_ACCOUNT_NEW)
+                .newAction(ActionDefinition.USER_ACCOUNT_NEW)
                 .publishIf(userGrant::iw)
 
-                .createAction(ActionDefinition.USER_ACCOUNT_VIEW_FROM_LIST)
+                .newAction(ActionDefinition.USER_ACCOUNT_VIEW_FROM_LIST)
                 .withSelect(table::getSelection, PageAction::applySingleSelection, EMPTY_SELECTION_TEXT_KEY)
                 .publishIf(() -> table.hasAnyContent())
 
-                .createAction(ActionDefinition.USER_ACCOUNT_MODIFY_FROM_LIST)
+                .newAction(ActionDefinition.USER_ACCOUNT_MODIFY_FROM_LIST)
                 .withSelect(table::getSelection, PageAction::applySingleSelection, EMPTY_SELECTION_TEXT_KEY)
                 .publishIf(() -> userGrant.im() && table.hasAnyContent());
     }
 
     private String getLocaleDisplayText(final UserInfo userInfo) {
         return (userInfo.language != null)
-                ? userInfo.language.getDisplayLanguage(this.widgetFactory.getI18nSupport().getCurrentLocale())
+                ? userInfo.language.getDisplayLanguage(this.pageService.getI18nSupport().getCurrentLocale())
                 : Constants.EMPTY_NOTE;
     }
 
diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/content/action/ActionDefinition.java b/src/main/java/ch/ethz/seb/sebserver/gui/content/action/ActionDefinition.java
index e2393c67..ceef7e10 100644
--- a/src/main/java/ch/ethz/seb/sebserver/gui/content/action/ActionDefinition.java
+++ b/src/main/java/ch/ethz/seb/sebserver/gui/content/action/ActionDefinition.java
@@ -8,471 +8,276 @@
 
 package ch.ethz.seb.sebserver.gui.content.action;
 
-import ch.ethz.seb.sebserver.gui.content.ExamForm;
-import ch.ethz.seb.sebserver.gui.content.ExamList;
-import ch.ethz.seb.sebserver.gui.content.IndicatorForm;
-import ch.ethz.seb.sebserver.gui.content.InstitutionForm;
-import ch.ethz.seb.sebserver.gui.content.InstitutionList;
-import ch.ethz.seb.sebserver.gui.content.LmsSetupForm;
-import ch.ethz.seb.sebserver.gui.content.LmsSetupList;
-import ch.ethz.seb.sebserver.gui.content.QuizDiscoveryList;
-import ch.ethz.seb.sebserver.gui.content.UserAccountChangePasswordForm;
-import ch.ethz.seb.sebserver.gui.content.UserAccountForm;
-import ch.ethz.seb.sebserver.gui.content.UserAccountList;
+import ch.ethz.seb.sebserver.gui.content.activity.PageStateDefinition;
 import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey;
-import ch.ethz.seb.sebserver.gui.service.page.TemplateComposer;
-import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCall;
-import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.exam.ActivateExam;
-import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.exam.DeactivateExam;
-import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.institution.ActivateInstitution;
-import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.institution.DeactivateInstitution;
-import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.lmssetup.ActivateLmsSetup;
-import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.lmssetup.DeactivateLmsSetup;
-import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.useraccount.ActivateUserAccount;
-import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.useraccount.DeactivateUserAccount;
+import ch.ethz.seb.sebserver.gui.service.page.PageState;
 import ch.ethz.seb.sebserver.gui.widget.WidgetFactory.ImageIcon;
 
 /** Enumeration of static action data for each action within the SEB Server GUI */
-// TODO add category to allow easy positioning of actions later
 public enum ActionDefinition {
 
     INSTITUTION_VIEW_LIST(
             new LocTextKey("sebserver.institution.action.list"),
-            InstitutionList.class),
+            PageStateDefinition.INSTITUTION_LIST),
     INSTITUTION_VIEW_FORM(
             new LocTextKey("sebserver.institution.action.form"),
-            InstitutionForm.class,
-            INSTITUTION_VIEW_LIST),
+            PageStateDefinition.INSTITUTION_VIEW),
     INSTITUTION_NEW(
             new LocTextKey("sebserver.institution.action.new"),
             ImageIcon.NEW,
-            InstitutionForm.class,
-            INSTITUTION_VIEW_LIST,
-            false),
+            PageStateDefinition.INSTITUTION_EDIT),
     INSTITUTION_VIEW_FROM_LIST(
             new LocTextKey("sebserver.institution.action.list.view"),
             ImageIcon.SHOW,
-            InstitutionForm.class,
-            INSTITUTION_VIEW_LIST,
+            PageStateDefinition.INSTITUTION_VIEW,
             ActionCategory.INSTITUTION_LIST),
     INSTITUTION_MODIFY_FROM_LIST(
             new LocTextKey("sebserver.institution.action.list.modify"),
             ImageIcon.EDIT,
-            InstitutionForm.class,
-            INSTITUTION_VIEW_LIST,
-            ActionCategory.INSTITUTION_LIST,
-            false),
+            PageStateDefinition.INSTITUTION_EDIT,
+            ActionCategory.INSTITUTION_LIST),
     INSTITUTION_MODIFY(
             new LocTextKey("sebserver.institution.action.modify"),
             ImageIcon.EDIT,
-            InstitutionForm.class,
-            INSTITUTION_VIEW_LIST,
-            ActionCategory.FORM,
-            false),
+            PageStateDefinition.INSTITUTION_EDIT,
+            ActionCategory.FORM),
     INSTITUTION_CANCEL_MODIFY(
             new LocTextKey("sebserver.overall.action.modify.cancel"),
             ImageIcon.CANCEL,
-            InstitutionForm.class,
-            INSTITUTION_VIEW_LIST,
-            ActionCategory.FORM,
-            true),
+            PageStateDefinition.INSTITUTION_VIEW,
+            ActionCategory.FORM),
     INSTITUTION_SAVE(
             new LocTextKey("sebserver.institution.action.save"),
             ImageIcon.SAVE,
-            InstitutionForm.class,
-            INSTITUTION_VIEW_LIST,
+            PageStateDefinition.INSTITUTION_VIEW,
             ActionCategory.FORM),
     INSTITUTION_ACTIVATE(
             new LocTextKey("sebserver.institution.action.activate"),
             ImageIcon.INACTIVE,
-            InstitutionForm.class,
-            ActivateInstitution.class,
-            INSTITUTION_VIEW_LIST,
+            PageStateDefinition.INSTITUTION_VIEW,
             ActionCategory.FORM),
     INSTITUTION_DEACTIVATE(
             new LocTextKey("sebserver.institution.action.deactivate"),
             ImageIcon.ACTIVE,
-            InstitutionForm.class,
-            DeactivateInstitution.class,
-            INSTITUTION_VIEW_LIST,
+            PageStateDefinition.INSTITUTION_VIEW,
             ActionCategory.FORM),
-    INSTITUTION_DELETE(
-            new LocTextKey("sebserver.institution.action.modify"),
-            ImageIcon.DELETE,
-            InstitutionList.class,
-            INSTITUTION_VIEW_LIST),
     INSTITUTION_EXPORT_SEB_CONFIG(
             new LocTextKey("sebserver.institution.action.export.sebconfig"),
             ImageIcon.SAVE,
-            InstitutionForm.class,
-            INSTITUTION_VIEW_LIST,
+            PageStateDefinition.INSTITUTION_VIEW,
             ActionCategory.FORM),
 
     USER_ACCOUNT_VIEW_LIST(
             new LocTextKey("sebserver.useraccount.action.list"),
-            UserAccountList.class),
+            PageStateDefinition.USER_ACCOUNT_LIST),
     USER_ACCOUNT_VIEW_FORM(
             new LocTextKey("sebserver.useraccount.action.form"),
-            UserAccountForm.class,
-            USER_ACCOUNT_VIEW_LIST),
+            PageStateDefinition.USER_ACCOUNT_VIEW),
     USER_ACCOUNT_NEW(
             new LocTextKey("sebserver.useraccount.action.new"),
             ImageIcon.NEW,
-            UserAccountForm.class,
-            USER_ACCOUNT_VIEW_LIST, false),
+            PageStateDefinition.USER_ACCOUNT_EDIT),
     USER_ACCOUNT_VIEW_FROM_LIST(
             new LocTextKey("sebserver.useraccount.action.view"),
             ImageIcon.SHOW,
-            UserAccountForm.class,
-            USER_ACCOUNT_VIEW_LIST,
+            PageStateDefinition.USER_ACCOUNT_VIEW,
             ActionCategory.USER_ACCOUNT_LIST),
     USER_ACCOUNT_MODIFY_FROM_LIST(
             new LocTextKey("sebserver.useraccount.action.list.modify"),
             ImageIcon.EDIT,
-            UserAccountForm.class,
-            USER_ACCOUNT_VIEW_LIST,
-            ActionCategory.USER_ACCOUNT_LIST,
-            false),
+            PageStateDefinition.USER_ACCOUNT_EDIT,
+            ActionCategory.USER_ACCOUNT_LIST),
     USER_ACCOUNT_MODIFY(
             new LocTextKey("sebserver.useraccount.action.modify"),
             ImageIcon.EDIT,
-            UserAccountForm.class,
-            USER_ACCOUNT_VIEW_LIST,
-            ActionCategory.FORM,
-            false),
+            PageStateDefinition.USER_ACCOUNT_EDIT,
+            ActionCategory.FORM),
     USER_ACCOUNT_CANCEL_MODIFY(
             new LocTextKey("sebserver.overall.action.modify.cancel"),
             ImageIcon.CANCEL,
-            UserAccountForm.class,
-            USER_ACCOUNT_VIEW_LIST,
-            ActionCategory.FORM,
-            true),
+            PageStateDefinition.USER_ACCOUNT_VIEW,
+            ActionCategory.FORM),
     USER_ACCOUNT_SAVE(
             new LocTextKey("sebserver.useraccount.action.save"),
             ImageIcon.SAVE,
-            UserAccountForm.class,
-            USER_ACCOUNT_VIEW_LIST,
+            PageStateDefinition.USER_ACCOUNT_VIEW,
             ActionCategory.FORM),
     USER_ACCOUNT_ACTIVATE(
             new LocTextKey("sebserver.useraccount.action.activate"),
             ImageIcon.INACTIVE,
-            UserAccountForm.class,
-            ActivateUserAccount.class,
-            USER_ACCOUNT_VIEW_LIST,
+            PageStateDefinition.USER_ACCOUNT_VIEW,
             ActionCategory.FORM),
     USER_ACCOUNT_DEACTIVATE(
             new LocTextKey("sebserver.useraccount.action.deactivate"),
             ImageIcon.ACTIVE,
-            UserAccountForm.class,
-            DeactivateUserAccount.class,
-            USER_ACCOUNT_VIEW_LIST,
+            PageStateDefinition.USER_ACCOUNT_VIEW,
             ActionCategory.FORM),
-    USER_ACCOUNT_DELETE(
-            new LocTextKey("sebserver.useraccount.action.modify"),
-            ImageIcon.DELETE,
-            UserAccountList.class,
-            USER_ACCOUNT_VIEW_LIST),
     USER_ACCOUNT_CHANGE_PASSOWRD(
             new LocTextKey("sebserver.useraccount.action.change.password"),
             ImageIcon.EDIT,
-            UserAccountChangePasswordForm.class,
-            USER_ACCOUNT_VIEW_LIST,
-            ActionCategory.FORM,
-            false),
+            PageStateDefinition.USER_ACCOUNT_PASSWORD_CHANGE,
+            ActionCategory.FORM),
     USER_ACCOUNT_CHANGE_PASSOWRD_SAVE(
             new LocTextKey("sebserver.useraccount.action.change.password.save"),
             ImageIcon.SAVE,
-            UserAccountForm.class,
-            USER_ACCOUNT_VIEW_LIST,
+            PageStateDefinition.USER_ACCOUNT_VIEW,
             ActionCategory.FORM),
 
     LMS_SETUP_VIEW_LIST(
             new LocTextKey("sebserver.lmssetup.action.list"),
-            LmsSetupList.class),
+            PageStateDefinition.LMS_SETUP_LIST),
     LMS_SETUP_NEW(
             new LocTextKey("sebserver.lmssetup.action.new"),
             ImageIcon.NEW,
-            LmsSetupForm.class,
-            LMS_SETUP_VIEW_LIST, false),
+            PageStateDefinition.LMS_SETUP_EDIT),
     LMS_SETUP_VIEW_FROM_LIST(
             new LocTextKey("sebserver.lmssetup.action.list.view"),
             ImageIcon.SHOW,
-            LmsSetupForm.class,
-            LMS_SETUP_VIEW_LIST,
+            PageStateDefinition.LMS_SETUP_VIEW,
             ActionCategory.LMS_SETUP_LIST),
     LMS_SETUP_MODIFY_FROM_LIST(
             new LocTextKey("sebserver.lmssetup.action.list.modify"),
             ImageIcon.EDIT,
-            LmsSetupForm.class,
-            LMS_SETUP_VIEW_LIST,
-            ActionCategory.LMS_SETUP_LIST,
-            false),
+            PageStateDefinition.LMS_SETUP_EDIT,
+            ActionCategory.LMS_SETUP_LIST),
     LMS_SETUP_MODIFY(
             new LocTextKey("sebserver.lmssetup.action.modify"),
             ImageIcon.EDIT,
-            LmsSetupForm.class,
-            LMS_SETUP_VIEW_LIST,
-            ActionCategory.FORM,
-            false),
+            PageStateDefinition.LMS_SETUP_EDIT,
+            ActionCategory.FORM),
     LMS_SETUP_TEST(
             new LocTextKey("sebserver.lmssetup.action.test"),
             ImageIcon.TEST,
-            LmsSetupForm.class,
-            LMS_SETUP_VIEW_LIST,
+            PageStateDefinition.LMS_SETUP_VIEW,
             ActionCategory.FORM),
     LMS_SETUP_CANCEL_MODIFY(
             new LocTextKey("sebserver.overall.action.modify.cancel"),
             ImageIcon.CANCEL,
-            LmsSetupForm.class,
-            LMS_SETUP_VIEW_LIST,
-            ActionCategory.FORM,
-            true),
+            PageStateDefinition.LMS_SETUP_VIEW,
+            ActionCategory.FORM),
     LMS_SETUP_SAVE(
             new LocTextKey("sebserver.lmssetup.action.save"),
             ImageIcon.SAVE,
-            LmsSetupForm.class,
-            LMS_SETUP_VIEW_LIST,
+            PageStateDefinition.LMS_SETUP_VIEW,
             ActionCategory.FORM),
     LMS_SETUP_ACTIVATE(
             new LocTextKey("sebserver.lmssetup.action.activate"),
             ImageIcon.INACTIVE,
-            LmsSetupForm.class,
-            ActivateLmsSetup.class,
-            LMS_SETUP_VIEW_LIST,
+            PageStateDefinition.LMS_SETUP_VIEW,
             ActionCategory.FORM),
     LMS_SETUP_DEACTIVATE(
             new LocTextKey("sebserver.lmssetup.action.deactivate"),
             ImageIcon.ACTIVE,
-            LmsSetupForm.class,
-            DeactivateLmsSetup.class,
-            LMS_SETUP_VIEW_LIST,
+            PageStateDefinition.LMS_SETUP_VIEW,
             ActionCategory.FORM),
 
     QUIZ_DISCOVERY_VIEW_LIST(
             new LocTextKey("sebserver.quizdiscovery.action.list"),
-            QuizDiscoveryList.class),
+            PageStateDefinition.QUIZ_LIST),
     QUIZ_DISCOVERY_SHOW_DETAILS(
             new LocTextKey("sebserver.quizdiscovery.action.details"),
             ImageIcon.SHOW,
+            null,
             ActionCategory.QUIZ_LIST),
     QUIZ_DISCOVERY_EXAM_IMPORT(
             new LocTextKey("sebserver.quizdiscovery.action.import"),
             ImageIcon.IMPORT,
-            ExamForm.class,
-            QUIZ_DISCOVERY_VIEW_LIST,
-            ActionCategory.QUIZ_LIST,
-            false),
+            PageStateDefinition.EXAM_EDIT,
+            ActionCategory.QUIZ_LIST),
 
     EXAM_VIEW_LIST(
             new LocTextKey("sebserver.exam.action.list"),
-            ExamList.class),
+            PageStateDefinition.EXAM_LIST),
     EXAM_IMPORT(
             new LocTextKey("sebserver.exam.action.import"),
             ImageIcon.IMPORT,
-            QuizDiscoveryList.class,
-            QUIZ_DISCOVERY_VIEW_LIST,
-            false),
+            PageStateDefinition.QUIZ_LIST),
     EXAM_VIEW_FROM_LIST(
             new LocTextKey("sebserver.exam.action.list.view"),
             ImageIcon.SHOW,
-            ExamForm.class,
-            EXAM_VIEW_LIST,
+            PageStateDefinition.EXAM_VIEW,
             ActionCategory.EXAM_LIST),
     EXAM_MODIFY_FROM_LIST(
             new LocTextKey("sebserver.exam.action.list.modify"),
             ImageIcon.EDIT,
-            ExamForm.class,
-            EXAM_VIEW_LIST,
-            ActionCategory.EXAM_LIST,
-            false),
+            PageStateDefinition.EXAM_EDIT,
+            ActionCategory.EXAM_LIST),
     EXAM_MODIFY(
             new LocTextKey("sebserver.exam.action.modify"),
             ImageIcon.EDIT,
-            ExamForm.class,
-            EXAM_VIEW_LIST,
-            ActionCategory.FORM,
-            false),
+            PageStateDefinition.EXAM_EDIT,
+            ActionCategory.FORM),
     EXAM_CANCEL_MODIFY(
             new LocTextKey("sebserver.overall.action.modify.cancel"),
             ImageIcon.CANCEL,
-            ExamForm.class,
-            EXAM_VIEW_LIST,
-            ActionCategory.FORM,
-            true),
+            PageStateDefinition.EXAM_VIEW,
+            ActionCategory.FORM),
     EXAM_SAVE(
             new LocTextKey("sebserver.exam.action.save"),
             ImageIcon.SAVE,
-            ExamForm.class,
-            EXAM_VIEW_LIST,
+            PageStateDefinition.EXAM_VIEW,
             ActionCategory.FORM),
     EXAM_ACTIVATE(
             new LocTextKey("sebserver.exam.action.activate"),
             ImageIcon.INACTIVE,
-            ExamForm.class,
-            ActivateExam.class,
-            EXAM_VIEW_LIST,
+            PageStateDefinition.EXAM_VIEW,
             ActionCategory.FORM),
     EXAM_DEACTIVATE(
             new LocTextKey("sebserver.exam.action.deactivate"),
             ImageIcon.ACTIVE,
-            ExamForm.class,
-            DeactivateExam.class,
-            EXAM_VIEW_LIST,
+            PageStateDefinition.EXAM_VIEW,
             ActionCategory.FORM),
 
     EXAM_INDICATOR_NEW(
             new LocTextKey("sebserver.exam.indicator.action.list.new"),
             ImageIcon.NEW,
-            IndicatorForm.class,
-            EXAM_VIEW_FROM_LIST,
-            false),
+            PageStateDefinition.INDICATOR_EDIT),
     EXAM_INDICATOR_MODIFY_FROM_LIST(
             new LocTextKey("sebserver.exam.indicator.action.list.modify"),
             ImageIcon.EDIT,
-            IndicatorForm.class,
-            EXAM_VIEW_FROM_LIST,
-            ActionCategory.INDICATOR_LIST,
-            false),
+            PageStateDefinition.INDICATOR_EDIT,
+            ActionCategory.INDICATOR_LIST),
     EXAM_INDICATOR_DELETE_FROM_LIST(
             new LocTextKey("sebserver.exam.indicator.action.list.delete"),
             ImageIcon.DELETE,
-            ExamForm.class,
-            EXAM_VIEW_FROM_LIST,
-            ActionCategory.INDICATOR_LIST,
-            true),
+            PageStateDefinition.EXAM_VIEW,
+            ActionCategory.INDICATOR_LIST),
     EXAM_INDICATOR_SAVE(
             new LocTextKey("sebserver.exam.indicator.action.save"),
             ImageIcon.SAVE,
-            ExamForm.class,
-            EXAM_VIEW_FROM_LIST,
+            PageStateDefinition.EXAM_VIEW,
             ActionCategory.FORM),
     EXAM_INDICATOR_CANCEL_MODIFY(
             new LocTextKey("sebserver.overall.action.modify.cancel"),
             ImageIcon.CANCEL,
-            ExamForm.class,
-            EXAM_VIEW_FROM_LIST,
-            ActionCategory.FORM,
-            true),
-    TEST_ACTION(
-            new LocTextKey("TEST"),
-            ImageIcon.TEST,
-            ExamList.class,
-            EXAM_VIEW_LIST,
+            PageStateDefinition.EXAM_VIEW,
             ActionCategory.FORM),
 
     ;
 
     public final LocTextKey title;
     public final ImageIcon icon;
-    public final Class<? extends TemplateComposer> contentPaneComposer;
-    public final Class<? extends TemplateComposer> actionPaneComposer;
-    public final Class<? extends RestCall<?>> restCallType;
-    public final ActionDefinition activityAlias;
+    public final PageState targetState;
     public final ActionCategory category;
-    public final Boolean readonly;
 
-    private ActionDefinition(
-            final LocTextKey title,
-            final Class<? extends TemplateComposer> contentPaneComposer) {
-
-        this(title, null, contentPaneComposer, ActionPane.class, null, null, null, null);
+    private ActionDefinition(final LocTextKey title, final PageState targetState) {
+        this(title, null, targetState, ActionCategory.VARIA);
     }
 
-    private ActionDefinition(
-            final LocTextKey title,
-            final Class<? extends TemplateComposer> contentPaneComposer,
-            final ActionDefinition activityAlias) {
-
-        this(title, null, contentPaneComposer, ActionPane.class, null, activityAlias, null, null);
+    private ActionDefinition(final LocTextKey title, final ImageIcon icon, final PageState targetState) {
+        this(title, icon, targetState, ActionCategory.VARIA);
     }
 
     private ActionDefinition(
             final LocTextKey title,
             final ImageIcon icon,
+            final PageState targetState,
             final ActionCategory category) {
 
-        this(title, icon, null, ActionPane.class, null, null, category, null);
-    }
-
-    private ActionDefinition(
-            final LocTextKey title,
-            final ImageIcon icon,
-            final Class<? extends TemplateComposer> contentPaneComposer,
-            final ActionDefinition activityAlias) {
-
-        this(title, icon, contentPaneComposer, ActionPane.class, null, activityAlias, null, null);
-    }
-
-    private ActionDefinition(
-            final LocTextKey title,
-            final ImageIcon icon,
-            final Class<? extends TemplateComposer> contentPaneComposer,
-            final ActionDefinition activityAlias,
-            final ActionCategory category) {
-
-        this(title, icon, contentPaneComposer, ActionPane.class, null, activityAlias, category, null);
-    }
-
-    private ActionDefinition(
-            final LocTextKey title,
-            final ImageIcon icon,
-            final Class<? extends TemplateComposer> contentPaneComposer,
-            final Class<? extends RestCall<?>> restCallType,
-            final ActionDefinition activityAlias) {
-
-        this(title, icon, contentPaneComposer, ActionPane.class, restCallType, activityAlias, null, null);
-    }
-
-    private ActionDefinition(
-            final LocTextKey title,
-            final ImageIcon icon,
-            final Class<? extends TemplateComposer> contentPaneComposer,
-            final Class<? extends RestCall<?>> restCallType,
-            final ActionDefinition activityAlias,
-            final ActionCategory category) {
-
-        this(title, icon, contentPaneComposer, ActionPane.class, restCallType, activityAlias, category, null);
-    }
-
-    private ActionDefinition(
-            final LocTextKey title,
-            final ImageIcon icon,
-            final Class<? extends TemplateComposer> contentPaneComposer,
-            final ActionDefinition activityAlias,
-            final boolean readonly) {
-
-        this(title, icon, contentPaneComposer, ActionPane.class, null, activityAlias, null, readonly);
-    }
-
-    private ActionDefinition(
-            final LocTextKey title,
-            final ImageIcon icon,
-            final Class<? extends TemplateComposer> contentPaneComposer,
-            final ActionDefinition activityAlias,
-            final ActionCategory category,
-            final boolean readonly) {
-
-        this(title, icon, contentPaneComposer, ActionPane.class, null, activityAlias, category, readonly);
-    }
-
-    private ActionDefinition(
-            final LocTextKey title,
-            final ImageIcon icon,
-            final Class<? extends TemplateComposer> contentPaneComposer,
-            final Class<? extends TemplateComposer> actionPaneComposer,
-            final Class<? extends RestCall<?>> restCallType,
-            final ActionDefinition activityAlias,
-            final ActionCategory category,
-            final Boolean readonly) {
-
         this.title = title;
         this.icon = icon;
-        this.contentPaneComposer = contentPaneComposer;
-        this.actionPaneComposer = actionPaneComposer;
-        this.restCallType = restCallType;
-        this.activityAlias = activityAlias;
-        this.category = (category != null) ? category : ActionCategory.VARIA;
-        this.readonly = readonly;
+        this.targetState = targetState;
+        this.category = category;
     }
 
 }
diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/content/action/ActionPane.java b/src/main/java/ch/ethz/seb/sebserver/gui/content/action/ActionPane.java
index 96b9e009..bb6e3828 100644
--- a/src/main/java/ch/ethz/seb/sebserver/gui/content/action/ActionPane.java
+++ b/src/main/java/ch/ethz/seb/sebserver/gui/content/action/ActionPane.java
@@ -28,12 +28,13 @@ import org.springframework.context.annotation.Lazy;
 import org.springframework.stereotype.Component;
 
 import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey;
-import ch.ethz.seb.sebserver.gui.service.page.PageAction;
 import ch.ethz.seb.sebserver.gui.service.page.PageContext;
+import ch.ethz.seb.sebserver.gui.service.page.PageService;
 import ch.ethz.seb.sebserver.gui.service.page.TemplateComposer;
 import ch.ethz.seb.sebserver.gui.service.page.event.ActionPublishEvent;
 import ch.ethz.seb.sebserver.gui.service.page.event.ActionPublishEventListener;
 import ch.ethz.seb.sebserver.gui.service.page.event.PageEventListener;
+import ch.ethz.seb.sebserver.gui.service.page.impl.PageAction;
 import ch.ethz.seb.sebserver.gui.widget.WidgetFactory;
 import ch.ethz.seb.sebserver.gui.widget.WidgetFactory.CustomVariant;
 
@@ -43,13 +44,14 @@ public class ActionPane implements TemplateComposer {
 
     private static final String ACTION_EVENT_CALL_KEY = "ACTION_EVENT_CALL";
 
+    private final PageService pageService;
     private final WidgetFactory widgetFactory;
 
     private final Map<String, Tree> actionTrees = new HashMap<>();
 
-    public ActionPane(final WidgetFactory widgetFactory) {
-        super();
-        this.widgetFactory = widgetFactory;
+    protected ActionPane(final PageService pageService) {
+        this.pageService = pageService;
+        this.widgetFactory = pageService.getWidgetFactory();
     }
 
     @Override
@@ -161,7 +163,7 @@ public class ActionPane implements TemplateComposer {
             final TreeItem treeItem = (TreeItem) event.item;
 
             final PageAction action = (PageAction) treeItem.getData(ACTION_EVENT_CALL_KEY);
-            action.run();
+            this.pageService.executePageAction(action);
 
             if (!treeItem.isDisposed()) {
                 treeItem.getParent().deselectAll();
diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/content/activity/ActivitiesPane.java b/src/main/java/ch/ethz/seb/sebserver/gui/content/activity/ActivitiesPane.java
index bee8f085..65e9d8fb 100644
--- a/src/main/java/ch/ethz/seb/sebserver/gui/content/activity/ActivitiesPane.java
+++ b/src/main/java/ch/ethz/seb/sebserver/gui/content/activity/ActivitiesPane.java
@@ -24,14 +24,17 @@ import ch.ethz.seb.sebserver.gbl.model.user.UserInfo;
 import ch.ethz.seb.sebserver.gbl.model.user.UserRole;
 import ch.ethz.seb.sebserver.gui.content.action.ActionDefinition;
 import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey;
-import ch.ethz.seb.sebserver.gui.service.page.PageAction;
+import ch.ethz.seb.sebserver.gui.service.page.Activity;
 import ch.ethz.seb.sebserver.gui.service.page.PageContext;
 import ch.ethz.seb.sebserver.gui.service.page.PageContext.AttributeKeys;
+import ch.ethz.seb.sebserver.gui.service.page.PageService;
+import ch.ethz.seb.sebserver.gui.service.page.PageService.PageActionBuilder;
+import ch.ethz.seb.sebserver.gui.service.page.PageState;
 import ch.ethz.seb.sebserver.gui.service.page.TemplateComposer;
 import ch.ethz.seb.sebserver.gui.service.page.event.ActionEvent;
 import ch.ethz.seb.sebserver.gui.service.page.event.ActionEventListener;
 import ch.ethz.seb.sebserver.gui.service.page.event.PageEventListener;
-import ch.ethz.seb.sebserver.gui.service.page.impl.MainPageState;
+import ch.ethz.seb.sebserver.gui.service.page.impl.PageAction;
 import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser;
 import ch.ethz.seb.sebserver.gui.widget.WidgetFactory;
 import ch.ethz.seb.sebserver.gui.widget.WidgetFactory.CustomVariant;
@@ -44,13 +47,15 @@ public class ActivitiesPane implements TemplateComposer {
 
     private final WidgetFactory widgetFactory;
     private final CurrentUser currentUser;
+    private final PageService pageService;
 
     public ActivitiesPane(
-            final WidgetFactory widgetFactory,
-            final CurrentUser currentUser) {
+            final CurrentUser currentUser,
+            final PageService pageService) {
 
-        this.widgetFactory = widgetFactory;
+        this.widgetFactory = pageService.getWidgetFactory();
         this.currentUser = currentUser;
+        this.pageService = pageService;
     }
 
     @Override
@@ -73,27 +78,32 @@ public class ActivitiesPane implements TemplateComposer {
         //navigationGridData.horizontalIndent = 10;
         navigation.setLayoutData(navigationGridData);
 
+        final PageActionBuilder actionBuilder = this.pageService.pageActionBuilder(pageContext);
+
         // Institution
         // If current user has SEB Server Admin role, show the Institution list
         if (userInfo.hasRole(UserRole.SEB_SERVER_ADMIN)) {
             // institutions (list) as root
             final TreeItem institutions = this.widgetFactory.treeItemLocalized(
                     navigation,
-                    ActionDefinition.INSTITUTION_VIEW_LIST.title);
+                    ActivityDefinition.INSTITUTION.displayName);
             injectActivitySelection(
                     institutions,
-                    pageContext.createAction(ActionDefinition.INSTITUTION_VIEW_LIST));
+                    actionBuilder
+                            .newAction(ActionDefinition.INSTITUTION_VIEW_LIST)
+                            .create());
 
         } else {
             // otherwise show the form of the institution for current user
             final TreeItem institutions = this.widgetFactory.treeItemLocalized(
                     navigation,
-                    ActionDefinition.INSTITUTION_VIEW_FORM.title);
+                    ActivityDefinition.INSTITUTION.displayName);
             injectActivitySelection(
                     institutions,
-                    pageContext.createAction(ActionDefinition.INSTITUTION_VIEW_FORM)
+                    actionBuilder.newAction(ActionDefinition.INSTITUTION_VIEW_FORM)
                             .withEntityKey(userInfo.institutionId, EntityType.INSTITUTION)
-                            .withAttribute(AttributeKeys.READ_ONLY, "true"));
+                            .withAttribute(AttributeKeys.READ_ONLY, "true")
+                            .create());
         }
 
         // User Account
@@ -101,30 +111,35 @@ public class ActivitiesPane implements TemplateComposer {
         if (this.currentUser.hasInstitutionalPrivilege(PrivilegeType.READ_ONLY, EntityType.USER)) {
             final TreeItem userAccounts = this.widgetFactory.treeItemLocalized(
                     navigation,
-                    ActionDefinition.USER_ACCOUNT_VIEW_LIST.title);
+                    ActivityDefinition.USER_ACCOUNT.displayName);
             injectActivitySelection(
                     userAccounts,
-                    pageContext.createAction(ActionDefinition.USER_ACCOUNT_VIEW_LIST));
+                    actionBuilder
+                            .newAction(ActionDefinition.USER_ACCOUNT_VIEW_LIST)
+                            .create());
         } else {
             // otherwise show the user account form for current user
             final TreeItem userAccounts = this.widgetFactory.treeItemLocalized(
                     navigation,
-                    ActionDefinition.USER_ACCOUNT_VIEW_FORM.title);
+                    ActivityDefinition.USER_ACCOUNT.displayName);
             injectActivitySelection(
                     userAccounts,
-                    pageContext.createAction(ActionDefinition.USER_ACCOUNT_VIEW_FORM)
+                    actionBuilder.newAction(ActionDefinition.USER_ACCOUNT_VIEW_FORM)
                             .withEntityKey(this.currentUser.get().getEntityKey())
-                            .withAttribute(AttributeKeys.READ_ONLY, "true"));
+                            .withAttribute(AttributeKeys.READ_ONLY, "true")
+                            .create());
         }
 
         // LMS Setup
         if (this.currentUser.hasInstitutionalPrivilege(PrivilegeType.READ_ONLY, EntityType.LMS_SETUP)) {
             final TreeItem lmsSetup = this.widgetFactory.treeItemLocalized(
                     navigation,
-                    ActionDefinition.LMS_SETUP_VIEW_LIST.title);
+                    ActivityDefinition.LMS_SETUP.displayName);
             injectActivitySelection(
                     lmsSetup,
-                    pageContext.createAction(ActionDefinition.LMS_SETUP_VIEW_LIST));
+                    actionBuilder
+                            .newAction(ActionDefinition.LMS_SETUP_VIEW_LIST)
+                            .create());
         }
 
         // Exam (Quiz Discovery)
@@ -134,18 +149,22 @@ public class ActivitiesPane implements TemplateComposer {
             // TODO discussion if this should be visible on Activity Pane or just over the Exam activity and Import action
             final TreeItem quizDiscovery = this.widgetFactory.treeItemLocalized(
                     navigation,
-                    ActionDefinition.QUIZ_DISCOVERY_VIEW_LIST.title);
+                    ActivityDefinition.QUIZ_DISCOVERY.displayName);
             injectActivitySelection(
                     quizDiscovery,
-                    pageContext.createAction(ActionDefinition.QUIZ_DISCOVERY_VIEW_LIST));
+                    actionBuilder
+                            .newAction(ActionDefinition.QUIZ_DISCOVERY_VIEW_LIST)
+                            .create());
 
             // Exam
             final TreeItem exam = this.widgetFactory.treeItemLocalized(
                     navigation,
-                    ActionDefinition.EXAM_VIEW_LIST.title);
+                    ActivityDefinition.EXAM.displayName);
             injectActivitySelection(
                     exam,
-                    pageContext.createAction(ActionDefinition.EXAM_VIEW_LIST));
+                    actionBuilder
+                            .newAction(ActionDefinition.EXAM_VIEW_LIST)
+                            .create());
         }
 
         // TODO other activities
@@ -157,34 +176,42 @@ public class ActivitiesPane implements TemplateComposer {
                 new ActivitiesActionEventListener(navigation));
 
         // page-selection on (re)load
-        final MainPageState mainPageState = MainPageState.get();
-
-        if (mainPageState.action == null) {
-            mainPageState.action = getActivitySelection(navigation.getItem(0));
+        final PageState state = this.pageService.getCurrentState();
+        if (state == null) {
+            final TreeItem item = navigation.getItem(0);
+            final PageAction activityAction = getActivitySelection(item);
+            this.pageService.executePageAction(activityAction);
+        } else {
+            final TreeItem item = findItemByActionDefinition(navigation.getItems(), state);
+            if (item != null) {
+                navigation.select(item);
+            }
         }
-        pageContext.firePageEvent(
-                new ActionEvent(mainPageState.action, false));
-        navigation.select(navigation.getItem(0));
-
     }
 
     private void handleSelection(final PageContext composerCtx, final Event event) {
         final TreeItem treeItem = (TreeItem) event.item;
-
-        System.out.println("selected: " + treeItem);
-
-        final MainPageState mainPageState = MainPageState.get();
         final PageAction action = getActivitySelection(treeItem);
-        if (mainPageState.action.definition != action.definition) {
-            mainPageState.action = action;
-            composerCtx.firePageEvent(
-                    new ActionEvent(action, true));
-        }
+        this.pageService.executePageAction(
+                action,
+                result -> {
+                    if (result.hasError()) {
+                        final Tree tree = (Tree) event.widget;
+                        tree.deselect(treeItem);
+                        final PageState currentState = this.pageService.getCurrentState();
+                        if (currentState != null) {
+                            final TreeItem item = findItemByActionDefinition(tree.getItems(), currentState);
+                            if (item != null) {
+                                tree.select(item);
+                            }
+                        }
+                    }
+                });
     }
 
-    static final TreeItem findItemByActionDefinition(
+    private static final TreeItem findItemByActionDefinition(
             final TreeItem[] items,
-            final ActionDefinition actionDefinition,
+            final Activity activity,
             final String modelId) {
 
         if (items == null) {
@@ -197,13 +224,14 @@ public class ActivitiesPane implements TemplateComposer {
                 continue;
             }
 
+            final Activity activityAnchor = action.definition.targetState.activityAnchor();
             final EntityKey entityKey = action.getEntityKey();
-            if ((action.definition == actionDefinition || action.definition == actionDefinition.activityAlias) &&
+            if (activityAnchor.name().equals(activity.name()) &&
                     (entityKey == null || (modelId != null && modelId.equals(entityKey.modelId)))) {
                 return item;
             }
 
-            final TreeItem _item = findItemByActionDefinition(item.getItems(), actionDefinition, modelId);
+            final TreeItem _item = findItemByActionDefinition(item.getItems(), activity, modelId);
             if (_item != null) {
                 return _item;
             }
@@ -212,8 +240,8 @@ public class ActivitiesPane implements TemplateComposer {
         return null;
     }
 
-    static final TreeItem findItemByActionDefinition(final TreeItem[] items, final ActionDefinition actionDefinition) {
-        return findItemByActionDefinition(items, actionDefinition, null);
+    static final TreeItem findItemByActionDefinition(final TreeItem[] items, final PageState pageState) {
+        return findItemByActionDefinition(items, pageState.activityAnchor(), null);
     }
 
     static final void expand(final TreeItem item) {
@@ -242,14 +270,15 @@ public class ActivitiesPane implements TemplateComposer {
 
         @Override
         public void notify(final ActionEvent event) {
-            final MainPageState mainPageState = MainPageState.get();
-            mainPageState.action = event.action;
+            // TODO
+//            final MainPageState mainPageState = MainPageState.get();
+//            mainPageState.action = event.action;
             if (!event.activity) {
                 final EntityKey entityKey = event.action.getEntityKey();
                 final String modelId = (entityKey != null) ? entityKey.modelId : null;
                 final TreeItem item = findItemByActionDefinition(
                         this.navigation.getItems(),
-                        event.action.definition,
+                        event.action.definition.targetState.activityAnchor(),
                         modelId);
                 if (item != null) {
                     this.navigation.select(item);
diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/content/activity/ActivityDefinition.java b/src/main/java/ch/ethz/seb/sebserver/gui/content/activity/ActivityDefinition.java
new file mode 100644
index 00000000..5423bf8d
--- /dev/null
+++ b/src/main/java/ch/ethz/seb/sebserver/gui/content/activity/ActivityDefinition.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+package ch.ethz.seb.sebserver.gui.content.activity;
+
+import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey;
+import ch.ethz.seb.sebserver.gui.service.page.Activity;
+
+public enum ActivityDefinition implements Activity {
+    INSTITUTION(new LocTextKey("sebserver.institution.action.list")),
+    USER_ACCOUNT(new LocTextKey("sebserver.useraccount.action.list")),
+    LMS_SETUP(new LocTextKey("sebserver.lmssetup.action.list")),
+    QUIZ_DISCOVERY(new LocTextKey("sebserver.quizdiscovery.action.list")),
+    EXAM(new LocTextKey("sebserver.exam.action.list")),
+    ;
+
+    public final LocTextKey displayName;
+
+    private ActivityDefinition(final LocTextKey displayName) {
+        this.displayName = displayName;
+    }
+
+    @Override
+    public LocTextKey displayName() {
+        return this.displayName;
+    }
+
+}
diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/content/activity/PageStateDefinition.java b/src/main/java/ch/ethz/seb/sebserver/gui/content/activity/PageStateDefinition.java
new file mode 100644
index 00000000..81cba0a8
--- /dev/null
+++ b/src/main/java/ch/ethz/seb/sebserver/gui/content/activity/PageStateDefinition.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+package ch.ethz.seb.sebserver.gui.content.activity;
+
+import ch.ethz.seb.sebserver.gui.content.ExamForm;
+import ch.ethz.seb.sebserver.gui.content.ExamList;
+import ch.ethz.seb.sebserver.gui.content.IndicatorForm;
+import ch.ethz.seb.sebserver.gui.content.InstitutionForm;
+import ch.ethz.seb.sebserver.gui.content.InstitutionList;
+import ch.ethz.seb.sebserver.gui.content.LmsSetupForm;
+import ch.ethz.seb.sebserver.gui.content.LmsSetupList;
+import ch.ethz.seb.sebserver.gui.content.QuizDiscoveryList;
+import ch.ethz.seb.sebserver.gui.content.UserAccountChangePasswordForm;
+import ch.ethz.seb.sebserver.gui.content.UserAccountForm;
+import ch.ethz.seb.sebserver.gui.content.UserAccountList;
+import ch.ethz.seb.sebserver.gui.content.action.ActionPane;
+import ch.ethz.seb.sebserver.gui.service.page.Activity;
+import ch.ethz.seb.sebserver.gui.service.page.PageState;
+import ch.ethz.seb.sebserver.gui.service.page.TemplateComposer;
+
+public enum PageStateDefinition implements PageState {
+
+    INSTITUTION_LIST(Type.LIST_VIEW, InstitutionList.class, ActivityDefinition.INSTITUTION),
+    INSTITUTION_VIEW(Type.FORM_VIEW, InstitutionForm.class, ActivityDefinition.INSTITUTION),
+    INSTITUTION_EDIT(Type.FORM_EDIT, InstitutionForm.class, ActivityDefinition.INSTITUTION),
+
+    USER_ACCOUNT_LIST(Type.LIST_VIEW, UserAccountList.class, ActivityDefinition.USER_ACCOUNT),
+    USER_ACCOUNT_VIEW(Type.FORM_VIEW, UserAccountForm.class, ActivityDefinition.USER_ACCOUNT),
+    USER_ACCOUNT_EDIT(Type.FORM_EDIT, UserAccountForm.class, ActivityDefinition.USER_ACCOUNT),
+    USER_ACCOUNT_PASSWORD_CHANGE(Type.FORM_EDIT, UserAccountChangePasswordForm.class, ActivityDefinition.USER_ACCOUNT),
+
+    LMS_SETUP_LIST(Type.LIST_VIEW, LmsSetupList.class, ActivityDefinition.LMS_SETUP),
+    LMS_SETUP_VIEW(Type.FORM_VIEW, LmsSetupForm.class, ActivityDefinition.LMS_SETUP),
+    LMS_SETUP_EDIT(Type.FORM_EDIT, LmsSetupForm.class, ActivityDefinition.LMS_SETUP),
+
+    QUIZ_LIST(Type.LIST_VIEW, QuizDiscoveryList.class, ActivityDefinition.QUIZ_DISCOVERY),
+
+    EXAM_LIST(Type.LIST_VIEW, ExamList.class, ActivityDefinition.EXAM),
+    EXAM_VIEW(Type.FORM_VIEW, ExamForm.class, ActivityDefinition.EXAM),
+    EXAM_EDIT(Type.FORM_EDIT, ExamForm.class, ActivityDefinition.EXAM),
+    INDICATOR_EDIT(Type.FORM_EDIT, IndicatorForm.class, ActivityDefinition.EXAM),
+
+    ;
+
+    public final Type type;
+    public final Class<? extends TemplateComposer> contentPaneComposer;
+    public final Class<? extends TemplateComposer> actionPaneComposer;
+    public final Activity activityAnchor;
+
+    private PageStateDefinition(
+            final Type type,
+            final Class<? extends TemplateComposer> contentPaneComposer,
+            final Activity activityAnchor) {
+
+        this(type, contentPaneComposer, ActionPane.class, activityAnchor);
+    }
+
+    private PageStateDefinition(
+            final Type type,
+            final Class<? extends TemplateComposer> contentPaneComposer,
+            final Class<? extends TemplateComposer> actionPaneComposer,
+            final Activity activityAnchor) {
+
+        this.type = type;
+        this.contentPaneComposer = contentPaneComposer;
+        this.actionPaneComposer = actionPaneComposer;
+        this.activityAnchor = activityAnchor;
+    }
+
+    @Override
+    public Type type() {
+        return this.type;
+    }
+
+    @Override
+    public Class<? extends TemplateComposer> contentPaneComposer() {
+        return this.contentPaneComposer;
+    }
+
+    @Override
+    public Class<? extends TemplateComposer> actionPaneComposer() {
+        return this.actionPaneComposer;
+    }
+
+    @Override
+    public Activity activityAnchor() {
+        return this.activityAnchor;
+    }
+
+}
diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/form/FormBuilder.java b/src/main/java/ch/ethz/seb/sebserver/gui/form/FormBuilder.java
index 25a2a0c2..62a69aab 100644
--- a/src/main/java/ch/ethz/seb/sebserver/gui/form/FormBuilder.java
+++ b/src/main/java/ch/ethz/seb/sebserver/gui/form/FormBuilder.java
@@ -25,12 +25,11 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import ch.ethz.seb.sebserver.gbl.Constants;
-import ch.ethz.seb.sebserver.gbl.api.JSONMapper;
 import ch.ethz.seb.sebserver.gbl.model.Entity;
 import ch.ethz.seb.sebserver.gbl.model.exam.Indicator.Threshold;
 import ch.ethz.seb.sebserver.gbl.util.Tuple;
-import ch.ethz.seb.sebserver.gui.service.i18n.PolyglotPageService;
 import ch.ethz.seb.sebserver.gui.service.page.PageContext;
+import ch.ethz.seb.sebserver.gui.service.page.PageService;
 import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCall;
 import ch.ethz.seb.sebserver.gui.widget.Selection;
 import ch.ethz.seb.sebserver.gui.widget.WidgetFactory;
@@ -40,9 +39,8 @@ public class FormBuilder {
 
     private static final Logger log = LoggerFactory.getLogger(FormBuilder.class);
 
+    final PageService pageService;
     final WidgetFactory widgetFactory;
-    final JSONMapper jsonMapper;
-    private final PolyglotPageService polyglotPageService;
     public final PageContext pageContext;
     public final Composite formParent;
     public final Form form;
@@ -53,18 +51,15 @@ public class FormBuilder {
     private int defaultSpanEmptyCell = 1;
     private boolean emptyCellSeparation = true;
 
-    FormBuilder(
-            final JSONMapper jsonMapper,
-            final WidgetFactory widgetFactory,
-            final PolyglotPageService polyglotPageService,
+    public FormBuilder(
+            final PageService pageService,
             final PageContext pageContext,
             final int rows) {
 
-        this.widgetFactory = widgetFactory;
-        this.jsonMapper = jsonMapper;
-        this.polyglotPageService = polyglotPageService;
+        this.pageService = pageService;
+        this.widgetFactory = pageService.getWidgetFactory();
         this.pageContext = pageContext;
-        this.form = new Form(jsonMapper);
+        this.form = new Form(pageService.getJSONMapper());
 
         this.formParent = new Composite(pageContext.getParent(), SWT.NONE);
         final GridLayout layout = new GridLayout(rows, true);
@@ -173,14 +168,12 @@ public class FormBuilder {
         return buildFor(null);
     }
 
-    public <T extends Entity> FormHandle<T> buildFor(
-            final RestCall<T> post) {
-
+    public <T extends Entity> FormHandle<T> buildFor(final RestCall<T> post) {
         return new FormHandle<>(
+                this.pageService,
                 this.pageContext,
                 this.form,
-                post,
-                this.polyglotPageService.getI18nSupport());
+                post);
     }
 
     private void empty(final Composite parent, final int hspan, final int vspan) {
diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/form/FormHandle.java b/src/main/java/ch/ethz/seb/sebserver/gui/form/FormHandle.java
index 3d70cadd..ec1890cd 100644
--- a/src/main/java/ch/ethz/seb/sebserver/gui/form/FormHandle.java
+++ b/src/main/java/ch/ethz/seb/sebserver/gui/form/FormHandle.java
@@ -19,11 +19,10 @@ import ch.ethz.seb.sebserver.gbl.util.Result;
 import ch.ethz.seb.sebserver.gui.form.Form.FormFieldAccessor;
 import ch.ethz.seb.sebserver.gui.service.i18n.I18nSupport;
 import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey;
-import ch.ethz.seb.sebserver.gui.service.page.PageAction;
 import ch.ethz.seb.sebserver.gui.service.page.FieldValidationError;
 import ch.ethz.seb.sebserver.gui.service.page.PageContext;
-import ch.ethz.seb.sebserver.gui.service.page.PageContext.AttributeKeys;
-import ch.ethz.seb.sebserver.gui.service.page.event.ActionEvent;
+import ch.ethz.seb.sebserver.gui.service.page.PageService;
+import ch.ethz.seb.sebserver.gui.service.page.impl.PageAction;
 import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCall;
 import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCallError;
 
@@ -33,21 +32,23 @@ public class FormHandle<T extends Entity> {
 
     public static final String FIELD_VALIDATION_LOCTEXT_PREFIX = "sebserver.form.validation.fieldError.";
 
+    private final PageService pageService;
     private final PageContext pageContext;
     private final Form form;
     private final RestCall<T> post;
     private final I18nSupport i18nSupport;
 
     FormHandle(
+            final PageService pageService,
             final PageContext pageContext,
             final Form form,
-            final RestCall<T> post,
-            final I18nSupport i18nSupport) {
+            final RestCall<T> post) {
 
+        this.pageService = pageService;
         this.pageContext = pageContext;
         this.form = form;
         this.post = post;
-        this.i18nSupport = i18nSupport;
+        this.i18nSupport = pageService.getI18nSupport();
     }
 
     /** Process an API post request to send and save the form field values
@@ -89,12 +90,14 @@ public class FormHandle<T extends Entity> {
     public PageAction handleFormPost(final Result<T> postResult, final PageAction action) {
         return postResult
                 .map(result -> {
-                    PageAction resultAction = action.createNew()
-                            .withAttribute(AttributeKeys.READ_ONLY, "true");
+
+                    PageAction resultAction = this.pageService.pageActionBuilder(action.pageContext())
+                            .newAction(action.definition)
+                            .create();
                     if (resultAction.getEntityKey() == null) {
                         resultAction = resultAction.withEntityKey(result.getEntityKey());
                     }
-                    action.pageContext().firePageEvent(new ActionEvent(resultAction, false));
+
                     return resultAction;
                 })
                 .onErrorDo(this::handleError)
diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/form/PageFormService.java b/src/main/java/ch/ethz/seb/sebserver/gui/form/PageFormService.java
deleted file mode 100644
index e59d05c5..00000000
--- a/src/main/java/ch/ethz/seb/sebserver/gui/form/PageFormService.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright (c) 2018 ETH Zürich, Educational Development and Technology (LET)
- *
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/.
- */
-
-package ch.ethz.seb.sebserver.gui.form;
-
-import org.springframework.context.annotation.Lazy;
-import org.springframework.stereotype.Component;
-
-import ch.ethz.seb.sebserver.gbl.api.JSONMapper;
-import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
-import ch.ethz.seb.sebserver.gui.service.i18n.PolyglotPageService;
-import ch.ethz.seb.sebserver.gui.service.page.PageContext;
-import ch.ethz.seb.sebserver.gui.widget.WidgetFactory;
-
-@Lazy
-@Component
-@GuiProfile
-public class PageFormService {
-
-    private final JSONMapper jsonMapper;
-    private final WidgetFactory widgetFactory;
-    private final PolyglotPageService polyglotPageService;
-
-    public PageFormService(
-            final JSONMapper jsonMapper,
-            final WidgetFactory widgetFactory,
-            final PolyglotPageService polyglotPageService) {
-
-        this.jsonMapper = jsonMapper;
-        this.widgetFactory = widgetFactory;
-        this.polyglotPageService = polyglotPageService;
-    }
-
-    public FormBuilder getBuilder(
-            final PageContext pageContext,
-            final int rows) {
-
-        return new FormBuilder(
-                this.jsonMapper,
-                this.widgetFactory,
-                this.polyglotPageService,
-                pageContext,
-                rows);
-    }
-
-    public WidgetFactory getWidgetFactory() {
-        return this.widgetFactory;
-    }
-
-    public PolyglotPageService getPolyglotPageService() {
-        return this.polyglotPageService;
-    }
-
-}
diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/page/Activity.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/page/Activity.java
new file mode 100644
index 00000000..11c7867e
--- /dev/null
+++ b/src/main/java/ch/ethz/seb/sebserver/gui/service/page/Activity.java
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+package ch.ethz.seb.sebserver.gui.service.page;
+
+import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey;
+
+public interface Activity {
+
+    String name();
+
+    LocTextKey displayName();
+
+}
diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/page/PageAction.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/page/PageAction.java
deleted file mode 100644
index c18f260a..00000000
--- a/src/main/java/ch/ethz/seb/sebserver/gui/service/page/PageAction.java
+++ /dev/null
@@ -1,250 +0,0 @@
-/*
- * Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
- *
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/.
- */
-
-package ch.ethz.seb.sebserver.gui.service.page;
-
-import java.util.Set;
-import java.util.function.BooleanSupplier;
-import java.util.function.Function;
-import java.util.function.Supplier;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import ch.ethz.seb.sebserver.gbl.api.EntityType;
-import ch.ethz.seb.sebserver.gbl.model.EntityKey;
-import ch.ethz.seb.sebserver.gui.content.action.ActionDefinition;
-import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey;
-import ch.ethz.seb.sebserver.gui.service.page.PageContext.AttributeKeys;
-import ch.ethz.seb.sebserver.gui.service.page.event.ActionEvent;
-import ch.ethz.seb.sebserver.gui.service.page.event.ActionPublishEvent;
-import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCallError;
-
-public final class PageAction implements Runnable {
-
-    private static final Logger log = LoggerFactory.getLogger(PageAction.class);
-
-    public final ActionDefinition definition;
-    Supplier<LocTextKey> confirm;
-    LocTextKey successMessage;
-
-    Supplier<Set<EntityKey>> selectionSupplier;
-    LocTextKey noSelectionMessage;
-
-    private final PageContext originalPageContext;
-    private PageContext pageContext;
-    private Function<PageAction, PageAction> exec = Function.identity();
-
-    private boolean fireActionEvent = true;
-
-    public PageAction(
-            final ActionDefinition definition,
-            final PageContext pageContext) {
-
-        this.definition = definition;
-        this.originalPageContext = pageContext;
-        final String readonly = pageContext.getAttribute(AttributeKeys.READ_ONLY, "true");
-        this.pageContext = pageContext.withAttribute(
-                AttributeKeys.READ_ONLY,
-                definition.readonly != null
-                        ? String.valueOf(definition.readonly)
-                        : readonly);
-    }
-
-    @Override
-    public void run() {
-        if (this.confirm != null) {
-            final LocTextKey confirmMessage = this.confirm.get();
-            if (confirmMessage != null) {
-                this.pageContext.applyConfirmDialog(confirmMessage, () -> exec());
-            }
-        } else {
-            exec();
-        }
-    }
-
-    private void exec() {
-        try {
-
-            final PageAction executedAction = this.exec.apply(this);
-            if (this.fireActionEvent) {
-                this.pageContext.firePageEvent(new ActionEvent(executedAction, false));
-            }
-
-        } catch (final PageMessageException pme) {
-            PageAction.this.pageContext.publishPageMessage(pme);
-
-        } catch (final RestCallError restCallError) {
-            if (restCallError.isFieldValidationError()) {
-                PageAction.this.pageContext.publishPageMessage(
-                        new LocTextKey("sebserver.form.validation.error.title"),
-                        new LocTextKey("sebserver.form.validation.error.message"));
-            } else {
-                log.error("Failed to execute action: {}", PageAction.this, restCallError);
-                PageAction.this.pageContext.notifyError("action.error.unexpected.message", restCallError);
-            }
-        } catch (final Throwable t) {
-            log.error("Failed to execute action: {}", PageAction.this, t);
-            PageAction.this.pageContext.notifyError("action.error.unexpected.message", t);
-        }
-    }
-
-    public PageAction createNew() {
-        return this.pageContext.createAction(this.definition);
-    }
-
-    public PageAction withExec(final Function<PageAction, PageAction> exec) {
-        this.exec = exec;
-        return this;
-    }
-
-    public PageAction withSelectionSupplier(final Supplier<Set<EntityKey>> selectionSupplier) {
-        this.selectionSupplier = selectionSupplier;
-        return this;
-    }
-
-    public PageAction withSelect(
-            final Supplier<Set<EntityKey>> selectionSupplier,
-            final Function<PageAction, PageAction> exec,
-            final LocTextKey noSelectionMessage) {
-
-        this.selectionSupplier = selectionSupplier;
-        this.exec = exec;
-        this.noSelectionMessage = noSelectionMessage;
-        return this;
-    }
-
-    public PageAction withConfirm(final String confirmationMessageKey) {
-        this.confirm = () -> new LocTextKey(confirmationMessageKey);
-        return this;
-    }
-
-    public PageAction withConfirm(final Supplier<LocTextKey> confirm) {
-        this.confirm = confirm;
-        return this;
-    }
-
-    public PageAction withSuccess(final String successMessageKey) {
-        this.successMessage = new LocTextKey(successMessageKey);
-        return this;
-    }
-
-    public PageAction resetEntityKey() {
-        this.pageContext = this.pageContext.withEntityKey(null);
-        return this;
-    }
-
-    public PageAction noEventPropagation() {
-        this.fireActionEvent = false;
-        return this;
-    }
-
-    public PageAction resetParentEntityKey() {
-        this.pageContext = this.pageContext.withParentEntityKey(null);
-        return this;
-    }
-
-    public EntityKey getEntityKey() {
-        return this.pageContext.getEntityKey();
-    }
-
-    public PageContext pageContext() {
-        return this.pageContext;
-    }
-
-    public PageAction withEntityKey(final EntityKey entityKey) {
-        this.pageContext = this.pageContext.withEntityKey(entityKey);
-        return this;
-    }
-
-    public PageAction withEntityKey(final Long modelId, final EntityType entityType) {
-        if (modelId != null) {
-            return withEntityKey(String.valueOf(modelId), entityType);
-        }
-
-        return this;
-    }
-
-    public PageAction withEntityKey(final String modelId, final EntityType entityType) {
-        if (modelId == null || entityType == null) {
-            return this;
-        }
-
-        this.pageContext = this.pageContext.withEntityKey(new EntityKey(modelId, entityType));
-        return this;
-    }
-
-    public PageAction withParentEntityKey(final EntityKey entityKey) {
-        this.pageContext = this.pageContext.withParentEntityKey(entityKey);
-        return this;
-    }
-
-    public PageAction withAttribute(final String name, final String value) {
-        this.pageContext = this.pageContext.withAttribute(name, value);
-        return this;
-    }
-
-    public PageContext publish() {
-        this.pageContext.firePageEvent(new ActionPublishEvent(this));
-        return this.originalPageContext;
-    }
-
-    public PageContext publishIf(final BooleanSupplier condition) {
-        if (condition.getAsBoolean()) {
-            publish();
-        }
-
-        return this.originalPageContext;
-    }
-
-    public EntityKey getSingleSelection() {
-        final Set<EntityKey> selection = getMultiSelection();
-        if (selection != null) {
-            return selection.iterator().next();
-        }
-
-        return null;
-    }
-
-    public Set<EntityKey> getMultiSelection() {
-        if (this.selectionSupplier != null) {
-            final Set<EntityKey> selection = this.selectionSupplier.get();
-            if (selection.isEmpty()) {
-                if (this.noSelectionMessage != null) {
-                    throw new PageMessageException(this.noSelectionMessage);
-                }
-
-                return null;
-            }
-
-            return selection;
-        }
-
-        if (this.noSelectionMessage != null) {
-            throw new PageMessageException(this.noSelectionMessage);
-        }
-
-        return null;
-    }
-
-    public static PageAction applySingleSelection(final PageAction action) {
-        return action.withEntityKey(action.getSingleSelection());
-    }
-
-    public static PageAction onEmptyEntityKeyGoToActivityHome(final PageAction action) {
-        if (action.getEntityKey() == null) {
-            final PageContext pageContext = action.pageContext();
-            final PageAction activityHomeAction = pageContext.createAction(action.definition.activityAlias);
-            action.pageContext.firePageEvent(new ActionEvent(activityHomeAction, false));
-            return activityHomeAction;
-        }
-
-        return action;
-    }
-
-}
diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/page/PageContext.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/page/PageContext.java
index bac0cabe..9ad6fa02 100644
--- a/src/main/java/ch/ethz/seb/sebserver/gui/service/page/PageContext.java
+++ b/src/main/java/ch/ethz/seb/sebserver/gui/service/page/PageContext.java
@@ -8,15 +8,15 @@
 
 package ch.ethz.seb.sebserver.gui.service.page;
 
+import java.util.function.Consumer;
+
 import org.eclipse.swt.widgets.Composite;
 import org.eclipse.swt.widgets.Shell;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import ch.ethz.seb.sebserver.gbl.model.EntityKey;
-import ch.ethz.seb.sebserver.gui.content.action.ActionDefinition;
 import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey;
-import ch.ethz.seb.sebserver.gui.service.page.event.PageEvent;
 
 /** Holds a page-context and defines some convenient functionality for page handling */
 public interface PageContext {
@@ -149,21 +149,12 @@ public interface PageContext {
      * @return a copy of this PageContext with the removed attribute */
     PageContext removeAttribute(String name);
 
-    /** Publishes a given PageEvent to the current page tree
-     * This goes through the page-tree and collects all listeners the are listen to
-     * the specified page event type.
-     *
-     * @param event the concrete PageEvent instance */
-    <T extends PageEvent> void firePageEvent(T event);
-
-    PageAction createAction(ActionDefinition actionDefinition);
-
     /** Apply a confirm dialog with a specified confirm message and a callback code
      * block that will be executed on users OK selection.
      *
      * @param confirmMessage the localized confirm message key
-     * @param onOK callback code block that will be executed on users OK selection */
-    void applyConfirmDialog(LocTextKey confirmMessage, Runnable onOK);
+     * @param onOK callback code block that will be called on users selection */
+    void applyConfirmDialog(LocTextKey confirmMessage, final Consumer<Boolean> callback);
 
     /** This can be used to forward to a defined page.
      *
diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/page/PageService.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/page/PageService.java
new file mode 100644
index 00000000..84ac7d26
--- /dev/null
+++ b/src/main/java/ch/ethz/seb/sebserver/gui/service/page/PageService.java
@@ -0,0 +1,259 @@
+/*
+ * Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+package ch.ethz.seb.sebserver.gui.service.page;
+
+import java.util.Set;
+import java.util.function.BooleanSupplier;
+import java.util.function.Consumer;
+import java.util.function.Function;
+import java.util.function.Supplier;
+
+import ch.ethz.seb.sebserver.gbl.api.API;
+import ch.ethz.seb.sebserver.gbl.api.EntityType;
+import ch.ethz.seb.sebserver.gbl.api.JSONMapper;
+import ch.ethz.seb.sebserver.gbl.model.Entity;
+import ch.ethz.seb.sebserver.gbl.model.EntityKey;
+import ch.ethz.seb.sebserver.gbl.model.Page;
+import ch.ethz.seb.sebserver.gbl.util.Result;
+import ch.ethz.seb.sebserver.gui.content.action.ActionDefinition;
+import ch.ethz.seb.sebserver.gui.form.FormBuilder;
+import ch.ethz.seb.sebserver.gui.service.i18n.I18nSupport;
+import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey;
+import ch.ethz.seb.sebserver.gui.service.i18n.PolyglotPageService;
+import ch.ethz.seb.sebserver.gui.service.page.PageContext.AttributeKeys;
+import ch.ethz.seb.sebserver.gui.service.page.event.ActionEvent;
+import ch.ethz.seb.sebserver.gui.service.page.event.PageEvent;
+import ch.ethz.seb.sebserver.gui.service.page.impl.PageAction;
+import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCall;
+import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestService;
+import ch.ethz.seb.sebserver.gui.table.TableBuilder;
+import ch.ethz.seb.sebserver.gui.widget.WidgetFactory;
+
+/** The main page service that provides functionality to build a page
+ * with forms and tables as well as dealing with page actions */
+public interface PageService {
+
+    /** get the WidgetFactory service
+     *
+     * @return the WidgetFactory service */
+    WidgetFactory getWidgetFactory();
+
+    /** get the polyglotPageService service
+     *
+     * @return the polyglotPageService service */
+    PolyglotPageService getPolyglotPageService();
+
+    /** get the I18nSupport (internationalization support) service
+     *
+     * @return the I18nSupport (internationalization support) service */
+    I18nSupport getI18nSupport();
+
+    /** get the JSONMapper for parse, read and write JSON
+     *
+     * @return the JSONMapper for parse, read and write JSON */
+    JSONMapper getJSONMapper();
+
+    PageState initPageState(PageState initState);
+
+    PageState getCurrentState();
+
+    /** Publishes a given PageEvent to the current page tree
+     * This goes through the page-tree and collects all listeners the are listen to
+     * the specified page event type.
+     *
+     * @param event the concrete PageEvent instance */
+    <T extends PageEvent> void firePageEvent(T event, PageContext pageContext);
+
+    default void executePageAction(final PageAction pageAction) {
+        executePageAction(pageAction, result -> {
+        });
+    }
+
+    void executePageAction(PageAction pageAction, Consumer<Result<PageAction>> callback);
+
+    void publishAction(final PageAction pageAction);
+
+    FormBuilder formBuilder(final PageContext pageContext, final int rows);
+
+    <T extends Entity> TableBuilder<T> entityTableBuilder(final RestCall<Page<T>> apiCall);
+
+    void clear();
+
+    default PageActionBuilder pageActionBuilder(final PageContext pageContext) {
+        return new PageActionBuilder(this, pageContext);
+    }
+
+    default PageAction onEmptyEntityKeyGoTo(final PageAction action, final ActionDefinition gotoActionDef) {
+        if (action.getEntityKey() == null) {
+            final PageContext pageContext = action.pageContext();
+            final PageAction activityHomeAction = pageActionBuilder(pageContext)
+                    .newAction(gotoActionDef)
+                    .create();
+            firePageEvent(new ActionEvent(activityHomeAction), activityHomeAction.pageContext());
+        }
+
+        return action;
+    }
+
+    public class PageActionBuilder {
+        private final PageService pageService;
+        private final PageContext originalPageContext;
+
+        private PageContext pageContext;
+        private ActionDefinition definition;
+        private Supplier<LocTextKey> confirm;
+        private LocTextKey successMessage;
+        private Supplier<Set<EntityKey>> selectionSupplier;
+        private LocTextKey noSelectionMessage;
+        private Function<PageAction, PageAction> exec;
+        private boolean fireActionEvent = true;
+        private boolean ignoreMoveAwayFromEdit = false;
+
+        protected PageActionBuilder(final PageService pageService, final PageContext pageContext) {
+            this.pageService = pageService;
+            this.originalPageContext = pageContext;
+        }
+
+        public PageActionBuilder newAction(final ActionDefinition definition) {
+            pageContext = originalPageContext.copy();
+            this.definition = definition;
+            confirm = null;
+            successMessage = null;
+            selectionSupplier = null;
+            noSelectionMessage = null;
+            exec = null;
+            fireActionEvent = true;
+            ignoreMoveAwayFromEdit = false;
+            return this;
+        }
+
+        public PageAction create() {
+            return new PageAction(
+                    definition,
+                    confirm,
+                    successMessage,
+                    selectionSupplier,
+                    noSelectionMessage,
+                    pageContext,
+                    exec,
+                    fireActionEvent,
+                    ignoreMoveAwayFromEdit);
+        }
+
+        public PageActionBuilder publish() {
+            pageService.publishAction(create());
+            return this;
+        }
+
+        public PageActionBuilder publishIf(final BooleanSupplier condition) {
+            if (!condition.getAsBoolean()) {
+                return this;
+            }
+
+            return this.publish();
+        }
+
+        public PageActionBuilder withExec(final Function<PageAction, PageAction> exec) {
+            this.exec = exec;
+            return this;
+        }
+
+        public PageActionBuilder withSelectionSupplier(final Supplier<Set<EntityKey>> selectionSupplier) {
+            this.selectionSupplier = selectionSupplier;
+            return this;
+        }
+
+        public PageActionBuilder withSelect(
+                final Supplier<Set<EntityKey>> selectionSupplier,
+                final Function<PageAction, PageAction> exec,
+                final LocTextKey noSelectionMessage) {
+
+            this.selectionSupplier = selectionSupplier;
+            this.exec = exec;
+            this.noSelectionMessage = noSelectionMessage;
+            return this;
+        }
+
+        public PageActionBuilder withSimpleRestCall(
+                final RestService restService,
+                final Class<? extends RestCall<?>> restCallType) {
+
+            this.exec = action -> {
+                restService.getBuilder(restCallType)
+                        .withURIVariable(
+                                API.PARAM_MODEL_ID,
+                                action.pageContext().getAttribute(AttributeKeys.ENTITY_ID))
+                        .call()
+                        .onErrorDo(t -> action.pageContext().notifyError(t));
+                return action;
+            };
+
+            return this;
+        }
+
+        public PageActionBuilder withConfirm(final String confirmationMessageKey) {
+            this.confirm = () -> new LocTextKey(confirmationMessageKey);
+            return this;
+        }
+
+        public PageActionBuilder withConfirm(final Supplier<LocTextKey> confirm) {
+            this.confirm = confirm;
+            return this;
+        }
+
+        public PageActionBuilder withSuccess(final String successMessageKey) {
+            this.successMessage = new LocTextKey(successMessageKey);
+            return this;
+        }
+
+        public PageActionBuilder noEventPropagation() {
+            this.fireActionEvent = false;
+            return this;
+        }
+
+        public PageActionBuilder withEntityKey(final EntityKey entityKey) {
+            this.pageContext = this.pageContext.withEntityKey(entityKey);
+            return this;
+        }
+
+        public PageActionBuilder ignoreMoveAwayFromEdit() {
+            this.ignoreMoveAwayFromEdit = true;
+            return this;
+        }
+
+        public PageActionBuilder withEntityKey(final Long modelId, final EntityType entityType) {
+            if (modelId != null) {
+                return withEntityKey(String.valueOf(modelId), entityType);
+            }
+
+            return this;
+        }
+
+        public PageActionBuilder withEntityKey(final String modelId, final EntityType entityType) {
+            if (modelId == null || entityType == null) {
+                return this;
+            }
+
+            this.pageContext = this.pageContext.withEntityKey(new EntityKey(modelId, entityType));
+            return this;
+        }
+
+        public PageActionBuilder withParentEntityKey(final EntityKey entityKey) {
+            this.pageContext = this.pageContext.withParentEntityKey(entityKey);
+            return this;
+        }
+
+        public PageActionBuilder withAttribute(final String name, final String value) {
+            this.pageContext = this.pageContext.withAttribute(name, value);
+            return this;
+        }
+
+    }
+
+}
diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/page/PageState.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/page/PageState.java
new file mode 100644
index 00000000..ca743d22
--- /dev/null
+++ b/src/main/java/ch/ethz/seb/sebserver/gui/service/page/PageState.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+package ch.ethz.seb.sebserver.gui.service.page;
+
+public interface PageState {
+
+    enum Type {
+        UNDEFINED,
+        LIST_VIEW,
+        FORM_VIEW,
+        FORM_EDIT
+    }
+
+    String name();
+
+    Type type();
+
+    public Class<? extends TemplateComposer> contentPaneComposer();
+
+    public Class<? extends TemplateComposer> actionPaneComposer();
+
+    Activity activityAnchor();
+}
diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/page/event/ActionEvent.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/page/event/ActionEvent.java
index 03b8c709..d2ccff06 100644
--- a/src/main/java/ch/ethz/seb/sebserver/gui/service/page/event/ActionEvent.java
+++ b/src/main/java/ch/ethz/seb/sebserver/gui/service/page/event/ActionEvent.java
@@ -8,15 +8,23 @@
 
 package ch.ethz.seb.sebserver.gui.service.page.event;
 
-import ch.ethz.seb.sebserver.gui.service.page.PageAction;
+import ch.ethz.seb.sebserver.gui.service.page.impl.PageAction;
 
 /** This Event is used to propagate a user-action to the GUI system.
  * Potentially every component can listen to an Event and react on the user-action */
 public final class ActionEvent implements PageEvent {
 
     public final PageAction action;
+    @Deprecated // use the ActionDefinition
     public final boolean activity;
 
+    public ActionEvent(final PageAction action) {
+        super();
+        this.action = action;
+        this.activity = false;
+    }
+
+    @Deprecated
     public ActionEvent(final PageAction action, final boolean activity) {
         super();
         this.action = action;
diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/page/event/ActionPublishEvent.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/page/event/ActionPublishEvent.java
index fe130a14..c5b487e3 100644
--- a/src/main/java/ch/ethz/seb/sebserver/gui/service/page/event/ActionPublishEvent.java
+++ b/src/main/java/ch/ethz/seb/sebserver/gui/service/page/event/ActionPublishEvent.java
@@ -8,7 +8,7 @@
 
 package ch.ethz.seb.sebserver.gui.service.page.event;
 
-import ch.ethz.seb.sebserver.gui.service.page.PageAction;
+import ch.ethz.seb.sebserver.gui.service.page.impl.PageAction;
 
 /** This action is used to publish an Action to the Action-Pane for a specified context.
  * The ActionPane is listening to this events and render specified actions on notify */
diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/page/impl/ComposerServiceImpl.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/page/impl/ComposerServiceImpl.java
index dae9808b..8b5733d5 100644
--- a/src/main/java/ch/ethz/seb/sebserver/gui/service/page/impl/ComposerServiceImpl.java
+++ b/src/main/java/ch/ethz/seb/sebserver/gui/service/page/impl/ComposerServiceImpl.java
@@ -24,7 +24,6 @@ import ch.ethz.seb.sebserver.gui.service.i18n.I18nSupport;
 import ch.ethz.seb.sebserver.gui.service.page.ComposerService;
 import ch.ethz.seb.sebserver.gui.service.page.PageContext;
 import ch.ethz.seb.sebserver.gui.service.page.PageDefinition;
-import ch.ethz.seb.sebserver.gui.service.page.PageUtils;
 import ch.ethz.seb.sebserver.gui.service.page.TemplateComposer;
 import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.AuthorizationContextHolder;
 
diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/page/impl/DefaultPageLayout.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/page/impl/DefaultPageLayout.java
index 79f98e54..f986be85 100644
--- a/src/main/java/ch/ethz/seb/sebserver/gui/service/page/impl/DefaultPageLayout.java
+++ b/src/main/java/ch/ethz/seb/sebserver/gui/service/page/impl/DefaultPageLayout.java
@@ -30,10 +30,12 @@ import org.springframework.context.annotation.Lazy;
 import org.springframework.core.env.Environment;
 import org.springframework.stereotype.Component;
 
+import ch.ethz.seb.sebserver.gbl.Constants;
 import ch.ethz.seb.sebserver.gbl.api.API;
 import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey;
 import ch.ethz.seb.sebserver.gui.service.i18n.PolyglotPageService;
 import ch.ethz.seb.sebserver.gui.service.page.PageContext;
+import ch.ethz.seb.sebserver.gui.service.page.PageService;
 import ch.ethz.seb.sebserver.gui.service.page.PageContext.AttributeKeys;
 import ch.ethz.seb.sebserver.gui.service.page.TemplateComposer;
 import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.AuthorizationContextHolder;
@@ -50,6 +52,7 @@ public class DefaultPageLayout implements TemplateComposer {
     private final WidgetFactory widgetFactory;
     private final PolyglotPageService polyglotPageService;
     private final AuthorizationContextHolder authorizationContextHolder;
+    private final PageService pageStateService;
     private final String sebServerVersion;
     private final boolean multilingual;
 
@@ -57,12 +60,14 @@ public class DefaultPageLayout implements TemplateComposer {
             final WidgetFactory widgetFactory,
             final PolyglotPageService polyglotPageService,
             final AuthorizationContextHolder authorizationContextHolder,
+            final PageService pageStateService,
             final Environment environment) {
 
         this.widgetFactory = widgetFactory;
         this.polyglotPageService = polyglotPageService;
         this.authorizationContextHolder = authorizationContextHolder;
-        this.sebServerVersion = environment.getProperty("sebserver.version", "--");
+        this.pageStateService = pageStateService;
+        this.sebServerVersion = environment.getProperty("sebserver.version", Constants.EMPTY_NOTE);
         this.multilingual = BooleanUtils.toBoolean(environment.getProperty("sebserver.gui.multilingual", "false"));
     }
 
@@ -135,7 +140,7 @@ public class DefaultPageLayout implements TemplateComposer {
                     // TODO error handling
                 }
 
-                MainPageState.clear();
+                this.pageStateService.clear();
 
                 // forward to login page with success message
                 pageContext.forwardToLoginPage();
diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/page/impl/MainPageState.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/page/impl/MainPageState.java
index e505bc6a..78a4115a 100644
--- a/src/main/java/ch/ethz/seb/sebserver/gui/service/page/impl/MainPageState.java
+++ b/src/main/java/ch/ethz/seb/sebserver/gui/service/page/impl/MainPageState.java
@@ -8,50 +8,52 @@
 
 package ch.ethz.seb.sebserver.gui.service.page.impl;
 
-import javax.servlet.http.HttpSession;
-
-import org.eclipse.rap.rwt.RWT;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import ch.ethz.seb.sebserver.gui.content.MainPage;
-import ch.ethz.seb.sebserver.gui.service.page.PageAction;
-
 public final class MainPageState {
 
-    private static final Logger log = LoggerFactory.getLogger(MainPageState.class);
-
-    public PageAction action = null;
-
-    private MainPageState() {
-    }
-
-    public static MainPageState get() {
-        try {
-
-            final HttpSession httpSession = RWT
-                    .getUISession()
-                    .getHttpSession();
-
-            MainPageState mainPageState = (MainPageState) httpSession.getAttribute(MainPage.ATTR_MAIN_PAGE_STATE);
-            if (mainPageState == null) {
-                mainPageState = new MainPageState();
-                httpSession.setAttribute(MainPage.ATTR_MAIN_PAGE_STATE, mainPageState);
-            }
-
-            return mainPageState;
-
-        } catch (final RuntimeException re) {
-            throw re;
-        } catch (final Exception e) {
-            log.error("Unexpected error while trying to get MainPageState from user-session");
-        }
-
-        return null;
-    }
-
-    public static void clear() {
-        final MainPageState mainPageState = get();
-        mainPageState.action = null;
-    }
+//    private static final Logger log = LoggerFactory.getLogger(MainPageState.class);
+//
+//    private PageAction action = null;
+//
+//    private MainPageState() {
+//    }
+//
+//    public action
+//
+//    public boolean changeTo(final PageAction action) {
+//        if (this.action.definition != action.definition) {
+//            this.action = action;
+//            return true;
+//        }
+//
+//        return false;
+//    }
+//
+//    public static MainPageState get() {
+//        try {
+//
+//            final HttpSession httpSession = RWT
+//                    .getUISession()
+//                    .getHttpSession();
+//
+//            MainPageState mainPageState = (MainPageState) httpSession.getAttribute(MainPage.ATTR_MAIN_PAGE_STATE);
+//            if (mainPageState == null) {
+//                mainPageState = new MainPageState();
+//                httpSession.setAttribute(MainPage.ATTR_MAIN_PAGE_STATE, mainPageState);
+//            }
+//
+//            return mainPageState;
+//
+//        } catch (final RuntimeException re) {
+//            throw re;
+//        } catch (final Exception e) {
+//            log.error("Unexpected error while trying to get MainPageState from user-session");
+//        }
+//
+//        return null;
+//    }
+//
+//    public static void clear() {
+//        final MainPageState mainPageState = get();
+//        mainPageState.action = null;
+//    }
 }
\ No newline at end of file
diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/page/ModalInputDialog.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/page/impl/ModalInputDialog.java
similarity index 94%
rename from src/main/java/ch/ethz/seb/sebserver/gui/service/page/ModalInputDialog.java
rename to src/main/java/ch/ethz/seb/sebserver/gui/service/page/impl/ModalInputDialog.java
index f7f88d36..63bf0381 100644
--- a/src/main/java/ch/ethz/seb/sebserver/gui/service/page/ModalInputDialog.java
+++ b/src/main/java/ch/ethz/seb/sebserver/gui/service/page/impl/ModalInputDialog.java
@@ -6,7 +6,7 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
  */
 
-package ch.ethz.seb.sebserver.gui.service.page;
+package ch.ethz.seb.sebserver.gui.service.page.impl;
 
 import java.util.function.Consumer;
 import java.util.function.Supplier;
@@ -22,6 +22,8 @@ import org.eclipse.swt.widgets.Dialog;
 import org.eclipse.swt.widgets.Shell;
 
 import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey;
+import ch.ethz.seb.sebserver.gui.service.page.ModalInputDialogComposer;
+import ch.ethz.seb.sebserver.gui.service.page.PageContext;
 import ch.ethz.seb.sebserver.gui.widget.WidgetFactory;
 import ch.ethz.seb.sebserver.gui.widget.WidgetFactory.CustomVariant;
 
diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/page/impl/PageAction.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/page/impl/PageAction.java
new file mode 100644
index 00000000..ddd7775c
--- /dev/null
+++ b/src/main/java/ch/ethz/seb/sebserver/gui/service/page/impl/PageAction.java
@@ -0,0 +1,170 @@
+/*
+ * Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+package ch.ethz.seb.sebserver.gui.service.page.impl;
+
+import java.util.Set;
+import java.util.function.Consumer;
+import java.util.function.Function;
+import java.util.function.Supplier;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import ch.ethz.seb.sebserver.gbl.Constants;
+import ch.ethz.seb.sebserver.gbl.model.EntityKey;
+import ch.ethz.seb.sebserver.gbl.util.Result;
+import ch.ethz.seb.sebserver.gui.content.action.ActionDefinition;
+import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey;
+import ch.ethz.seb.sebserver.gui.service.page.PageContext;
+import ch.ethz.seb.sebserver.gui.service.page.PageContext.AttributeKeys;
+import ch.ethz.seb.sebserver.gui.service.page.PageMessageException;
+import ch.ethz.seb.sebserver.gui.service.page.PageState.Type;
+import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCallError;
+
+public final class PageAction {
+
+    private static final Logger log = LoggerFactory.getLogger(PageAction.class);
+
+    public final ActionDefinition definition;
+    private final Supplier<LocTextKey> confirm;
+    final LocTextKey successMessage;
+    private final Supplier<Set<EntityKey>> selectionSupplier;
+    private final LocTextKey noSelectionMessage;
+    private PageContext pageContext;
+    private final Function<PageAction, PageAction> exec;
+    final boolean fireActionEvent;
+    final boolean ignoreMoveAwayFromEdit;
+
+    public PageAction(
+            final ActionDefinition definition,
+            final Supplier<LocTextKey> confirm,
+            final LocTextKey successMessage,
+            final Supplier<Set<EntityKey>> selectionSupplier,
+            final LocTextKey noSelectionMessage,
+            final PageContext pageContext,
+            final Function<PageAction, PageAction> exec,
+            final boolean fireActionEvent,
+            final boolean ignoreMoveAwayFromEdit) {
+
+        this.definition = definition;
+        this.confirm = confirm;
+        this.successMessage = successMessage;
+        this.selectionSupplier = selectionSupplier;
+        this.noSelectionMessage = noSelectionMessage;
+        this.pageContext = pageContext;
+        this.exec = (exec != null) ? exec : Function.identity();
+        this.fireActionEvent = fireActionEvent;
+        this.ignoreMoveAwayFromEdit = ignoreMoveAwayFromEdit;
+
+        this.pageContext = pageContext.withAttribute(AttributeKeys.READ_ONLY, Constants.TRUE_STRING);
+        if (definition.targetState != null) {
+            final Type type = definition.targetState.type();
+            if (type.name().equals(Type.FORM_EDIT.name())) {
+                this.pageContext = pageContext.withAttribute(AttributeKeys.READ_ONLY, Constants.FALSE_STRING);
+            }
+        }
+    }
+
+    public EntityKey getEntityKey() {
+        return this.pageContext.getEntityKey();
+    }
+
+    public PageContext pageContext() {
+        return this.pageContext;
+    }
+
+    public EntityKey getSingleSelection() {
+        final Set<EntityKey> selection = getMultiSelection();
+        if (selection != null) {
+            return selection.iterator().next();
+        }
+
+        return null;
+    }
+
+    public Set<EntityKey> getMultiSelection() {
+        if (this.selectionSupplier != null) {
+            final Set<EntityKey> selection = this.selectionSupplier.get();
+            if (selection.isEmpty()) {
+                if (this.noSelectionMessage != null) {
+                    throw new PageMessageException(this.noSelectionMessage);
+                }
+
+                return null;
+            }
+
+            return selection;
+        }
+
+        if (this.noSelectionMessage != null) {
+            throw new PageMessageException(this.noSelectionMessage);
+        }
+
+        return null;
+    }
+
+    void applyAction(final Consumer<Result<PageAction>> callback) {
+        if (this.confirm != null) {
+            final LocTextKey confirmMessage = this.confirm.get();
+            if (confirmMessage != null) {
+                this.pageContext.applyConfirmDialog(confirmMessage,
+                        confirm -> callback.accept((confirm)
+                                ? exec()
+                                : Result.ofRuntimeError("Confirm denied")));
+            }
+        } else {
+            callback.accept(exec());
+        }
+    }
+
+    private Result<PageAction> exec() {
+        try {
+
+            return Result.of(this.exec.apply(this));
+
+        } catch (final PageMessageException pme) {
+            PageAction.this.pageContext.publishPageMessage(pme);
+            return Result.ofError(pme);
+        } catch (final RestCallError restCallError) {
+            if (restCallError.isFieldValidationError()) {
+                PageAction.this.pageContext.publishPageMessage(
+                        new LocTextKey("sebserver.form.validation.error.title"),
+                        new LocTextKey("sebserver.form.validation.error.message"));
+            } else {
+                log.error("Failed to execute action: {}", PageAction.this, restCallError);
+                PageAction.this.pageContext.notifyError("action.error.unexpected.message", restCallError);
+            }
+            return Result.ofError(restCallError);
+        } catch (final Throwable t) {
+            log.error("Failed to execute action: {}", PageAction.this, t);
+            PageAction.this.pageContext.notifyError("action.error.unexpected.message", t);
+            return Result.ofError(t);
+        }
+    }
+
+    public PageAction withEntityKey(final EntityKey entityKey) {
+        this.pageContext = this.pageContext.withEntityKey(entityKey);
+        return this;
+    }
+
+    public PageAction withParentEntityKey(final EntityKey parentEntityKey) {
+        this.pageContext = this.pageContext.withParentEntityKey(parentEntityKey);
+        return this;
+    }
+
+    public PageAction withAttribute(final String name, final String value) {
+        this.pageContext = this.pageContext.withAttribute(name, value);
+        return this;
+    }
+
+    public static PageAction applySingleSelection(final PageAction action) {
+        return action.withEntityKey(action.getSingleSelection());
+    }
+
+}
diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/page/impl/PageContextImpl.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/page/impl/PageContextImpl.java
index 3ed27dad..76dfcf72 100644
--- a/src/main/java/ch/ethz/seb/sebserver/gui/service/page/impl/PageContextImpl.java
+++ b/src/main/java/ch/ethz/seb/sebserver/gui/service/page/impl/PageContextImpl.java
@@ -8,12 +8,10 @@
 
 package ch.ethz.seb.sebserver.gui.service.page.impl;
 
-import java.io.Serializable;
-import java.util.ArrayList;
-import java.util.Comparator;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.function.Consumer;
 
 import org.apache.commons.lang3.BooleanUtils;
 import org.eclipse.rap.rwt.widgets.DialogCallback;
@@ -29,24 +27,18 @@ import ch.ethz.seb.sebserver.gbl.api.APIMessageError;
 import ch.ethz.seb.sebserver.gbl.api.EntityType;
 import ch.ethz.seb.sebserver.gbl.model.EntityKey;
 import ch.ethz.seb.sebserver.gbl.util.Utils;
-import ch.ethz.seb.sebserver.gui.content.action.ActionDefinition;
 import ch.ethz.seb.sebserver.gui.service.i18n.I18nSupport;
 import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey;
-import ch.ethz.seb.sebserver.gui.service.page.PageAction;
 import ch.ethz.seb.sebserver.gui.service.page.ComposerService;
 import ch.ethz.seb.sebserver.gui.service.page.PageContext;
 import ch.ethz.seb.sebserver.gui.service.page.PageDefinition;
 import ch.ethz.seb.sebserver.gui.service.page.PageMessageException;
-import ch.ethz.seb.sebserver.gui.service.page.event.PageEvent;
-import ch.ethz.seb.sebserver.gui.service.page.event.PageEventListener;
 import ch.ethz.seb.sebserver.gui.widget.Message;
 
 public class PageContextImpl implements PageContext {
 
     private static final Logger log = LoggerFactory.getLogger(PageContextImpl.class);
 
-    private static final ListenerComparator LIST_COMPARATOR = new ListenerComparator();
-
     private final I18nSupport i18nSupport;
     private final ComposerService composerService;
     private final Composite root;
@@ -218,48 +210,14 @@ public class PageContextImpl implements PageContext {
     }
 
     @Override
-    @SuppressWarnings("unchecked")
-    public <T extends PageEvent> void firePageEvent(final T event) {
-        final Class<? extends PageEvent> typeClass = event.getClass();
-        final List<PageEventListener<T>> listeners = new ArrayList<>();
-        ComposerService.traversePageTree(
-                this.root,
-                c -> {
-                    final PageEventListener<?> listener =
-                            (PageEventListener<?>) c.getData(PageEventListener.LISTENER_ATTRIBUTE_KEY);
-                    return listener != null && listener.match(typeClass);
-                },
-                c -> listeners.add(((PageEventListener<T>) c.getData(PageEventListener.LISTENER_ATTRIBUTE_KEY))));
-
-        if (listeners.isEmpty()) {
-            return;
-        }
-
-        listeners.stream()
-                .sorted(LIST_COMPARATOR)
-                .forEach(listener -> {
-                    try {
-                        listener.notify(event);
-                    } catch (final Exception e) {
-                        log.error("Unexpected error while notify PageEventListener: ", e);
-                    }
-                });
-    }
-
-    @Override
-    public PageAction createAction(final ActionDefinition actionDefinition) {
-        return new PageAction(actionDefinition, this);
-    }
-
-    @Override
-    public void applyConfirmDialog(final LocTextKey confirmMessage, final Runnable onOK) {
+    public void applyConfirmDialog(final LocTextKey confirmMessage, final Consumer<Boolean> callback) {
         final Message messageBox = new Message(
                 this.root.getShell(),
                 this.i18nSupport.getText("sebserver.dialog.confirm.title"),
                 this.i18nSupport.getText(confirmMessage),
                 SWT.OK | SWT.CANCEL);
         messageBox.setMarkupEnabled(true);
-        messageBox.open(new ConfirmDialogCallback(onOK));
+        messageBox.open(new ConfirmDialogCallback(callback));
     }
 
     @Override
@@ -341,7 +299,6 @@ public class PageContextImpl implements PageContext {
             log.info("Cleanup logout failed: {}", e.getMessage());
         }
 
-        MainPageState.clear();
         forwardToLoginPage();
     }
 
@@ -353,9 +310,9 @@ public class PageContextImpl implements PageContext {
 
     private static final class ConfirmDialogCallback implements DialogCallback {
         private static final long serialVersionUID = 1491270214433492441L;
-        private final Runnable onOK;
+        private final Consumer<Boolean> onOK;
 
-        private ConfirmDialogCallback(final Runnable onOK) {
+        private ConfirmDialogCallback(final Consumer<Boolean> onOK) {
             this.onOK = onOK;
         }
 
@@ -363,25 +320,15 @@ public class PageContextImpl implements PageContext {
         public void dialogClosed(final int returnCode) {
             if (returnCode == SWT.OK) {
                 try {
-                    this.onOK.run();
+                    this.onOK.accept(true);
                 } catch (final Throwable t) {
                     log.error(
                             "Unexpected on confirm callback execution. This should not happen, plase secure the given onOK Runnable",
                             t);
+                    this.onOK.accept(false);
                 }
             }
-        }
-    }
-
-    private static final class ListenerComparator implements Comparator<PageEventListener<?>>, Serializable {
-
-        private static final long serialVersionUID = 2571739214439340404L;
-
-        @Override
-        public int compare(final PageEventListener<?> o1, final PageEventListener<?> o2) {
-            final int x = o1.priority();
-            final int y = o2.priority();
-            return (x < y) ? -1 : ((x == y) ? 0 : 1);
+            this.onOK.accept(false);
         }
     }
 
diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/page/impl/PageServiceImpl.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/page/impl/PageServiceImpl.java
new file mode 100644
index 00000000..c182a45d
--- /dev/null
+++ b/src/main/java/ch/ethz/seb/sebserver/gui/service/page/impl/PageServiceImpl.java
@@ -0,0 +1,236 @@
+/*
+ * Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+package ch.ethz.seb.sebserver.gui.service.page.impl;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.List;
+import java.util.function.Consumer;
+
+import javax.servlet.http.HttpSession;
+
+import org.eclipse.rap.rwt.RWT;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.context.annotation.Lazy;
+import org.springframework.stereotype.Service;
+
+import ch.ethz.seb.sebserver.gbl.api.JSONMapper;
+import ch.ethz.seb.sebserver.gbl.model.Entity;
+import ch.ethz.seb.sebserver.gbl.model.Page;
+import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
+import ch.ethz.seb.sebserver.gbl.util.Result;
+import ch.ethz.seb.sebserver.gui.form.FormBuilder;
+import ch.ethz.seb.sebserver.gui.service.i18n.I18nSupport;
+import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey;
+import ch.ethz.seb.sebserver.gui.service.i18n.PolyglotPageService;
+import ch.ethz.seb.sebserver.gui.service.page.ComposerService;
+import ch.ethz.seb.sebserver.gui.service.page.PageContext;
+import ch.ethz.seb.sebserver.gui.service.page.PageService;
+import ch.ethz.seb.sebserver.gui.service.page.PageState;
+import ch.ethz.seb.sebserver.gui.service.page.PageState.Type;
+import ch.ethz.seb.sebserver.gui.service.page.event.ActionEvent;
+import ch.ethz.seb.sebserver.gui.service.page.event.ActionPublishEvent;
+import ch.ethz.seb.sebserver.gui.service.page.event.PageEvent;
+import ch.ethz.seb.sebserver.gui.service.page.event.PageEventListener;
+import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCall;
+import ch.ethz.seb.sebserver.gui.table.TableBuilder;
+import ch.ethz.seb.sebserver.gui.widget.WidgetFactory;
+
+@Lazy
+@Service
+@GuiProfile
+public class PageServiceImpl implements PageService {
+
+    private static final Logger log = LoggerFactory.getLogger(PageServiceImpl.class);
+
+    private static final LocTextKey MSG_GO_AWAY_FROM_EDIT =
+            new LocTextKey("sebserver.overall.action.goAwayFromEditPageConfirm");
+
+    private static final String ATTR_PAGE_STATE = "PAGE_STATE";
+    private static final ListenerComparator LIST_COMPARATOR = new ListenerComparator();
+
+    private final JSONMapper jsonMapper;
+    private final WidgetFactory widgetFactory;
+    private final PolyglotPageService polyglotPageService;
+
+    public PageServiceImpl(
+            final JSONMapper jsonMapper,
+            final WidgetFactory widgetFactory,
+            final PolyglotPageService polyglotPageService) {
+
+        this.jsonMapper = jsonMapper;
+        this.widgetFactory = widgetFactory;
+        this.polyglotPageService = polyglotPageService;
+    }
+
+    @Override
+    public WidgetFactory getWidgetFactory() {
+        return this.widgetFactory;
+    }
+
+    @Override
+    public PolyglotPageService getPolyglotPageService() {
+        return this.polyglotPageService;
+    }
+
+    @Override
+    public I18nSupport getI18nSupport() {
+        return this.widgetFactory.getI18nSupport();
+    }
+
+    @Override
+    public JSONMapper getJSONMapper() {
+        return this.jsonMapper;
+    }
+
+    @Override
+    public PageState initPageState(final PageState initState) {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    @Override
+    public PageState getCurrentState() {
+        try {
+
+            final HttpSession httpSession = RWT
+                    .getUISession()
+                    .getHttpSession();
+
+            return (PageState) httpSession.getAttribute(ATTR_PAGE_STATE);
+
+        } catch (final Exception e) {
+            log.error("Failed to get current PageState: ", e);
+            return null;
+        }
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public <T extends PageEvent> void firePageEvent(final T event, final PageContext pageContext) {
+        final Class<? extends PageEvent> typeClass = event.getClass();
+        final List<PageEventListener<T>> listeners = new ArrayList<>();
+        ComposerService.traversePageTree(
+                pageContext.getRoot(),
+                c -> {
+                    final PageEventListener<?> listener =
+                            (PageEventListener<?>) c.getData(PageEventListener.LISTENER_ATTRIBUTE_KEY);
+                    return listener != null && listener.match(typeClass);
+                },
+                c -> listeners.add(((PageEventListener<T>) c.getData(PageEventListener.LISTENER_ATTRIBUTE_KEY))));
+
+        if (listeners.isEmpty()) {
+            return;
+        }
+
+        listeners.stream()
+                .sorted(LIST_COMPARATOR)
+                .forEach(listener -> {
+                    try {
+                        listener.notify(event);
+                    } catch (final Exception e) {
+                        log.error("Unexpected error while notify PageEventListener: ", e);
+                    }
+                });
+    }
+
+    @Override
+    public void executePageAction(final PageAction pageAction, final Consumer<Result<PageAction>> callback) {
+        final PageState currentState = getCurrentState();
+
+        // TODO should there be a check to reload or not to reload the page if the state is the same?
+
+        if (!pageAction.ignoreMoveAwayFromEdit && currentState != null && currentState.type() == Type.FORM_EDIT) {
+            pageAction.pageContext().applyConfirmDialog(
+                    MSG_GO_AWAY_FROM_EDIT,
+                    confirm -> {
+                        if (confirm) {
+                            exec(pageAction, callback);
+                        } else {
+                            callback.accept(Result.ofRuntimeError("Confirm denied"));
+                        }
+                    });
+        } else {
+            exec(pageAction, callback);
+        }
+    }
+
+    private void exec(final PageAction pageAction, final Consumer<Result<PageAction>> callback) {
+        pageAction.applyAction(result -> {
+            if (!result.hasError()) {
+                final PageAction action = result.get();
+                if (pageAction.fireActionEvent) {
+                    firePageEvent(new ActionEvent(action), action.pageContext());
+                }
+
+                try {
+
+                    final HttpSession httpSession = RWT
+                            .getUISession()
+                            .getHttpSession();
+
+                    log.debug("SET session PageState: {} : {}", pageAction.definition.targetState, httpSession.getId());
+                    httpSession.setAttribute(ATTR_PAGE_STATE, pageAction.definition.targetState);
+
+                } catch (final Exception e) {
+                    log.error("Failed to set current PageState: ", e);
+                }
+
+            }
+            callback.accept(result);
+        });
+
+    }
+
+    @Override
+    public void publishAction(final PageAction pageAction) {
+        this.firePageEvent(new ActionPublishEvent(pageAction), pageAction.pageContext());
+    }
+
+    @Override
+    public FormBuilder formBuilder(final PageContext pageContext, final int rows) {
+        return new FormBuilder(this, pageContext, rows);
+    }
+
+    @Override
+    public <T extends Entity> TableBuilder<T> entityTableBuilder(final RestCall<Page<T>> apiCall) {
+        return new TableBuilder<>(this, apiCall);
+    }
+
+    @Override
+    public void clear() {
+        try {
+
+            final HttpSession httpSession = RWT
+                    .getUISession()
+                    .getHttpSession();
+
+            log.debug("Clear session PageState: {}", httpSession.getId());
+            httpSession.removeAttribute(ATTR_PAGE_STATE);
+
+        } catch (final Exception e) {
+            log.error("Failed to clear current PageState: ", e);
+        }
+    }
+
+    private static final class ListenerComparator implements Comparator<PageEventListener<?>>, Serializable {
+
+        private static final long serialVersionUID = 2571739214439340404L;
+
+        @Override
+        public int compare(final PageEventListener<?> o1, final PageEventListener<?> o2) {
+            final int x = o1.priority();
+            final int y = o2.priority();
+            return (x < y) ? -1 : ((x == y) ? 0 : 1);
+        }
+    }
+
+}
diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/page/PageUtils.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/page/impl/PageUtils.java
similarity index 88%
rename from src/main/java/ch/ethz/seb/sebserver/gui/service/page/PageUtils.java
rename to src/main/java/ch/ethz/seb/sebserver/gui/service/page/impl/PageUtils.java
index 9634f330..4a467589 100644
--- a/src/main/java/ch/ethz/seb/sebserver/gui/service/page/PageUtils.java
+++ b/src/main/java/ch/ethz/seb/sebserver/gui/service/page/impl/PageUtils.java
@@ -6,7 +6,7 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
  */
 
-package ch.ethz.seb.sebserver.gui.service.page;
+package ch.ethz.seb.sebserver.gui.service.page.impl;
 
 import java.util.Set;
 import java.util.function.Supplier;
@@ -28,18 +28,6 @@ public final class PageUtils {
 
     private static final Logger log = LoggerFactory.getLogger(PageUtils.class);
 
-    enum CommonTextKeys {
-
-        ;
-
-        public LocTextKey textKey;
-
-        private CommonTextKeys(final LocTextKey textKey) {
-            this.textKey = textKey;
-        }
-
-    }
-
     public static void clearComposite(final Composite parent) {
         if (parent == null) {
             return;
diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/remote/webservice/api/RestService.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/remote/webservice/api/RestService.java
index 57217193..f79f6ea2 100644
--- a/src/main/java/ch/ethz/seb/sebserver/gui/service/remote/webservice/api/RestService.java
+++ b/src/main/java/ch/ethz/seb/sebserver/gui/service/remote/webservice/api/RestService.java
@@ -12,7 +12,6 @@ import org.springframework.web.client.RestTemplate;
 import org.springframework.web.util.UriComponentsBuilder;
 
 import ch.ethz.seb.sebserver.gbl.api.EntityType;
-import ch.ethz.seb.sebserver.gui.service.page.PageAction;
 import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCall.CallType;
 
 /** Interface to SEB Server webservice API thought RestCall's
@@ -72,11 +71,11 @@ public interface RestService {
             EntityType entityType,
             CallType callType);
 
-    /** Performs an activation Action on RestCall specified within the given Action.
-     * The RestCall must be of CallType.ACTIVATION_ACTIVATE or CallType.ACTIVATION_DEACTIVATE
-     *
-     * @param action the Action that defines an entity activation
-     * @return the successfully executed Action */
-    <T> PageAction activation(PageAction action);
+//    /** Performs an activation Action on RestCall specified within the given Action.
+//     * The RestCall must be of CallType.ACTIVATION_ACTIVATE or CallType.ACTIVATION_DEACTIVATE
+//     *
+//     * @param action the Action that defines an entity activation
+//     * @return the successfully executed Action */
+//    <T> PageAction activation(PageAction action);
 
 }
\ No newline at end of file
diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/remote/webservice/api/RestServiceImpl.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/remote/webservice/api/RestServiceImpl.java
index 9b74a6e7..72140f52 100644
--- a/src/main/java/ch/ethz/seb/sebserver/gui/service/remote/webservice/api/RestServiceImpl.java
+++ b/src/main/java/ch/ethz/seb/sebserver/gui/service/remote/webservice/api/RestServiceImpl.java
@@ -17,12 +17,9 @@ import org.springframework.stereotype.Service;
 import org.springframework.web.client.RestTemplate;
 import org.springframework.web.util.UriComponentsBuilder;
 
-import ch.ethz.seb.sebserver.gbl.api.API;
 import ch.ethz.seb.sebserver.gbl.api.EntityType;
 import ch.ethz.seb.sebserver.gbl.api.JSONMapper;
 import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
-import ch.ethz.seb.sebserver.gui.service.page.PageAction;
-import ch.ethz.seb.sebserver.gui.service.page.PageContext.AttributeKeys;
 import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCall.CallType;
 import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.AuthorizationContextHolder;
 import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.WebserviceURIService;
@@ -113,24 +110,24 @@ public class RestServiceImpl implements RestService {
         return restCall.newBuilder();
     }
 
-    @Override
-    public <T> PageAction activation(final PageAction action) {
-        if (action.definition.restCallType == null) {
-            throw new IllegalArgumentException("ActionDefinition needs to define a restCallType to use this action");
-        }
-
-        @SuppressWarnings("unchecked")
-        final Class<? extends RestCall<T>> restCallType =
-                (Class<? extends RestCall<T>>) action.definition.restCallType;
-
-        this.getBuilder(restCallType)
-                .withURIVariable(
-                        API.PARAM_MODEL_ID,
-                        action.pageContext().getAttribute(AttributeKeys.ENTITY_ID))
-                .call()
-                .onErrorDo(t -> action.pageContext().notifyError(t));
-
-        return action;
-    }
+//    @Override
+//    public <T> PageAction activation(final PageAction action) {
+//        if (action.restCallType() == null) {
+//            throw new IllegalArgumentException("ActionDefinition needs to define a restCallType to use this action");
+//        }
+//
+//        @SuppressWarnings("unchecked")
+//        final Class<? extends RestCall<T>> restCallType =
+//                (Class<? extends RestCall<T>>) action.restCallType();
+//
+//        this.getBuilder(restCallType)
+//                .withURIVariable(
+//                        API.PARAM_MODEL_ID,
+//                        action.pageContext().getAttribute(AttributeKeys.ENTITY_ID))
+//                .call()
+//                .onErrorDo(t -> action.pageContext().notifyError(t));
+//
+//        return action;
+//    }
 
 }
diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/table/EntityTable.java b/src/main/java/ch/ethz/seb/sebserver/gui/table/EntityTable.java
index 77684c56..b01bd40c 100644
--- a/src/main/java/ch/ethz/seb/sebserver/gui/table/EntityTable.java
+++ b/src/main/java/ch/ethz/seb/sebserver/gui/table/EntityTable.java
@@ -39,7 +39,8 @@ import ch.ethz.seb.sebserver.gbl.model.Page;
 import ch.ethz.seb.sebserver.gbl.util.Utils;
 import ch.ethz.seb.sebserver.gui.service.i18n.I18nSupport;
 import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey;
-import ch.ethz.seb.sebserver.gui.service.page.PageAction;
+import ch.ethz.seb.sebserver.gui.service.page.PageService;
+import ch.ethz.seb.sebserver.gui.service.page.impl.PageAction;
 import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCall;
 import ch.ethz.seb.sebserver.gui.widget.WidgetFactory;
 import ch.ethz.seb.sebserver.gui.widget.WidgetFactory.ImageIcon;
@@ -52,6 +53,7 @@ public class EntityTable<ROW extends Entity> {
     static final String COLUMN_DEFINITION = "COLUMN_DEFINITION";
     static final String TABLE_ROW_DATA = "TABLE_ROW_DATA";
 
+    final PageService pageService;
     final WidgetFactory widgetFactory;
     final RestCall<Page<ROW>> restCall;
     final I18nSupport i18nSupport;
@@ -75,7 +77,7 @@ public class EntityTable<ROW extends Entity> {
             final int type,
             final Composite parent,
             final RestCall<Page<ROW>> restCall,
-            final WidgetFactory widgetFactory,
+            final PageService pageService,
             final List<ColumnDefinition<ROW>> columns,
             final List<TableRowAction> actions,
             final int pageSize,
@@ -83,8 +85,9 @@ public class EntityTable<ROW extends Entity> {
             final Function<EntityTable<ROW>, PageAction> defaultActionFunction) {
 
         this.composite = new Composite(parent, type);
-        this.widgetFactory = widgetFactory;
-        this.i18nSupport = widgetFactory.getI18nSupport();
+        this.pageService = pageService;
+        this.i18nSupport = pageService.getI18nSupport();
+        this.widgetFactory = pageService.getWidgetFactory();
         this.restCall = restCall;
         this.columns = Utils.immutableListOf(columns);
         this.actions = Utils.immutableListOf(actions);
@@ -110,7 +113,7 @@ public class EntityTable<ROW extends Entity> {
                         .findFirst()
                         .isPresent() ? new TableFilter<>(this) : null;
 
-        this.table = widgetFactory.tableLocalized(this.composite);
+        this.table = this.widgetFactory.tableLocalized(this.composite);
         final GridLayout gridLayout = new GridLayout(columns.size(), true);
         this.table.setLayout(gridLayout);
         gridData = new GridData(SWT.FILL, SWT.TOP, true, false);
@@ -133,9 +136,8 @@ public class EntityTable<ROW extends Entity> {
                 this.table.addListener(SWT.MouseDoubleClick, event -> {
                     final EntityKey selection = getSingleSelection();
                     if (selection != null) {
-                        defaultAction
-                                .withEntityKey(selection)
-                                .run();
+                        this.pageService.executePageAction(
+                                defaultAction.withEntityKey(selection));
                     }
                 });
             }
diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/table/TableBuilder.java b/src/main/java/ch/ethz/seb/sebserver/gui/table/TableBuilder.java
index 062322c5..365206ed 100644
--- a/src/main/java/ch/ethz/seb/sebserver/gui/table/TableBuilder.java
+++ b/src/main/java/ch/ethz/seb/sebserver/gui/table/TableBuilder.java
@@ -19,9 +19,9 @@ import org.eclipse.swt.widgets.Composite;
 import ch.ethz.seb.sebserver.gbl.model.Entity;
 import ch.ethz.seb.sebserver.gbl.model.Page;
 import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey;
-import ch.ethz.seb.sebserver.gui.service.page.PageAction;
+import ch.ethz.seb.sebserver.gui.service.page.PageService;
+import ch.ethz.seb.sebserver.gui.service.page.impl.PageAction;
 import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCall;
-import ch.ethz.seb.sebserver.gui.widget.WidgetFactory;
 
 /** <code>
  *  new TableBuilder<T>(RestCall)
@@ -40,7 +40,7 @@ import ch.ethz.seb.sebserver.gui.widget.WidgetFactory;
  * </code> */
 public class TableBuilder<ROW extends Entity> {
 
-    private final WidgetFactory widgetFactory;
+    private final PageService pageService;
     final RestCall<Page<ROW>> restCall;
     final List<ColumnDefinition<ROW>> columns = new ArrayList<>();
     final List<TableRowAction> actions = new ArrayList<>();
@@ -50,10 +50,10 @@ public class TableBuilder<ROW extends Entity> {
     private int type = SWT.NONE;
 
     public TableBuilder(
-            final WidgetFactory widgetFactory,
+            final PageService pageService,
             final RestCall<Page<ROW>> restCall) {
 
-        this.widgetFactory = widgetFactory;
+        this.pageService = pageService;
         this.restCall = restCall;
     }
 
@@ -107,7 +107,7 @@ public class TableBuilder<ROW extends Entity> {
                 this.type,
                 parent,
                 this.restCall,
-                this.widgetFactory,
+                this.pageService,
                 this.columns,
                 this.actions,
                 this.pageSize,
diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/table/TableNavigator.java b/src/main/java/ch/ethz/seb/sebserver/gui/table/TableNavigator.java
index 39848c9e..fbe87cb9 100644
--- a/src/main/java/ch/ethz/seb/sebserver/gui/table/TableNavigator.java
+++ b/src/main/java/ch/ethz/seb/sebserver/gui/table/TableNavigator.java
@@ -17,7 +17,7 @@ import org.eclipse.swt.widgets.Composite;
 import org.eclipse.swt.widgets.Label;
 
 import ch.ethz.seb.sebserver.gbl.model.Page;
-import ch.ethz.seb.sebserver.gui.service.page.PageUtils;
+import ch.ethz.seb.sebserver.gui.service.page.impl.PageUtils;
 import ch.ethz.seb.sebserver.gui.widget.WidgetFactory.CustomVariant;
 
 public class TableNavigator {
diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/widget/MultiSelection.java b/src/main/java/ch/ethz/seb/sebserver/gui/widget/MultiSelection.java
index 1aee259a..c7300066 100644
--- a/src/main/java/ch/ethz/seb/sebserver/gui/widget/MultiSelection.java
+++ b/src/main/java/ch/ethz/seb/sebserver/gui/widget/MultiSelection.java
@@ -23,7 +23,7 @@ import org.eclipse.swt.widgets.Label;
 
 import ch.ethz.seb.sebserver.gbl.Constants;
 import ch.ethz.seb.sebserver.gbl.util.Tuple;
-import ch.ethz.seb.sebserver.gui.service.page.PageUtils;
+import ch.ethz.seb.sebserver.gui.service.page.impl.PageUtils;
 import ch.ethz.seb.sebserver.gui.widget.WidgetFactory.CustomVariant;
 
 public class MultiSelection extends Composite implements Selection {
diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/widget/WidgetFactory.java b/src/main/java/ch/ethz/seb/sebserver/gui/widget/WidgetFactory.java
index ef4a2fb5..e1145719 100644
--- a/src/main/java/ch/ethz/seb/sebserver/gui/widget/WidgetFactory.java
+++ b/src/main/java/ch/ethz/seb/sebserver/gui/widget/WidgetFactory.java
@@ -39,8 +39,6 @@ import org.slf4j.LoggerFactory;
 import org.springframework.context.annotation.Lazy;
 import org.springframework.stereotype.Service;
 
-import ch.ethz.seb.sebserver.gbl.model.Entity;
-import ch.ethz.seb.sebserver.gbl.model.Page;
 import ch.ethz.seb.sebserver.gbl.model.exam.Indicator.Threshold;
 import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
 import ch.ethz.seb.sebserver.gbl.util.Tuple;
@@ -50,8 +48,6 @@ import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey;
 import ch.ethz.seb.sebserver.gui.service.i18n.PolyglotPageService;
 import ch.ethz.seb.sebserver.gui.service.page.PageContext;
 import ch.ethz.seb.sebserver.gui.service.push.ServerPushService;
-import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCall;
-import ch.ethz.seb.sebserver.gui.table.TableBuilder;
 
 @Lazy
 @Service
@@ -310,10 +306,6 @@ public class WidgetFactory {
         return item;
     }
 
-    public <T extends Entity> TableBuilder<T> entityTableBuilder(final RestCall<Page<T>> apiCall) {
-        return new TableBuilder<>(this, apiCall);
-    }
-
     public Table tableLocalized(final Composite parent) {
         final Table table = new Table(parent, SWT.SINGLE | SWT.NO_SCROLL);
         this.injectI18n(table);
diff --git a/src/main/resources/messages.properties b/src/main/resources/messages.properties
index 7b5e428d..c9805e61 100644
--- a/src/main/resources/messages.properties
+++ b/src/main/resources/messages.properties
@@ -15,7 +15,7 @@ sebserver.overall.action.filter.clear=Clear Filter Criteria
 sebserver.overall.action.ok=OK
 sebserver.overall.action.cancel=Cancel
 sebserver.overall.action.close=Close
-
+sebserver.overall.action.goAwayFromEditPageConfirm=Are you sure to leave this page? Any unsaved data will be lost. 
 sebserver.overall.action.category.varia=Varia
 
 ################################