Repository: CSCfi/rems
Pull request #1616 (2019-09-11 13:28:49)

Flash message location
#1580

Adds support for having flash messages at different places on the page.

# Definition of Done / Review checklist

## Reviewability
- [x] link to issue

## Documentation
- [x] update changelog if necessary
   - flash messages are still in the unreleased section, so no need to add more details
- [x] add or update docstrings for namespaces and functions

## Accessibility
- [x] conscious decision about where to move focus after an action



Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index b9987f67f..df70d09fb 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -71,7 +71,6 @@ Changes since v2.4
 - Improved table performance: added a "show all rows" button for long tables
 - Modal popups have been replaced with flash messages (#1469)
 - Email messages now use the application title and full names of users
-- Email message texts improved
 
 ### Fixes
 - Entitlement API
diff --git a/resources/migrations/20190910192940-missing-licenses-in-resources-changed.edn b/resources/migrations/20190910192940-missing-licenses-in-resources-changed.edn
deleted file mode 100644
index a1ca03543..000000000
--- a/resources/migrations/20190910192940-missing-licenses-in-resources-changed.edn
+++ /dev/null
@@ -1,3 +0,0 @@
-{:ns rems.migrations.missing-licenses-in-resources-changed
- :up-fn migrate-up
- :down-fn nil}
diff --git a/resources/translations/en.edn b/resources/translations/en.edn
index d1d284df5..6612a1e57 100644
--- a/resources/translations/en.edn
+++ b/resources/translations/en.edn
@@ -23,8 +23,6 @@
             :licenses-not-accepted-error "Terms of use not accepted."
             :load-application-states "Load application states"
             :member "Member"
-            :member-invited "Member invited."
-            :member-added "Member added."
             :member-name "Name"
             :member-email "Email"
             :name-and-email-required "Name and email are required."
@@ -218,43 +216,36 @@
                     :title "Title"}
   :dropdown {:no-results "No results"
              :placeholder "Select..."}
-  :email {:application-approved {:subject-to-applicant "Your application has been approved (%3)"
-                                 :message-to-applicant "Dear %1,\n\nYour application %3 has been approved.\n\nYou can view the application and the decision: %6"
-                                 :subject-to-handler "Application approved (%3)"
-                                 :message-to-handler "Dear %1,\n\n%2 has approved the application %3 from %4.\n\nYou can view the application and the decision: %6"}
-          :application-rejected {:subject-to-applicant "Your application has been rejected (%3)"
-                                 :message-to-applicant "Dear %1,\n\nYour application %3 has been rejected.\n\nYou can view the application and the decision: %6"
-                                 :subject-to-handler "Application rejected (%3)"
-                                 :message-to-handler "Dear %1,\n\n%2 has rejected the application %3 from %4.\n\nYou can view the application and the decision: %6"}
-          :application-closed {:subject-to-applicant "Your application has been closed (%3)"
-                               :message-to-applicant "Dear %1,\n\nYour application %3 has been closed.\n\nYou can view the application: %6"
-                               :subject-to-handler "Application closed (%3)"
-                               :message-to-handler "Dear %1,\n\n%2 has closed the application %3 from %4.\n\nYou can view the application: %6"}
-          :application-returned {:subject-to-applicant "Your application has been returned for modifications (%3)"
-                                 :message-to-applicant "Dear %1,\n\nYour application %3 has been returned to you for modifications.\n\nYou can modify and resubmit the application: %6"
-                                 :subject-to-handler "Application has been returned for modifications (%3)"
-                                 :message-to-handler "Dear %1,\n\n%2 has returned the application %3 to the applicant %4 for modifications.\n\nYou can view the application: %6"}
-          :application-licenses-added {:subject "New terms of use waiting for approval (%3)"
-                                       :message "Dear %1,\n\n%2 has requested your acceptance for new terms of use for application %3.\n\nYou can view the application and accept the terms of use: %6"}
-          :application-resubmitted {:subject "Application has been resubmitted (%3)"
-                                    :message "Dear %1,\n\nApplication %3 has been resubmitted by %4.\n\nYou can view the application: %6"}
-          :application-submitted {:subject "A new application has been submitted (%3)"
-                                  :message "Dear %1,\n\n%4 has submitted a new application %3 to access resource(s) %5.\n\nYou can view the application: %6"}
-          :comment-requested {:subject "Review request (%3)"
-                              :message "Dear %1,\n\n%2 has requested your review on application %3 submitted by %4.\n\nYou can review the application: %6"}
-          :commented {:subject "Application has been reviewed (%3)"
-                     :message "Dear %1,\n\n%2 has reviewed the application %3 submitted by %4.\n\nYou can view the application and the review: %6"}
-          :decided {:subject "Decision notification (%3)"
-                    :message "Dear %1,\n\n%2 has sent a decision on application %3 submitted by %4.\n\nYou can view the application and the decision: %6"}
-          :decision-requested {:subject "Decision requested (%3)"
-                               :message "Dear %1,\n\n%2 has requested your decision on application %3 submitted by %4.\n\nYou can view application: %6"}
-          :footer "\n\nPlease do not reply to this automatically generated message."
+  :email {:application-approved {:subject "Application approved (%3)"
+                                 :message-to-applicant "Dear %1,\n\nYour application %3 has been approved.\n\nView application: %6"
+                                 :message-to-handler "Dear %1,\n\n%2 has approved the application %3 from %4.\n\nView application: %6"}
+          :application-rejected {:subject "Application rejected (%3)"
+                                 :message-to-applicant "Dear %1,\n\nYour application %3 has been rejected.\n\nView application: %6"
+                                 :message-to-handler "Dear %1,\n\n%2 has rejected the application %3 from %4.\n\nView application: %6"}
+          :application-closed {:subject "Application closed (%3)"
+                               :message-to-applicant "Dear %1,\n\nYour application %3 has been closed.\n\nView application: %6"
+                               :message-to-handler "Dear %1,\n\n%2 has closed the application %3 from %4.\n\nView application: %6"}
+          :application-returned {:subject "Application returned (%3)"
+                                 :message-to-applicant "Dear %1,\n\nYour application %3 has been returned.\n\nView application: %6"
+                                 :message-to-handler "Dear %1,\n\n%2 has returned the application %3 from %4.\n\nView application: %6"}
+          :application-licenses-added {:subject "Terms of use added to application (%3)"
+                                       :message-to-applicant "Dear %1,\n\nTerms of use have been added to your application %3. They need to be accepted before gaining access to the resources.\n\nView application: %6"
+                                       :message-to-handler "Dear %1,\n\n%2 has added terms of use to the application %3 from %4.\n\nView application: %6"}
+          :application-submitted {:subject "Application submitted (%4: %3)"
+                                  :message "Dear %1,\n\n%4 has submitted an application (%3): %5.\n\nView application: %6"}
+          :comment-requested {:subject "Review requested (%2: %3)"
+                              :message "Dear %1,\n\n%2 has requested a review on application %3.\n\nComment: %6"}
+          :commented {:subject "Review added (%2: %3)"
+                      :message "Dear %1,\n\n%2 has reviewed application %3.\n\nView application: %6"}
+          :decided {:subject "Decision made (%2: %3)"
+                    :message "Dear %1,\n\n%2 has made a decision on application %3.\n\nView application: %6"}
+          :decision-requested {:subject "Decision requested (%2: %3)"
+                               :message "Dear %1,\n\n%2 has requested your decision on application %3.\n\nView application: %6"}
+          :footer "\n\nPlease don't reply to this automatically generated message."
           :member-added {:subject "Added as a member of an application (%3)"
                          :message "Dear %1,\n\nYou've been added as a member of application %3.\n\nView application: %6"}
           :member-invited {:subject "Invitation to participate in an application"
-                           :message "Dear %1,\n\nYou have been invited to participate in an application submitted by %2. The title of the application is %3.\n\nYou can view the application and accept the terms of use: %4"}
-          :remarked {:subject "Application has been commented on (%3)"
-                     :message "Dear %1,\n\n%2 has commented on the application %3 submitted by %4.\n\nYou can view the application and the comment: %6"}}
+                           :message "Hello,\n\nThis email address (%1) has been invited to participate in an application.\n\nParticipate: %2"}}
   :footer "CSC – IT Center for Science"
   :form {:accepted-licenses "Accepted terms of use"
          :actions "Actions"
diff --git a/resources/translations/fi.edn b/resources/translations/fi.edn
index cf7b6aeef..fbafafc77 100644
--- a/resources/translations/fi.edn
+++ b/resources/translations/fi.edn
@@ -23,8 +23,6 @@
             :licenses-not-accepted-error "Käyttöehtoja ei ole hyväksytty."
             :load-application-states "Lataa hakemusten tilat"
             :member "Jäsen"
-            :member-added "Jäsen lisätty."
-            :member-invited "Jäsen kutsuttu."
             :member-name "Nimi"
             :member-email "Sähköposti"
             :name-and-email-required "Nimi ja sähköposti ovat pakollisia."
@@ -216,43 +214,36 @@
                     :title "Työvuon nimi"}
   :dropdown {:no-results "Ei tuloksia"
              :placeholder "Valitse..."}
-  :email {:application-approved {:subject-to-applicant "Hakemuksesi on hyväksytty (%3)"
-                                 :message-to-applicant "Hyvä %1,\n\nHakemuksesi %3 on hyväksytty.\n\nVoit tarkastella hakemusta ja päätöstä: %6"
-                                 :subject-to-handler "Hakemus hyväksytty (%3)"
-                                 :message-to-handler "Hyvä %1,\n\n%2 on hyväksynyt käyttäjän %4 hakemuksen %3.\n\nVoit tarkastella hakemusta ja päätöstä: %6"}
-          :application-rejected {:subject-to-applicant "Hakemuksesi on hylätty (%3)"
-                                 :message-to-applicant "Hyvä %1,\n\nHakemuksesi %3 on hylätty.\n\nVoit tarkastella hakemusta ja päätöstä: %6"
-                                 :subject-to-handler "Hakemus hylätty (%3)"
-                                 :message-to-handler "Hyvä %1,\n\n%2 on hylännyt käyttäjän %4 hakemuksen %3.\n\nVoit tarkastella hakemusta ja päätöstä: %6"}
-          :application-closed {:subject-to-applicant "Hakemuksesi on suljettu (%3)"
-                               :message-to-applicant "Hyvä %1,\n\nHakemuksesi %3 on suljettu.\n\nVoit tarkastella hakemusta: %5"
-                               :subject-to-handler "Hakemus suljettu (%3)"
-                               :message-to-handler "Hyvä %1,\n\n%2 on sulkenut käyttäjän %4 hakemuksen %3.\n\nVoit tarkastella hakemusta: %5"}
-          :application-returned {:subject-to-applicant "Hakemuksesi on palautettu (%3)"
-                                 :message-to-applicant "Hyvä %1,\n\nHakemuksesi %3 on palautettu muokattavaksi.\n\nVoit muokata hakemusta ja lähettää sen uudelleen: %6"
-                                 :subject-to-handler "Hakemus palautettu (%3)"
-                                 :message-to-handler "Hyvä %1,\n\n%2 on palauttanut käyttäjän %4 hakemuksen %3.\n\nVoit tarkastella hakemusta: %6"}
+  :email {:application-approved {:subject "Hakemus hyväksytty (%3)"
+                                 :message-to-applicant "Hyvä %1,\n\nHakemuksesi %3 on hyväksytty.\n\nTarkastele hakemusta: %5"
+                                 :message-to-handler "Hyvä %1,\n\n%2 on hyväksynyt käyttäjän %4 hakemuksen %3.\n\nTarkastele hakemusta: %5"}
+          :application-rejected {:subject "Hakemus hylätty (%3)"
+                                 :message-to-applicant "Hyvä %1,\n\nHakemuksesi %3 on hylätty.\n\nTarkastele hakemusta: %5"
+                                 :message-to-handler "Hyvä %1,\n\n%2 on hylännyt käyttäjän %4 hakemuksen %3.\n\nTarkastele hakemusta: %5"}
+          :application-closed {:subject "Hakemus suljettu (%3)"
+                               :message-to-applicant "Hyvä %1,\n\nHakemuksesi %3 on suljettu.\n\nTarkastele hakemusta: %5"
+                               :message-to-handler "Hyvä %1,\n\n%2 on sulkenut käyttäjän %4 hakemuksen %3.\n\nTarkastele hakemusta: %5"}
+          :application-returned {:subject "Hakemus palautettu (%3)"
+                                 :message-to-applicant "Hyvä %1,\n\nHakemuksesi %3 on palautettu.\n\nTarkastele hakemusta: %5"
+                                 :message-to-handler "Hyvä %1,\n\n%2 on palauttanut käyttäjän %4 hakemuksen %3.\n\nTarkastele hakemusta: %5"}
           :application-licenses-added {:subject "Hakemukseen lisätty käyttöehtoja (%3)"
-                                       :message "Hyvä %1,\n\n%2 pyytää hyväksyntääsi uusille käyttöehdoille hakemukseen %3.\n\nVoit tarkastella hakemusta ja hyväksyä käyttöehdot: %6"}
-          :application-resubmitted {:subject "Hakemus lähetetty uudelleen (%3)"
-                                    :message "Dear %1,\n\nKäyttäjä %4 on lähettänyt uudelleen hakemuksen %3.\n\nVoit tarkastella hakemusta: %6"}
-          :application-submitted {:subject "Uusi hakemus (%3)"
-                                  :message "Hyvä %1,\n\n%4 on lähettänyt käyttöoikeushakemuksen %3 resurss(e)ille %5.\n\nVoit tarkastella hakemusta: %6"}
-          :comment-requested {:subject "Katselmointipyyntö (%3)"
-                              :message "Hyvä %1,\n\n%2 on pyytänyt katselmointiasi käyttäjän %4 lähettämälle hakemukselle %3.\n\nVoit katselmoida hakemuksen: %6"}
-          :commented {:subject "Hakemus katselmoitu (%3)"
-                      :message "Hyvä %1,\n\n%2 on katselmoinut käyttäjän %4 lähettämän hakemuksen %3.\n\nVoit tarkastella hakemusta ja lukea kommentit: %6"}
-          :decided {:subject "Päätös lähetetty (%3)"
-                    :message "Hyvä %1,\n\n%2 on lähettänyt päätöksen käyttäjän %4 hakemuksesta %3.\n\nVoit tarkastella hakemusta ja päätöstä: %6"}
-          :decision-requested {:subject "Päätöspyyntö (%3)"
-                               :message "Hyvä %1,\n\n%2 on pyytänyt sinulta päätöstä käyttäjän %4 hakemuksesta %3.\n\nVoit tarkastella hakemusta: %6"}
+                                       :message-to-applicant "Hyvä %1,\n\nHakemukseesi %3 on lisätty käyttöehtoja. Käyttöehdot täytyy hyväksyä ennen käyttöoikeuden saamista.\n\nTarkastele hakemusta: %5"
+                                       :message-to-handler "Hyvä %1,\n\n%2 on lisännyt käyttöehtoja käyttäjän %4 hakemukseen %3.\n\nTarkastele hakemusta: %5"}
+          :application-submitted {:subject "Hakemus lähetetty (%4: %3)"
+                                  :message "Hyvä %1,\n\n%4 on lähettänyt käyttöoikeushakemuksen (%3): %5.\n\nTarkastele hakemusta: %6"}
+          :comment-requested {:subject "Katselmointipyyntö (%2: %3)"
+                              :message "Hyvä %1,\n\n%2 on pyytänyt katselmoimaan hakemuksen %3.\n\nKommentoi: %6"}
+          :commented {:subject "Hakemus katselmoitu (%2: %3)"
+                      :message "Hyvä %1,\n\n%2 on katselmoinut hakemuksen %3.\n\nTarkastele hakemusta: %6"}
+          :decided {:subject "Päätös tehty (%2: %3)"
+                    :message "Hyvä %1,\n\n%2 on tehnyt päätöksen hakemuksesta %3.\n\nTarkastele hakemusta: %6"}
+          :decision-requested {:subject "Päätöspyyntö (%2: %3)"
+                               :message "Hyvä %1,\n\n%2 on pyytänyt sinua tekemään päätöksen hakemuksesta %3.\n\nTarkastele hakemusta: %6"}
           :footer "\n\nTämä on automaattinen viesti. Älä vastaa."
           :member-added {:subject "Lisätty hakemuksen jäseneksi (%3)"
-                         :message "Hyvä %1,\n\nSinut on lisätty hakemuksen %3 jäseneksi.\n\nVoit tarkastella hakemusta: %6"}
+                         :message "Hyvä %1,\n\nSinut on lisätty hakemuksen %3 jäseneksi.\n\nTarkastele hakemusta: %6"}
           :member-invited {:subject "Kutsu osallistumaan hakemukseen"
-                           :message "Hyvä %1,\n\nSinut on kutsuttu osallistumaan käyttäjän %2 jättämään käyttöoikeushakemukseen. Hakemuksen otsikko on %3.\n\nVoit tarkastella hakemusta ja hyväksyä käyttöehdot: %4"}
-          :remarked {:subject "Hakemusta kommentoitu (%3)"
-                     :message "Hyvä %1,\n\n%2 on kommentoinut käyttäjän %4 lähettämää hakemusta %3.\n\nVoit tarkastella hakemusta ja lukea kommentin: %6"}}
+                           :message "Hei,\n\nTämä sähköpostiosoite (%1) on kutsuttu osallistumaan resurssien käyttöoikeushakemukseen.\n\nOsallistumislinkki: %2"}}
   :footer "CSC – Tieteen tietotekniikan keskus"
   :form {:accepted-licenses "Käyttöehdot hyväksytty"
          :actions "Toiminnot"
diff --git a/src/clj/rems/migrations/missing_licenses_in_resources_changed.clj b/src/clj/rems/migrations/missing_licenses_in_resources_changed.clj
deleted file mode 100644
index a5d9d3f8e..000000000
--- a/src/clj/rems/migrations/missing_licenses_in_resources_changed.clj
+++ /dev/null
@@ -1,67 +0,0 @@
-(ns rems.migrations.missing-licenses-in-resources-changed
-  (:require [hugsql.core :as hugsql]
-            [rems.json :as json]))
-
-;; Fixes the resources-changed type events in the database. Those events
-;; did not have :application/licenses field previously, which caused the
-;; licenses to not be updated when resources were changed.
-;;
-;; This migration goes through all resources-changed events in the database
-;; and adds :application/licenses field to the event data, with license ids
-;; corresponding to the new selection of resources.
-
-;; SQL query for get-licenses repeated here so that this migration is standalone
-
-(hugsql/def-db-fns-from-string
-  "
--- :name get-events-of-type-resources-changed :? :*
-SELECT id, appid, eventdata::TEXT
-FROM application_event
-WHERE eventdata->>'event/type' = 'application.event/resources-changed';
-
--- :name update-event! :!
-UPDATE application_event
-SET eventdata = eventdata || :value::jsonb
-WHERE id = :id;
-
--- :name get-licenses :? :*
--- :doc
--- - Gets application licenses by workflow and catalogue item ids
--- - :wfid workflow id for workflow licenses
--- - :items vector of catalogue item ids for resource licenses
-SELECT lic.id, lic.type, lic.enabled, lic.archived
-FROM license lic
-INNER JOIN workflow_licenses wl ON lic.id = wl.licid
-WHERE wl.wfid = :wfid
-UNION
-SELECT lic.id, lic.type, lic.enabled, lic.archived
-FROM license lic
-INNER JOIN resource_licenses rl ON lic.id = rl.licid
-INNER JOIN catalogue_item item ON (item.resid = rl.resid)
-WHERE item.id IN (:v*:items)
-ORDER BY id;
-
--- :name get-catalogue-item-workflow :? :1
-SELECT wfid
-FROM catalogue_item
-WHERE id = :id;
-")
-
-(defn get-catalogue-item-license-ids [catalogue-item-id conn]
-  (let [wfid (:wfid (get-catalogue-item-workflow conn {:id catalogue-item-id}))]
-    (map :id (get-licenses conn {:wfid wfid
-                                 :items [catalogue-item-id]}))))
-
-(defn migrate-up [{:keys [conn]}]
-  (doseq [{:keys [id appid eventdata]}
-          (get-events-of-type-resources-changed conn)]
-    (let [event (json/parse-string eventdata)
-          cat-ids (mapv :catalogue-item/id (:application/resources event))
-          licenses (->> cat-ids
-                        (mapcat #(get-catalogue-item-license-ids % conn))
-                        distinct)
-          value (json/generate-string
-                 {:application/licenses
-                  (map (fn [licid] {:license/id licid}) licenses)})]
-      (update-event! conn {:id id
-                           :value value}))))
diff --git a/src/clj/rems/poller/email.clj b/src/clj/rems/poller/email.clj
index e60c8122c..7f9851e30 100644
--- a/src/clj/rems/poller/email.clj
+++ b/src/clj/rems/poller/email.clj
@@ -95,60 +95,58 @@
 (defmethod event-to-emails-impl :application.event/approved [event application]
   (concat (emails-to-recipients (applicant-and-members application)
                                 event application
-                                :t.email.application-approved/subject-to-applicant
+                                :t.email.application-approved/subject
                                 :t.email.application-approved/message-to-applicant)
           (emails-to-recipients (other-handlers event application)
                                 event application
-                                :t.email.application-approved/subject-to-handler
+                                :t.email.application-approved/subject
                                 :t.email.application-approved/message-to-handler)))
 
 (defmethod event-to-emails-impl :application.event/rejected [event application]
   (concat (emails-to-recipients (applicant-and-members application)
                                 event application
-                                :t.email.application-rejected/subject-to-applicant
+                                :t.email.application-rejected/subject
                                 :t.email.application-rejected/message-to-applicant)
           (emails-to-recipients (other-handlers event application)
                                 event application
-                                :t.email.application-rejected/subject-to-handler
+                                :t.email.application-rejected/subject
                                 :t.email.application-rejected/message-to-handler)))
 
 (defmethod event-to-emails-impl :application.event/closed [event application]
   (concat (emails-to-recipients (applicant-and-members application)
                                 event application
-                                :t.email.application-closed/subject-to-applicant
+                                :t.email.application-closed/subject
                                 :t.email.application-closed/message-to-applicant)
           (emails-to-recipients (other-handlers event application)
                                 event application
-                                :t.email.application-closed/subject-to-handler
+                                :t.email.application-closed/subject
                                 :t.email.application-closed/message-to-handler)))
 
 (defmethod event-to-emails-impl :application.event/returned [event application]
   (concat (emails-to-recipients (applicant-and-members application)
                                 event application
-                                :t.email.application-returned/subject-to-applicant
+                                :t.email.application-returned/subject
                                 :t.email.application-returned/message-to-applicant)
           (emails-to-recipients (other-handlers event application)
                                 event application
-                                :t.email.application-returned/subject-to-handler
+                                :t.email.application-returned/subject
                                 :t.email.application-returned/message-to-handler)))
 
 (defmethod event-to-emails-impl :application.event/licenses-added [event application]
-  (emails-to-recipients (applicant-and-members application)
-                        event application
-                        :t.email.application-licenses-added/subject
-                        :t.email.application-licenses-added/message))
+  (concat (emails-to-recipients (applicant-and-members application)
+                                event application
+                                :t.email.application-licenses-added/subject
+                                :t.email.application-licenses-added/message-to-applicant)
+          (emails-to-recipients (other-handlers event application)
+                                event application
+                                :t.email.application-licenses-added/subject
+                                :t.email.application-licenses-added/message-to-handler)))
 
 (defmethod event-to-emails-impl :application.event/submitted [event application]
-  (if (= (:event/time event)
-         (:application/first-submitted application))
-    (emails-to-recipients (handlers application)
-                          event application
-                          :t.email.application-submitted/subject
-                          :t.email.application-submitted/message)
-    (emails-to-recipients (handlers application)
-                          event application
-                          :t.email.application-resubmitted/subject
-                          :t.email.application-resubmitted/message)))
+  (emails-to-recipients (handlers application)
+                        event application
+                        :t.email.application-submitted/subject
+                        :t.email.application-submitted/message))
 
 (defmethod event-to-emails-impl :application.event/comment-requested [event application]
   (emails-to-recipients (:application/commenters event)
@@ -162,12 +160,6 @@
                         :t.email.commented/subject
                         :t.email.commented/message))
 
-(defmethod event-to-emails-impl :application.event/remarked [event application]
-  (emails-to-recipients (handlers application)
-                        event application
-                        :t.email.remarked/subject
-                        :t.email.remarked/message))
-
 (defmethod event-to-emails-impl :application.event/decided [event application]
   (emails-to-recipients (handlers application)
                         event application
@@ -187,16 +179,16 @@
                         :t.email.member-added/subject
                         :t.email.member-added/message))
 
-(defmethod event-to-emails-impl :application.event/member-invited [event application]
+(defmethod event-to-emails-impl :application.event/member-invited [event _application]
   (with-language (:default-language env)
     (fn []
       [{:to (:email (:application/member event))
-        :subject (text-format :t.email.member-invited/subject)
+        :subject (text-format :t.email.member-invited/subject
+                              (:email (:application/member event))
+                              (invitation-link (:invitation/token event)))
         :body (str
                (text-format :t.email.member-invited/message
-                            (:name (:application/member event))
-                            (user-for-email (:application/applicant application))
-                            (format-application-for-email application)
+                            (:email (:application/member event))
                             (invitation-link (:invitation/token event)))
                (text :t.email/footer))}])))
 
diff --git a/src/cljs/rems/actions/accept_licenses.cljs b/src/cljs/rems/actions/accept_licenses.cljs
index 4acb93d67..14d05b282 100644
--- a/src/cljs/rems/actions/accept_licenses.cljs
+++ b/src/cljs/rems/actions/accept_licenses.cljs
@@ -1,18 +1,20 @@
 (ns rems.actions.accept-licenses
   (:require [re-frame.core :as rf]
             [rems.actions.action :refer [action-button action-form-view action-comment button-wrapper]]
-            [rems.status-modal :as status-modal]
+            [rems.flash-message :as flash-message]
             [rems.text :refer [text]]
             [rems.util :refer [post!]]))
 
 (rf/reg-event-fx
  ::send-accept-licenses
  (fn [_ [_ {:keys [application-id licenses on-finished]}]]
-   (post! "/api/applications/accept-licenses"
-          {:params {:application-id application-id
-                    :accepted-licenses licenses}
-           :handler (fn [_] (on-finished))
-           :error-handler status-modal/common-error-handler!})
+   (let [description (text :t.actions/accept-licenses)]
+     (post! "/api/applications/accept-licenses"
+            {:params {:application-id application-id
+                      :accepted-licenses licenses}
+             :handler (flash-message/default-success-handler
+                       :accept-licenses description (fn [_] (on-finished)))
+             :error-handler (flash-message/default-error-handler :accept-licenses description)}))
    {}))
 
 (defn accept-licenses-action-button [application-id licenses on-finished]
diff --git a/src/cljs/rems/actions/add_licenses.cljs b/src/cljs/rems/actions/add_licenses.cljs
index 60073110d..c0ca482f0 100644
--- a/src/cljs/rems/actions/add_licenses.cljs
+++ b/src/cljs/rems/actions/add_licenses.cljs
@@ -54,11 +54,12 @@
                       :comment comment
                       :licenses (map :id licenses)}
              :handler (flash-message/default-success-handler
+                       :top
                        description
                        (fn [_]
                          (collapse-action-form action-form-id)
                          (on-finished)))
-             :error-handler (flash-message/default-error-handler description)}))
+             :error-handler (flash-message/default-error-handler :top description)}))
    {}))
 
 (defn add-licenses-action-button []
diff --git a/src/cljs/rems/actions/add_member.cljs b/src/cljs/rems/actions/add_member.cljs
index e8a3160fe..c83f92207 100644
--- a/src/cljs/rems/actions/add_member.cljs
+++ b/src/cljs/rems/actions/add_member.cljs
@@ -18,7 +18,6 @@
  ::open-form
  (fn [{:keys [db]} _]
    {:db (assoc db
-               ::done? false
                ::potential-members #{}
                ::selected-member nil)
     ::fetch-potential-members #(rf/dispatch [::set-potential-members %])}))
@@ -34,23 +33,23 @@
 (rf/reg-event-db ::set-selected-member (fn [db [_ member]] (assoc db ::selected-member member)))
 (rf/reg-sub ::selected-member (fn [db _] (::selected-member db)))
 
-(rf/reg-event-db ::set-done? (fn [db [_ done]] (assoc db ::done? done)))
-(rf/reg-sub ::done? (fn [db _] (::done? db)))
-
 (def ^:private action-form-id "add-member")
 (def ^:private dropdown-id "add-member-dropdown")
 
 (rf/reg-event-fx
  ::send-add-member
  (fn [_ [_ {:keys [member application-id on-finished]}]]
-   (post! "/api/applications/add-member"
-          {:params {:application-id application-id
-                    :member (select-keys member [:userid])}
-           :handler (fn [_]
-                      (collapse-action-form action-form-id)
-                      (rf/dispatch [::set-done? true])
-                      (on-finished))
-           :error-handler (flash-message/default-error-handler (text :t.actions/add-member))})
+   (let [description (text :t.actions/add-member)]
+     (post! "/api/applications/add-member"
+            {:params {:application-id application-id
+                      :member (select-keys member [:userid])}
+             :handler (flash-message/default-success-handler
+                       :change-members
+                       description
+                       (fn [_]
+                         (collapse-action-form action-form-id)
+                         (on-finished)))
+             :error-handler (flash-message/default-error-handler :change-members description)}))
    {}))
 
 (defn add-member-action-button []
@@ -58,11 +57,6 @@
                   :text (text :t.actions/add-member)
                   :on-click #(rf/dispatch [::open-form])}])
 
-(defn add-member-status []
-  (when @(rf/subscribe [::done?])
-    [atoms/flash-message {:status :success
-                          :contents (text :t.actions/member-added)}]))
-
 (defn add-member-view
   [{:keys [selected-member potential-members on-set-member on-send]}]
   [action-form-view action-form-id
diff --git a/src/cljs/rems/actions/approve_reject.cljs b/src/cljs/rems/actions/approve_reject.cljs
index 1dbe6d089..b1033c13c 100644
--- a/src/cljs/rems/actions/approve_reject.cljs
+++ b/src/cljs/rems/actions/approve_reject.cljs
@@ -23,11 +23,12 @@
             {:params {:application-id application-id
                       :comment comment}
              :handler (flash-message/default-success-handler
+                       :top
                        description
                        (fn [_]
                          (collapse-action-form action-form-id)
                          (on-finished)))
-             :error-handler (flash-message/default-error-handler description)}))
+             :error-handler (flash-message/default-error-handler :top description)}))
    {}))
 
 (rf/reg-event-fx
@@ -38,11 +39,12 @@
             {:params {:application-id application-id
                       :comment comment}
              :handler (flash-message/default-success-handler
+                       :top
                        description
                        (fn [_]
                          (collapse-action-form action-form-id)
                          (on-finished)))
-             :error-handler (flash-message/default-error-handler description)}))
+             :error-handler (flash-message/default-error-handler :top description)}))
    {}))
 
 (defn approve-reject-action-button []
diff --git a/src/cljs/rems/actions/change_resources.cljs b/src/cljs/rems/actions/change_resources.cljs
index 9abaf8c70..69f8cf771 100644
--- a/src/cljs/rems/actions/change_resources.cljs
+++ b/src/cljs/rems/actions/change_resources.cljs
@@ -2,8 +2,8 @@
   (:require [re-frame.core :as rf]
             [rems.actions.action :refer [action-button action-form-view action-comment button-wrapper collapse-action-form]]
             [rems.dropdown :as dropdown]
+            [rems.flash-message :as flash-message]
             [rems.spinner :as spinner]
-            [rems.status-modal :as status-modal]
             [rems.text :refer [text get-localized-title]]
             [rems.util :refer [fetch post!]]))
 
@@ -38,15 +38,19 @@
 (rf/reg-event-fx
  ::send-change-resources
  (fn [_ [_ {:keys [application-id resources comment on-finished]}]]
-   (post! "/api/applications/change-resources"
-          {:params (merge {:application-id application-id
-                           :catalogue-item-ids (vec resources)}
-                          (when comment
-                            {:comment comment}))
-           :handler (fn [_]
-                      (collapse-action-form action-form-id)
-                      (on-finished))
-           :error-handler status-modal/common-error-handler!})
+   (let [description (text :t.actions/change-resources)]
+     (post! "/api/applications/change-resources"
+            {:params (merge {:application-id application-id
+                             :catalogue-item-ids (vec resources)}
+                            (when comment
+                              {:comment comment}))
+             :handler (flash-message/default-success-handler
+                       :change-resources
+                       description
+                       (fn [_]
+                         (collapse-action-form action-form-id)
+                         (on-finished)))
+             :error-handler (flash-message/default-error-handler :change-resources description)}))
    {}))
 
 (defn change-resources-action-button [initial-resources]
diff --git a/src/cljs/rems/actions/close.cljs b/src/cljs/rems/actions/close.cljs
index a475f53e2..4f61558d1 100644
--- a/src/cljs/rems/actions/close.cljs
+++ b/src/cljs/rems/actions/close.cljs
@@ -23,11 +23,12 @@
             {:params {:application-id application-id
                       :comment comment}
              :handler (flash-message/default-success-handler
+                       :top
                        description
                        (fn [_]
                          (collapse-action-form action-form-id)
                          (on-finished)))
-             :error-handler (flash-message/default-error-handler description)}))
+             :error-handler (flash-message/default-error-handler :top description)}))
    {}))
 
 (defn close-action-button []
diff --git a/src/cljs/rems/actions/decide.cljs b/src/cljs/rems/actions/decide.cljs
index 536b2d11b..8c54b32f6 100644
--- a/src/cljs/rems/actions/decide.cljs
+++ b/src/cljs/rems/actions/decide.cljs
@@ -24,11 +24,12 @@
                       :decision decision
                       :comment comment}
              :handler (flash-message/default-success-handler
+                       :top
                        description
                        (fn [_]
                          (collapse-action-form action-form-id)
                          (on-finished)))
-             :error-handler (flash-message/default-error-handler description)}))
+             :error-handler (flash-message/default-error-handler :top description)}))
    {}))
 
 (defn decide-action-button []
diff --git a/src/cljs/rems/actions/invite_member.cljs b/src/cljs/rems/actions/invite_member.cljs
index 3ebd55f0d..e723198eb 100644
--- a/src/cljs/rems/actions/invite_member.cljs
+++ b/src/cljs/rems/actions/invite_member.cljs
@@ -1,7 +1,7 @@
 (ns rems.actions.invite-member
   (:require [re-frame.core :as rf]
             [rems.actions.action :refer [action-button action-form-view button-wrapper collapse-action-form]]
-            [rems.atoms :as atoms]
+            [rems.flash-message :as flash-message]
             [rems.status-modal :as status-modal]
             [rems.text :refer [text]]
             [rems.util :refer [post!]]))
@@ -10,7 +10,6 @@
  ::open-form
  (fn [db _]
    (assoc db
-          ::done? false
           ::name ""
           ::email "")))
 
@@ -20,9 +19,6 @@
 (rf/reg-event-db ::set-email (fn [db [_ email]] (assoc db ::email email)))
 (rf/reg-sub ::email (fn [db _] (::email db)))
 
-(rf/reg-event-db ::set-done? (fn [db [_ done]] (assoc db ::done? done)))
-(rf/reg-sub ::done? (fn [db _] (::done? db)))
-
 (def ^:private action-form-id "invite-member")
 
 (defn- validate-member [{:keys [name email]}]
@@ -33,16 +29,19 @@
 (rf/reg-event-fx
  ::send-invite-member
  (fn [_ [_ {:keys [member application-id on-finished]}]]
-   (if-let [errors (validate-member member)]
-     (status-modal/set-error! {:result {:errors errors}})
-     (post! "/api/applications/invite-member"
-            {:params {:application-id application-id
-                      :member member}
-             :handler (fn [_]
-                        (collapse-action-form action-form-id)
-                        (rf/dispatch [::set-done? true])
-                        (on-finished))
-             :error-handler status-modal/common-error-handler!}))
+   (let [description (text :t.actions/invite-member)]
+     (if-let [errors (validate-member member)]
+       (flash-message/show-error! :invite-member-errors (status-modal/format-errors errors))
+       (post! "/api/applications/invite-member"
+              {:params {:application-id application-id
+                        :member member}
+               :handler (flash-message/default-success-handler
+                         :change-members
+                         description
+                         (fn [_]
+                           (collapse-action-form action-form-id)
+                           (on-finished)))
+               :error-handler (flash-message/default-error-handler :invite-member-errors description)})))
    {}))
 
 (defn invite-member-action-button []
@@ -51,25 +50,25 @@
                   :on-click #(rf/dispatch [::open-form])}])
 
 ;; TODO refactor to common input-field ?
-(defn input-field [{:keys [id label placeholder value type on-change normalizer]}]
-  (let [normalizer (or normalizer identity)]
-    [:div.form-group.field
-     [:label {:for id} label]
-     [:input.form-control {:type type
-                           :id id
-                           :placeholder placeholder
-                           :value value
-                           :on-change on-change}]]))
+(defn input-field [{:keys [id label placeholder value type on-change]}]
+  [:div.form-group.field
+   [:label {:for id} label]
+   [:input.form-control {:type type
+                         :id id
+                         :placeholder placeholder
+                         :value value
+                         :on-change on-change}]])
 
 (defn invite-member-view
-  [{:keys [name email done? on-send]}]
+  [{:keys [name email on-send]}]
   [action-form-view action-form-id
    (text :t.actions/invite-member)
    [[button-wrapper {:id "invite-member"
                      :text (text :t.actions/invite-member)
-                      :class "btn-primary"
+                     :class "btn-primary"
                      :on-click on-send}]]
    [:div
+    [flash-message/component :invite-member-errors]
     [input-field {:id "member-name"
                   :label (text :t.actions/member-name)
                   :value name
@@ -82,15 +81,9 @@
                   :on-change #(rf/dispatch [::set-email (.. % -target -value)])}]]
    {:collapse-id "member-action-forms"}])
 
-(defn invite-member-status []
-  (when @(rf/subscribe [::done?])
-    [atoms/flash-message {:status :success
-                          :contents (text :t.actions/member-invited)}]))
-
 (defn invite-member-form [application-id on-finished]
   (let [name @(rf/subscribe [::name])
-        email @(rf/subscribe [::email])
-        done? @(rf/subscribe [::done?])]
+        email @(rf/subscribe [::email])]
     [invite-member-view {:name name
                          :email email
                          :on-send #(rf/dispatch [::send-invite-member {:application-id application-id
diff --git a/src/cljs/rems/actions/remark.cljs b/src/cljs/rems/actions/remark.cljs
index 05154d9d1..c5e85dfeb 100644
--- a/src/cljs/rems/actions/remark.cljs
+++ b/src/cljs/rems/actions/remark.cljs
@@ -29,11 +29,12 @@
                       :comment (::comment db)
                       :public (::public db)}
              :handler (flash-message/default-success-handler
+                       :top
                        description
                        (fn [_]
                          (collapse-action-form action-form-id)
                          (on-finished)))
-             :error-handler (flash-message/default-error-handler description)}))
+             :error-handler (flash-message/default-error-handler :top description)}))
    {}))
 
 (defn remark-action-button []
diff --git a/src/cljs/rems/actions/remove_member.cljs b/src/cljs/rems/actions/remove_member.cljs
index 019b1c4e6..c431755db 100644
--- a/src/cljs/rems/actions/remove_member.cljs
+++ b/src/cljs/rems/actions/remove_member.cljs
@@ -33,11 +33,12 @@
                                 (select-keys member [:name :email]))
                       :comment comment}
              :handler (flash-message/default-success-handler
+                       :change-members
                        description
                        (fn [_]
                          (collapse-action-form collapse-id)
                          (on-finished)))
-             :error-handler (flash-message/default-error-handler description)}))
+             :error-handler (flash-message/default-error-handler :change-members description)}))
    {}))
 
 (defn remove-member-action-button [element-id]
diff --git a/src/cljs/rems/actions/request_decision.cljs b/src/cljs/rems/actions/request_decision.cljs
index ee9208f19..bc1cafcf7 100644
--- a/src/cljs/rems/actions/request_decision.cljs
+++ b/src/cljs/rems/actions/request_decision.cljs
@@ -47,11 +47,12 @@
                       :comment comment
                       :deciders (map :userid deciders)}
              :handler (flash-message/default-success-handler
+                       :top
                        description
                        (fn [_]
                          (collapse-action-form action-form-id)
                          (on-finished)))
-             :error-handler (flash-message/default-error-handler description)}))
+             :error-handler (flash-message/default-error-handler :top description)}))
    {}))
 
 (defn request-decision-action-button []
diff --git a/src/cljs/rems/actions/request_review.cljs b/src/cljs/rems/actions/request_review.cljs
index ac30fb64d..a832a6605 100644
--- a/src/cljs/rems/actions/request_review.cljs
+++ b/src/cljs/rems/actions/request_review.cljs
@@ -49,11 +49,12 @@
                       :comment comment
                       :commenters (map :userid reviewers)}
              :handler (flash-message/default-success-handler
+                       :top
                        description
                        (fn [_]
                          (collapse-action-form action-form-id)
                          (on-finished)))
-             :error-handler (flash-message/default-error-handler description)}))
+             :error-handler (flash-message/default-error-handler :top description)}))
    {}))
 
 (defn request-review-action-button []
diff --git a/src/cljs/rems/actions/return_action.cljs b/src/cljs/rems/actions/return_action.cljs
index becc9be73..475f9b28e 100644
--- a/src/cljs/rems/actions/return_action.cljs
+++ b/src/cljs/rems/actions/return_action.cljs
@@ -23,11 +23,12 @@
             {:params {:application-id application-id
                       :comment comment}
              :handler (flash-message/default-success-handler
+                       :top
                        description
                        (fn [_]
                          (collapse-action-form action-form-id)
                          (on-finished)))
-             :error-handler (flash-message/default-error-handler description)}))
+             :error-handler (flash-message/default-error-handler :top description)}))
    {}))
 
 (defn return-action-button []
diff --git a/src/cljs/rems/actions/review.cljs b/src/cljs/rems/actions/review.cljs
index 08b66837a..eeb32bda6 100644
--- a/src/cljs/rems/actions/review.cljs
+++ b/src/cljs/rems/actions/review.cljs
@@ -23,11 +23,12 @@
             {:params {:application-id application-id
                       :comment comment}
              :handler (flash-message/default-success-handler
+                       :top
                        description
                        (fn [_]
                          (collapse-action-form action-form-id)
                          (on-finished)))
-             :error-handler (flash-message/default-error-handler description)}))
+             :error-handler (flash-message/default-error-handler :top description)}))
    {}))
 
 (defn review-action-button []
diff --git a/src/cljs/rems/administration/catalogue_item.cljs b/src/cljs/rems/administration/catalogue_item.cljs
index 47818d59f..0efd1e173 100644
--- a/src/cljs/rems/administration/catalogue_item.cljs
+++ b/src/cljs/rems/administration/catalogue_item.cljs
@@ -90,7 +90,7 @@
       [:div
        [administration-navigator-container]
        [document-title (text :t.administration/catalogue-item)]
-       [flash-message/component]
+       [flash-message/component :top]
        (if @loading?
          [spinner/big]
          [catalogue-item-view @catalogue-item @language])])))
diff --git a/src/cljs/rems/administration/catalogue_items.cljs b/src/cljs/rems/administration/catalogue_items.cljs
index a5295c1ef..7debdb687 100644
--- a/src/cljs/rems/administration/catalogue_items.cljs
+++ b/src/cljs/rems/administration/catalogue_items.cljs
@@ -44,8 +44,9 @@
  (fn [_ [_ item description dispatch-on-finished]]
    (put! "/api/catalogue-items/archived"
          {:params (select-keys item [:id :archived])
-          :handler (flash-message/status-update-handler description #(rf/dispatch dispatch-on-finished))
-          :error-handler (flash-message/default-error-handler description)})
+          :handler (flash-message/status-update-handler
+                    :top description #(rf/dispatch dispatch-on-finished))
+          :error-handler (flash-message/default-error-handler :top description)})
    {}))
 
 (rf/reg-event-fx
@@ -53,8 +54,9 @@
  (fn [_ [_ item description dispatch-on-finished]]
    (put! "/api/catalogue-items/enabled"
          {:params (select-keys item [:id :enabled])
-          :handler (flash-message/status-update-handler description #(rf/dispatch dispatch-on-finished))
-          :error-handler (flash-message/default-error-handler description)})
+          :handler (flash-message/status-update-handler
+                    :top description #(rf/dispatch dispatch-on-finished))
+          :error-handler (flash-message/default-error-handler :top description)})
    {}))
 
 (rf/reg-event-fx
@@ -143,7 +145,7 @@
   (into [:div
          [administration-navigator-container]
          [document-title (text :t.administration/catalogue-items)]
-         [flash-message/component]]
+         [flash-message/component :top]]
         (if @(rf/subscribe [::loading?])
           [[spinner/big]]
           [[to-create-catalogue-item]
diff --git a/src/cljs/rems/administration/create_catalogue_item.cljs b/src/cljs/rems/administration/create_catalogue_item.cljs
index dc989d0ba..167b76413 100644
--- a/src/cljs/rems/administration/create_catalogue_item.cljs
+++ b/src/cljs/rems/administration/create_catalogue_item.cljs
@@ -87,11 +87,12 @@
                         ;; create disabled catalogue items by default
                         (assoc :enabled false))
             :handler (flash-message/default-success-handler
+                      :top
                       description
                       (fn [response]
                         (dispatch! (str "#/administration/catalogue-items/"
                                         (:id response)))))
-            :error-handler (flash-message/default-error-handler description)}))
+            :error-handler (flash-message/default-error-handler :top description)}))
   {})
 
 (defn- edit-catalogue-item! [{:keys [db]} [_ request]]
@@ -101,10 +102,11 @@
           {:params {:id id
                     :localizations (:localizations request)}
            :handler (flash-message/default-success-handler
+                     :top
                      description
                      (fn [_]
                        (dispatch! (str "#/administration/catalogue-items/" id))))
-           :error-handler (flash-message/default-error-handler description)}))
+           :error-handler (flash-message/default-error-handler :top description)}))
   {})
 
 (rf/reg-event-fx ::create-catalogue-item create-catalogue-item!)
@@ -276,7 +278,7 @@
     [:div
      [administration-navigator-container]
      [document-title (page-title editing?)]
-     [flash-message/component]
+     [flash-message/component :top]
      [collapsible/component
       {:id "create-catalogue-item"
        :title (page-title editing?)
diff --git a/src/cljs/rems/administration/create_form.cljs b/src/cljs/rems/administration/create_form.cljs
index a8724bb93..348ae81fd 100644
--- a/src/cljs/rems/administration/create_form.cljs
+++ b/src/cljs/rems/administration/create_form.cljs
@@ -183,13 +183,14 @@
        (send-verb send-url
                   {:params request
                    :handler (flash-message/default-success-handler
+                             :top
                              description
                              (fn [response]
                                (dispatch! (str "#/administration/forms/"
                                                (if edit?
                                                  (::form-id db)
                                                  (response :id))))))
-                   :error-handler (flash-message/default-error-handler description)}))
+                   :error-handler (flash-message/default-error-handler :top description)}))
      {:db (assoc db ::form-errors form-errors)})))
 
 ;;;; preview auto-scrolling
@@ -444,7 +445,7 @@
     [:div
      [administration-navigator-container]
      [document-title (page-title edit-form?)]
-     [flash-message/component]
+     [flash-message/component :top]
      (if loading-form?
        [:div [spinner/big]]
        [:div.container-fluid.editor-content
diff --git a/src/cljs/rems/administration/create_license.cljs b/src/cljs/rems/administration/create_license.cljs
index 4b33554dd..e1334c32a 100644
--- a/src/cljs/rems/administration/create_license.cljs
+++ b/src/cljs/rems/administration/create_license.cljs
@@ -63,8 +63,9 @@
    (let [description (text :t.administration/create-license)]
      (post! "/api/licenses/create"
             {:params request
-             :handler (flash-message/default-success-handler description #(dispatch! (str "#/administration/licenses/" (:id %))))
-             :error-handler (flash-message/default-error-handler description)}))
+             :handler (flash-message/default-success-handler
+                       :top description #(dispatch! (str "#/administration/licenses/" (:id %))))
+             :error-handler (flash-message/default-error-handler :top description)}))
    {}))
 
 (defn- save-attachment [language form-data]
@@ -200,7 +201,7 @@
     [:div
      [administration-navigator-container]
      [document-title (text :t.administration/create-license)]
-     [flash-message/component]
+     [flash-message/component :top]
      [collapsible/component
       {:id "create-license"
        :title (text :t.administration/create-license)
diff --git a/src/cljs/rems/administration/create_resource.cljs b/src/cljs/rems/administration/create_resource.cljs
index 577c2af38..5b30dec80 100644
--- a/src/cljs/rems/administration/create_resource.cljs
+++ b/src/cljs/rems/administration/create_resource.cljs
@@ -49,8 +49,9 @@
      (post! "/api/resources/create"
             {:params request
              ;; TODO: render the catalogue items that use this resource in the error handler
-             :handler (flash-message/default-success-handler description #(dispatch! (str "#/administration/resources/" (:id %))))
-             :error-handler (flash-message/default-error-handler description)}))
+             :handler (flash-message/default-success-handler
+                       :top description #(dispatch! (str "#/administration/resources/" (:id %))))
+             :error-handler (flash-message/default-error-handler :top description)}))
    {}))
 
 ;; available licenses
@@ -126,7 +127,7 @@
     [:div
      [administration-navigator-container]
      [document-title (text :t.administration/create-resource)]
-     [flash-message/component]
+     [flash-message/component :top]
      [collapsible/component
       {:id "create-resource"
        :title (text :t.administration/create-resource)
diff --git a/src/cljs/rems/administration/create_workflow.cljs b/src/cljs/rems/administration/create_workflow.cljs
index aaf19bde6..be73009da 100644
--- a/src/cljs/rems/administration/create_workflow.cljs
+++ b/src/cljs/rems/administration/create_workflow.cljs
@@ -89,8 +89,9 @@
    (let [description (text :t.administration/create-workflow)]
      (post! "/api/workflows/create"
             {:params request
-             :handler (flash-message/default-success-handler description #(dispatch! (str "#/administration/workflows/" (:id %))))
-             :error-handler (flash-message/default-error-handler description)}))
+             :handler (flash-message/default-success-handler
+                       :top description #(dispatch! (str "#/administration/workflows/" (:id %))))
+             :error-handler (flash-message/default-error-handler :top description)}))
    {}))
 
 (rf/reg-event-fx
@@ -99,8 +100,9 @@
    (let [description (text :t.administration/edit-workflow)]
      (put! "/api/workflows/edit"
            {:params request
-            :handler (flash-message/default-success-handler description #(dispatch! (str "#/administration/workflows/" (:id request))))
-            :error-handler (flash-message/default-error-handler description)}))
+            :handler (flash-message/default-success-handler
+                      :top description #(dispatch! (str "#/administration/workflows/" (:id request))))
+            :error-handler (flash-message/default-error-handler :top description)}))
    {}))
 
 (rf/reg-event-db ::set-handlers (fn [db [_ handlers]] (assoc-in db [::form :handlers] (sort-by :userid handlers))))
@@ -208,7 +210,7 @@
     [:div
      [administration-navigator-container]
      [document-title title]
-     [flash-message/component]
+     [flash-message/component :top]
      [collapsible/component
       {:id "create-workflow"
        :title title
diff --git a/src/cljs/rems/administration/form.cljs b/src/cljs/rems/administration/form.cljs
index 0e629ea37..3420e9a96 100644
--- a/src/cljs/rems/administration/form.cljs
+++ b/src/cljs/rems/administration/form.cljs
@@ -42,8 +42,9 @@
             {:handler (fn [response]
                         (if (:success response)
                           (dispatch! (str "/#/administration/edit-form/" id))
-                          (flash-message/show-default-error! description (status-flags/format-update-failure response))))
-             :error-handler (flash-message/default-error-handler description)}))
+                          (flash-message/show-default-error!
+                           :top description (status-flags/format-update-failure response))))
+             :error-handler (flash-message/default-error-handler :top description)}))
    {}))
 
 (defn- back-button []
@@ -92,7 +93,7 @@
       [:div
        [administration-navigator-container]
        [document-title (text :t.administration/form)]
-       [flash-message/component]
+       [flash-message/component :top]
        (if @loading?
          [spinner/big]
          [form-view @form])])))
diff --git a/src/cljs/rems/administration/forms.cljs b/src/cljs/rems/administration/forms.cljs
index aadc007bf..ea0d7c2b6 100644
--- a/src/cljs/rems/administration/forms.cljs
+++ b/src/cljs/rems/administration/forms.cljs
@@ -42,8 +42,9 @@
    (put! "/api/forms/archived"
          {:params {:id (:form/id form)
                    :archived (:archived form)}
-          :handler (flash-message/status-update-handler description #(rf/dispatch dispatch-on-finished))
-          :error-handler (flash-message/default-error-handler description)})
+          :handler (flash-message/status-update-handler
+                    :top description #(rf/dispatch dispatch-on-finished))
+          :error-handler (flash-message/default-error-handler :top description)})
    {}))
 
 (rf/reg-event-fx
@@ -52,8 +53,9 @@
    (put! "/api/forms/enabled"
          {:params {:id (:form/id form)
                    :enabled (:enabled form)}
-          :handler (flash-message/status-update-handler description #(rf/dispatch dispatch-on-finished))
-          :error-handler (flash-message/default-error-handler description)})
+          :handler (flash-message/status-update-handler
+                    :top description #(rf/dispatch dispatch-on-finished))
+          :error-handler (flash-message/default-error-handler :top description)})
    {}))
 
 (rf/reg-event-fx
@@ -127,7 +129,7 @@
   (into [:div
          [administration-navigator-container]
          [document-title (text :t.administration/forms)]
-         [flash-message/component]]
+         [flash-message/component :top]]
         (if @(rf/subscribe [::loading?])
           [[spinner/big]]
           [[to-create-form]
diff --git a/src/cljs/rems/administration/license.cljs b/src/cljs/rems/administration/license.cljs
index 07cc01711..024818601 100644
--- a/src/cljs/rems/administration/license.cljs
+++ b/src/cljs/rems/administration/license.cljs
@@ -130,7 +130,7 @@
       [:div
        [administration-navigator-container]
        [document-title (text :t.administration/license)]
-       [flash-message/component]
+       [flash-message/component :top]
        (if @loading?
          [spinner/big]
          [license-view @license @language])])))
diff --git a/src/cljs/rems/administration/licenses.cljs b/src/cljs/rems/administration/licenses.cljs
index 60679556f..e2a7e7e26 100644
--- a/src/cljs/rems/administration/licenses.cljs
+++ b/src/cljs/rems/administration/licenses.cljs
@@ -40,8 +40,9 @@
  (fn [_ [_ item description dispatch-on-finished]]
    (put! "/api/licenses/archived"
          {:params (select-keys item [:id :archived])
-          :handler (flash-message/status-update-handler description #(rf/dispatch dispatch-on-finished))
-          :error-handler (flash-message/default-error-handler description)})
+          :handler (flash-message/status-update-handler
+                    :top description #(rf/dispatch dispatch-on-finished))
+          :error-handler (flash-message/default-error-handler :top description)})
    {}))
 
 (rf/reg-event-fx
@@ -49,8 +50,9 @@
  (fn [_ [_ item description dispatch-on-finished]]
    (put! "/api/licenses/enabled"
          {:params (select-keys item [:id :enabled])
-          :handler (flash-message/status-update-handler description #(rf/dispatch dispatch-on-finished))
-          :error-handler (flash-message/default-error-handler description)})
+          :handler (flash-message/status-update-handler
+                    :top description #(rf/dispatch dispatch-on-finished))
+          :error-handler (flash-message/default-error-handler :top description)})
    {}))
 
 (rf/reg-event-fx
@@ -113,7 +115,7 @@
   (into [:div
          [administration-navigator-container]
          [document-title (text :t.administration/licenses)]
-         [flash-message/component]]
+         [flash-message/component :top]]
         (if @(rf/subscribe [::loading?])
           [[spinner/big]]
           [[to-create-license]
diff --git a/src/cljs/rems/administration/resource.cljs b/src/cljs/rems/administration/resource.cljs
index 63740adc1..2345f87b6 100644
--- a/src/cljs/rems/administration/resource.cljs
+++ b/src/cljs/rems/administration/resource.cljs
@@ -65,7 +65,7 @@
       [:div
        [administration-navigator-container]
        [document-title (text :t.administration/resource)]
-       [flash-message/component]
+       [flash-message/component :top]
        (if @loading?
          [spinner/big]
          [resource-view @resource @language])])))
diff --git a/src/cljs/rems/administration/resources.cljs b/src/cljs/rems/administration/resources.cljs
index 29065ceb4..b90a371a4 100644
--- a/src/cljs/rems/administration/resources.cljs
+++ b/src/cljs/rems/administration/resources.cljs
@@ -42,8 +42,9 @@
  (fn [_ [_ item description dispatch-on-finished]]
    (put! "/api/resources/archived"
          {:params (select-keys item [:id :archived])
-          :handler (flash-message/status-update-handler description #(rf/dispatch dispatch-on-finished))
-          :error-handler (flash-message/default-error-handler description)})
+          :handler (flash-message/status-update-handler
+                    :top description #(rf/dispatch dispatch-on-finished))
+          :error-handler (flash-message/default-error-handler :top description)})
    {}))
 
 (rf/reg-event-fx
@@ -51,8 +52,9 @@
  (fn [_ [_ item description dispatch-on-finished]]
    (put! "/api/resources/enabled"
          {:params (select-keys item [:id :enabled])
-          :handler (flash-message/status-update-handler description #(rf/dispatch dispatch-on-finished))
-          :error-handler (flash-message/default-error-handler description)})
+          :handler (flash-message/status-update-handler
+                    :top description #(rf/dispatch dispatch-on-finished))
+          :error-handler (flash-message/default-error-handler :top description)})
    {}))
 
 (rf/reg-event-fx
@@ -118,7 +120,7 @@
   (into [:div
          [administration-navigator-container]
          [document-title (text :t.administration/resources)]
-         [flash-message/component]]
+         [flash-message/component :top]]
         (if @(rf/subscribe [::loading?])
           [[spinner/big]]
           [[to-create-resource]
diff --git a/src/cljs/rems/administration/workflow.cljs b/src/cljs/rems/administration/workflow.cljs
index d11e46ee1..0244fb391 100644
--- a/src/cljs/rems/administration/workflow.cljs
+++ b/src/cljs/rems/administration/workflow.cljs
@@ -81,7 +81,7 @@
       [:div
        [administration-navigator-container]
        [document-title (text :t.administration/workflow)]
-       [flash-message/component]
+       [flash-message/component :top]
        (if @loading?
          [spinner/big]
          [workflow-view @workflow @language])])))
diff --git a/src/cljs/rems/administration/workflows.cljs b/src/cljs/rems/administration/workflows.cljs
index afacacec6..9433fafe5 100644
--- a/src/cljs/rems/administration/workflows.cljs
+++ b/src/cljs/rems/administration/workflows.cljs
@@ -41,8 +41,9 @@
  (fn [_ [_ item description dispatch-on-finished]]
    (put! "/api/workflows/archived"
          {:params (select-keys item [:id :archived])
-          :handler (flash-message/status-update-handler description #(rf/dispatch dispatch-on-finished))
-          :error-handler (flash-message/default-error-handler description)})
+          :handler (flash-message/status-update-handler
+                    :top description #(rf/dispatch dispatch-on-finished))
+          :error-handler (flash-message/default-error-handler :top description)})
    {}))
 
 (rf/reg-event-fx
@@ -50,8 +51,9 @@
  (fn [_ [_ item description dispatch-on-finished]]
    (put! "/api/workflows/enabled"
          {:params (select-keys item [:id :enabled])
-          :handler (flash-message/status-update-handler description #(rf/dispatch dispatch-on-finished))
-          :error-handler (flash-message/default-error-handler description)})
+          :handler (flash-message/status-update-handler
+                    :top description #(rf/dispatch dispatch-on-finished))
+          :error-handler (flash-message/default-error-handler :top description)})
    {}))
 
 (rf/reg-event-fx
@@ -119,7 +121,7 @@
   (into [:div
          [administration-navigator-container]
          [document-title (text :t.administration/workflows)]
-         [flash-message/component]]
+         [flash-message/component :top]]
         (if @(rf/subscribe [::loading?])
           [[spinner/big]]
           [[to-create-workflow]
diff --git a/src/cljs/rems/application.cljs b/src/cljs/rems/application.cljs
index ec287e07e..7c40d8f4a 100644
--- a/src/cljs/rems/application.cljs
+++ b/src/cljs/rems/application.cljs
@@ -7,12 +7,12 @@
             [rems.actions.accept-licenses :refer [accept-licenses-action-button]]
             [rems.actions.action :refer [action-button action-form-view action-comment action-collapse-id button-wrapper]]
             [rems.actions.add-licenses :refer [add-licenses-action-button add-licenses-form]]
-            [rems.actions.add-member :refer [add-member-action-button add-member-form add-member-status]]
+            [rems.actions.add-member :refer [add-member-action-button add-member-form]]
             [rems.actions.approve-reject :refer [approve-reject-action-button approve-reject-form]]
             [rems.actions.change-resources :refer [change-resources-action-button change-resources-form]]
             [rems.actions.close :refer [close-action-button close-form]]
             [rems.actions.decide :refer [decide-action-button decide-form]]
-            [rems.actions.invite-member :refer [invite-member-action-button invite-member-form invite-member-status]]
+            [rems.actions.invite-member :refer [invite-member-action-button invite-member-form]]
             [rems.actions.remark :refer [remark-action-button remark-form]]
             [rems.actions.remove-member :refer [remove-member-action-button remove-member-form]]
             [rems.actions.request-decision :refer [request-decision-action-button request-decision-form]]
@@ -142,10 +142,11 @@
          {:params {:application-id application-id
                    :field-values (field-values-to-api field-values)}
           :handler (flash-message/default-success-handler
+                    :top
                     description
                     (fn [_]
                       (rf/dispatch [::fetch-application application-id])))
-          :error-handler (flash-message/default-error-handler description)}))
+          :error-handler (flash-message/default-error-handler :top description)}))
 
 (rf/reg-event-fx
  ::save-application
@@ -166,10 +167,10 @@
           :handler (fn [response]
                      (cond
                        (not (:success response))
-                       (flash-message/show-default-error! description)
+                       (flash-message/show-default-error! :top description)
 
                        (not (accepted-licenses? application userid))
-                       (flash-message/show-error! (text :t.actions/licenses-not-accepted-error))
+                       (flash-message/show-error! :top (text :t.actions/licenses-not-accepted-error))
 
                        :else
                        (post! "/api/applications/submit"
@@ -178,12 +179,12 @@
                                           (if (:success response)
                                             (do
                                               (rf/dispatch [::fetch-application application-id])
-                                              (flash-message/show-default-success! description))
+                                              (flash-message/show-default-success! :top description))
                                             (do
                                               (rf/dispatch [::set-validation-errors (:errors response)])
-                                              (flash-message/show-error! [format-validation-errors application (:errors response)]))))
-                               :error-handler (flash-message/default-error-handler description)})))
-          :error-handler (flash-message/default-error-handler description)}))
+                                              (flash-message/show-error! :top [format-validation-errors application (:errors response)]))))
+                               :error-handler (flash-message/default-error-handler :top description)})))
+          :error-handler (flash-message/default-error-handler :top description)}))
 
 (rf/reg-event-fx
  ::submit-application
@@ -205,11 +206,12 @@
      (post! "/api/applications/copy-as-new"
             {:params {:application-id application-id}
              :handler (flash-message/default-success-handler
+                       :top
                        description
                        (fn [response]
                          (rf/dispatch [:rems.spa/user-triggered-navigation])
                          (dispatch! (str "/#/application/" (:application-id response)))))
-             :error-handler (flash-message/default-error-handler description)}))
+             :error-handler (flash-message/default-error-handler :top description)}))
    {}))
 
 (defn- save-attachment [{:keys [db]} [_ field-id file description]]
@@ -222,13 +224,14 @@
             ;; this ensures that the attachment is not left
             ;; dangling (with no references to it)
             :handler (flash-message/default-success-handler
+                      :top
                       description
                       (fn [response]
                         ;; no race condition here: events are handled in a FIFO manner
                         (rf/dispatch [::set-field-value field-id (str (:id response))])
                         (rf/dispatch [::set-attachment-success field-id])
                         (rf/dispatch [::save-application description])))
-            :error-handler (flash-message/default-error-handler description)})
+            :error-handler (flash-message/default-error-handler :top description)})
     {}))
 
 (rf/reg-event-fx ::save-attachment save-attachment)
@@ -363,6 +366,7 @@
         :title (text :t.form/licenses)
         :always
         [:div
+         [flash-message/component :accept-licenses]
          [:p (text :t.form/must-accept-licenses)]
          (into [:div#licenses]
                (for [license licenses]
@@ -573,6 +577,7 @@
       :title (text :t.applicant-info/applicants)
       :always
       (into [:div
+             [flash-message/component :change-members]
              [member-info {:element-id "applicant"
                            :attributes applicant
                            :application application
@@ -596,8 +601,6 @@
                              :group? true
                              :can-remove? can-uninvite?}])))
       :footer [:div
-               [invite-member-status]
-               [add-member-status]
                [:div.commands
                 (when can-invite? [invite-member-action-button])
                 (when can-add? [add-member-action-button])]
@@ -675,6 +678,7 @@
      {:id "resources"
       :title (text :t.form/resources)
       :always [:div.form-items.form-group
+               [flash-message/component :change-resources]
                (into [:div.application-resources]
                      (for [resource (:application/resources application)]
                        [render-resource resource]))]
@@ -691,7 +695,7 @@
    [:div.row
     [:div.col-lg-4.order-lg-last
      [:div#float-actions.mb-3
-      [flash-message/component]
+      [flash-message/component :top]
       [disabled-items-warning application]
       [actions-form application]]]
     [:div.col-lg-8
diff --git a/src/cljs/rems/atoms.cljs b/src/cljs/rems/atoms.cljs
index 084991fad..7bbae1ff0 100644
--- a/src/cljs/rems/atoms.cljs
+++ b/src/cljs/rems/atoms.cljs
@@ -51,11 +51,14 @@
 (defn flash-message
   "Displays a notification (aka flash) message.
 
+   :id - HTML element ID
    :status   - one of the alert types from Bootstrap i.e. :success, :info, :warning or :danger
    :contents - content to show inside the notification"
-  [{status :status contents :contents}]
+  [{:keys [id status contents]}]
   (when status
-    [:div#flash-message.alert {:class (str "alert-" (name status))} contents]))
+    [:div.alert {:class (str "alert-" (name status))
+                 :id id}
+     contents]))
 
 (defn readonly-checkbox
   "Displays a checkbox."
diff --git a/src/cljs/rems/flash_message.cljs b/src/cljs/rems/flash_message.cljs
index 4079f8b02..484331749 100644
--- a/src/cljs/rems/flash_message.cljs
+++ b/src/cljs/rems/flash_message.cljs
@@ -1,5 +1,6 @@
 (ns rems.flash-message
-  (:require [re-frame.core :as rf]
+  (:require [cljs.test :refer-macros [deftest is testing]]
+            [re-frame.core :as rf]
             [reagent.core :as reagent]
             [rems.administration.status-flags :as status-flags]
             [rems.atoms :as atoms]
@@ -20,24 +21,38 @@
   (let [expires (get message :expires 0)]
     (< expires (current-time-millis))))
 
+(defn- location-to-id [location]
+  (str "flash-message-"
+       (cond
+         (keyword? location) (name location)
+         (vector? location) (str (name (first location))
+                                 "-"
+                                 (second location)))))
+
+(deftest location-to-id-test
+  (is (= "flash-message-top" (location-to-id :top)))
+  (is (= "flash-message-attachment-10" (location-to-id [:attachment 10]))))
+
 (rf/reg-event-fx
  ::show-flash-message
  (fn [{:keys [db]} [_ message]]
-   (focus/focus-element-async "#flash-message")
+   (focus/focus-element-async (str "#" (location-to-id (:location message))))
    ;; TODO: flash the message with CSS
    {:db (assoc db ::message (assoc message :expires (+ 500 (current-time-millis))))}))
 
-(defn show-success! [contents]
+(defn show-success! [location contents]
   (rf/dispatch [::show-flash-message {:status :success
+                                      :location location
                                       :contents contents
                                       :page @(rf/subscribe [:page])}]))
 
-(defn show-error! [contents]
+(defn show-error! [location contents]
   (rf/dispatch [::show-flash-message {:status :danger
+                                      :location location
                                       :contents contents
                                       :page @(rf/subscribe [:page])}]))
 
-(defn component []
+(defn component [location]
   (reagent/create-class
    {:display-name "rems.flash-message/component"
 
@@ -50,37 +65,40 @@
     :reagent-render
     (fn []
       (let [message @(rf/subscribe [::message])]
-        [atoms/flash-message message]))}))
+        (when (= location (:location message))
+          [atoms/flash-message {:id (location-to-id (:location message))
+                                :status (:status message)
+                                :contents (:contents message)}])))}))
 
 ;;; Helpers for typical messages
 
-(defn show-default-success! [description]
-  (show-success! [:div#status-success.flash-message-title
-                  (str description ": " (text :t.form/success))]))
+(defn show-default-success! [location description]
+  (show-success! location [:div#status-success.flash-message-title
+                           (str description ": " (text :t.form/success))]))
 
-(defn show-default-error! [description & more]
-  (show-error! (into [:<> [:div#status-failed.flash-message-title
-                           (str description ": " (text :t.form/failed))]]
-                     more)))
+(defn show-default-error! [location description & more]
+  (show-error! location (into [:<> [:div#status-failed.flash-message-title
+                                    (str description ": " (text :t.form/failed))]]
+                              more)))
 
-(defn default-success-handler [description on-success]
+(defn default-success-handler [location description on-success]
   (fn [response]
     (if (:success response)
       (do
-        (show-default-success! description)
+        (show-default-success! location description)
         (when on-success
           (on-success response)))
-      (show-default-error! description))))
+      (show-default-error! location description))))
 
-(defn status-update-handler [description on-success]
+(defn status-update-handler [location description on-success]
   (fn [response]
     (if (:success response)
       (do
-        (show-default-success! description)
+        (show-default-success! location description)
         (when on-success
           (on-success response)))
-      (show-default-error! description (status-flags/format-update-failure response)))))
+      (show-default-error! location description (status-flags/format-update-failure response)))))
 
-(defn default-error-handler [description]
+(defn default-error-handler [location description]
   (fn [response]
-    (show-default-error! description (:status-text response))))
+    (show-default-error! location description (:status-text response))))
diff --git a/src/cljs/rems/focus.cljs b/src/cljs/rems/focus.cljs
index f668e600e..9cf1185d4 100644
--- a/src/cljs/rems/focus.cljs
+++ b/src/cljs/rems/focus.cljs
@@ -2,20 +2,27 @@
   "Focuses an HTML element as soon as it exists."
   (:require [rems.util :refer [visibility-ratio]]))
 
+(defn- scroll-below-navigation-menu
+  "Scrolls an element into view if it's behind the navigation menu."
+  [element]
+  (when-let [navbar (.querySelector js/document ".fixed-top")]
+    (let [navbar-height (.-height (.getBoundingClientRect navbar))
+          element-top (.-top (.getBoundingClientRect element))]
+      (when (< element-top navbar-height)
+        (.scrollBy js/window 0 (- element-top navbar-height))))))
+
 (defn focus-element-async
-  "Focus an element when it appears. Options can include:
-    :tries -- number of times to poll, defaults to 100"
-  [selector & [options]]
-  (let [tries (get options :tries 100)]
-    (when (pos? tries)
-      (if-let [element (.querySelector js/document selector)]
-        (do
-          (.setAttribute element "tabindex" "-1")
-          ;; Focusing the element scrolls it into the viewport, but
-          ;; it's hidden behind the navigation menu,
-          ;; so explicit scrolling is needed. There used to be code
-          ;; for this, but most pages perform a scroll to top
-          ;; anyway (e.g. via ::rems.spa/user-triggered-navigation).
-          (.focus element))
-        (js/setTimeout #(focus-element-async selector (assoc options :tries (dec tries)))
-                       10)))))
+  "Focus an element when it appears."
+  ([selector]
+   (focus-element-async selector 100))
+  ([selector tries]
+   (when (pos? tries)
+     (if-let [element (.querySelector js/document selector)]
+       (do
+         (.setAttribute element "tabindex" "-1")
+         ;; Focusing the element scrolls it into the viewport, but
+         ;; it can still be hidden behind the navigation menu.
+         (.focus element)
+         (scroll-below-navigation-menu element))
+       (js/setTimeout #(focus-element-async selector (dec tries))
+                      10)))))


Test patch:
diff --git a/test/clj/rems/poller/test_email.clj b/test/clj/rems/poller/test_email.clj
index daa6ad993..8716f2829 100644
--- a/test/clj/rems/poller/test_email.clj
+++ b/test/clj/rems/poller/test_email.clj
@@ -67,11 +67,6 @@
                               :field/optional false
                               :field/type :description}]}))
 
-(def ^:private get-license
-  (constantly {:id 1234
-               :licensetype "text"
-               :textcontent "foobar"}))
-
 (defn ^:private get-nothing [& _]
   nil)
 
@@ -86,7 +81,7 @@
                         (model/enrich-with-injections {:get-workflow get-workflow
                                                        :get-catalogue-item get-catalogue-item
                                                        :get-form-template get-form-template
-                                                       :get-license get-license
+                                                       :get-license get-nothing
                                                        :get-user get-nothing
                                                        :get-users-with-role get-nothing
                                                        :get-attachments-for-application get-nothing}))]
@@ -111,8 +106,7 @@
                       :application/field-values {1 "Application title"}}
                      {:application/id 7
                       :event/type :application.event/submitted
-                      :event/actor "applicant"
-                      :event/time 13}]]
+                      :event/actor "applicant"}]]
     (let [events (into
                   base-events
                   [{:application/id 7
@@ -132,19 +126,11 @@
                     :event/type :application.event/commented
                     :event/actor "commenter2"
                     :application/request-id "r1"
-                    :application/comment "this is a comment"}
-                   {:application/id 7
-                    :event/type :application.event/remarked
-                    :event/actor "remarker"
-                    :application/comment "remark!"}
+                    :application/comment ["this is a comment"]}
                    {:application/id 7
                     :event/type :application.event/member-added
                     :event/actor "handler"
                     :application/member {:userid "member"}}
-                   {:application/id 7
-                    :event/type :application.event/licenses-added
-                    :event/actor "handler"
-                    :application/licenses [{:license/id 1234}]}
                    {:application/id 7
                     :event/type :application.event/decision-requested
                     :event/actor "assistant"
@@ -162,79 +148,64 @@
                     :event/actor "assistant"}])]
       (is (= [[]
               []
-              [{:to-user "assistant"
-                :subject "A new application has been submitted (2001/3, \"Application title\")"
-                :body "Dear assistant,\n\nAlice Applicant has submitted a new application 2001/3, \"Application title\" to access resource(s) en title 11, en title 21.\n\nYou can view the application: http://example.com/#/application/7\n\nPlease do not reply to this automatically generated message."}
-               {:to-user "handler"
-                :subject "A new application has been submitted (2001/3, \"Application title\")"
-                :body "Dear Hannah Handler,\n\nAlice Applicant has submitted a new application 2001/3, \"Application title\" to access resource(s) en title 11, en title 21.\n\nYou can view the application: http://example.com/#/application/7\n\nPlease do not reply to this automatically generated message."}]
+              [{:to-user "assistant",
+                :subject "Application submitted (Alice Applicant: 2001/3, \"Application title\")",
+                :body "Dear assistant,\n\nAlice Applicant has submitted an application (2001/3, \"Application title\"): en title 11, en title 21.\n\nView application: http://example.com/#/application/7\n\nPlease don't reply to this automatically generated message."}
+               {:to-user "handler",
+                :subject "Application submitted (Alice Applicant: 2001/3, \"Application title\")",
+                :body "Dear Hannah Handler,\n\nAlice Applicant has submitted an application (2001/3, \"Application title\"): en title 11, en title 21.\n\nView application: http://example.com/#/application/7\n\nPlease don't reply to this automatically generated message."}]
               [{:to "somebody@example.com",
                 :subject "Invitation to participate in an application",
-                :body "Dear Some Body,\n\nYou have been invited to participate in an application submitted by Alice Applicant. The title of the application is 2001/3, \"Application title\".\n\nYou can view the application and accept the terms of use: http://example.com/accept-invitation?token=abc\n\nPlease do not reply to this automatically generated message."}]
-              [{:to-user "commenter1"
-                :subject "Review request (2001/3, \"Application title\")"
-                :body "Dear commenter1,\n\nHannah Handler has requested your review on application 2001/3, \"Application title\" submitted by Alice Applicant.\n\nYou can review the application: http://example.com/#/application/7\n\nPlease do not reply to this automatically generated message."}
-               {:to-user "commenter2"
-                :subject "Review request (2001/3, \"Application title\")"
-                :body "Dear commenter2,\n\nHannah Handler has requested your review on application 2001/3, \"Application title\" submitted by Alice Applicant.\n\nYou can review the application: http://example.com/#/application/7\n\nPlease do not reply to this automatically generated message."}]
+                :body "Hello,\n\nThis email address (somebody@example.com) has been invited to participate in an application.\n\nParticipate: http://example.com/accept-invitation?token=abc\n\nPlease don't reply to this automatically generated message."}]
+              [{:to-user "commenter1",
+                :subject "Review requested (Hannah Handler: 2001/3, \"Application title\")",
+                :body "Dear commenter1,\n\nHannah Handler has requested a review on application 2001/3, \"Application title\".\n\nComment: http://example.com/#/application/7\n\nPlease don't reply to this automatically generated message."}
+               {:to-user "commenter2",
+                :subject "Review requested (Hannah Handler: 2001/3, \"Application title\")",
+                :body "Dear commenter2,\n\nHannah Handler has requested a review on application 2001/3, \"Application title\".\n\nComment: http://example.com/#/application/7\n\nPlease don't reply to this automatically generated message."}]
               []
-              [{:to-user "assistant"
-                :subject "Application has been reviewed (2001/3, \"Application title\")"
-                :body "Dear assistant,\n\ncommenter2 has reviewed the application 2001/3, \"Application title\" submitted by Alice Applicant.\n\nYou can view the application and the review: http://example.com/#/application/7\n\nPlease do not reply to this automatically generated message."}
-               {:to-user "handler"
-                :subject "Application has been reviewed (2001/3, \"Application title\")"
-                :body "Dear Hannah Handler,\n\ncommenter2 has reviewed the application 2001/3, \"Application title\" submitted by Alice Applicant.\n\nYou can view the application and the review: http://example.com/#/application/7\n\nPlease do not reply to this automatically generated message."}]
-              [{:to-user "assistant"
-                :subject "Application has been commented on (2001/3, \"Application title\")"
-                :body "Dear assistant,\n\nremarker has commented on the application 2001/3, \"Application title\" submitted by Alice Applicant.\n\nYou can view the application and the comment: http://example.com/#/application/7\n\nPlease do not reply to this automatically generated message."}
-               {:to-user "handler"
-                :subject "Application has been commented on (2001/3, \"Application title\")"
-                :body "Dear Hannah Handler,\n\nremarker has commented on the application 2001/3, \"Application title\" submitted by Alice Applicant.\n\nYou can view the application and the comment: http://example.com/#/application/7\n\nPlease do not reply to this automatically generated message."}]
+              [{:to-user "assistant",
+                :subject "Review added (commenter2: 2001/3, \"Application title\")",
+                :body "Dear assistant,\n\ncommenter2 has reviewed application 2001/3, \"Application title\".\n\nView application: http://example.com/#/application/7\n\nPlease don't reply to this automatically generated message."}
+               {:to-user "handler",
+                :subject "Review added (commenter2: 2001/3, \"Application title\")",
+                :body "Dear Hannah Handler,\n\ncommenter2 has reviewed application 2001/3, \"Application title\".\n\nView application: http://example.com/#/application/7\n\nPlease don't reply to this automatically generated message."}]
               [{:to-user "member",
                 :subject "Added as a member of an application (2001/3, \"Application title\")",
-                :body "Dear member,\n\nYou've been added as a member of application 2001/3, \"Application title\".\n\nView application: http://example.com/#/application/7\n\nPlease do not reply to this automatically generated message."}]
-              [{:to-user "applicant"
-                :subject "New terms of use waiting for approval (2001/3, \"Application title\")"
-                :body "Dear Alice Applicant,\n\nHannah Handler has requested your acceptance for new terms of use for application 2001/3, \"Application title\".\n\nYou can view the application and accept the terms of use: http://example.com/#/application/7\n\nPlease do not reply to this automatically generated message."}
-               {:to-user "member"
-                :subject "New terms of use waiting for approval (2001/3, \"Application title\")"
-                :body "Dear member,\n\nHannah Handler has requested your acceptance for new terms of use for application 2001/3, \"Application title\".\n\nYou can view the application and accept the terms of use: http://example.com/#/application/7\n\nPlease do not reply to this automatically generated message."}
-               {:to-user "somebody"
-                :subject "New terms of use waiting for approval (2001/3, \"Application title\")"
-                :body "Dear somebody,\n\nHannah Handler has requested your acceptance for new terms of use for application 2001/3, \"Application title\".\n\nYou can view the application and accept the terms of use: http://example.com/#/application/7\n\nPlease do not reply to this automatically generated message."}]
+                :body "Dear member,\n\nYou've been added as a member of application 2001/3, \"Application title\".\n\nView application: http://example.com/#/application/7\n\nPlease don't reply to this automatically generated message."}]
               [{:to-user "decider",
-                :subject "Decision requested (2001/3, \"Application title\")",
-                :body "Dear decider,\n\nassistant has requested your decision on application 2001/3, \"Application title\" submitted by Alice Applicant.\n\nYou can view application: http://example.com/#/application/7\n\nPlease do not reply to this automatically generated message."}]
+                :subject "Decision requested (assistant: 2001/3, \"Application title\")",
+                :body "Dear decider,\n\nassistant has requested your decision on application 2001/3, \"Application title\".\n\nView application: http://example.com/#/application/7\n\nPlease don't reply to this automatically generated message."}]
               [{:to-user "assistant",
-                :subject "Decision notification (2001/3, \"Application title\")",
-                :body "Dear assistant,\n\ndecider has sent a decision on application 2001/3, \"Application title\" submitted by Alice Applicant.\n\nYou can view the application and the decision: http://example.com/#/application/7\n\nPlease do not reply to this automatically generated message."}
+                :subject "Decision made (decider: 2001/3, \"Application title\")",
+                :body "Dear assistant,\n\ndecider has made a decision on application 2001/3, \"Application title\".\n\nView application: http://example.com/#/application/7\n\nPlease don't reply to this automatically generated message."}
                {:to-user "handler",
-                :subject "Decision notification (2001/3, \"Application title\")",
-                :body "Dear Hannah Handler,\n\ndecider has sent a decision on application 2001/3, \"Application title\" submitted by Alice Applicant.\n\nYou can view the application and the decision: http://example.com/#/application/7\n\nPlease do not reply to this automatically generated message."}]
+                :subject "Decision made (decider: 2001/3, \"Application title\")",
+                :body "Dear Hannah Handler,\n\ndecider has made a decision on application 2001/3, \"Application title\".\n\nView application: http://example.com/#/application/7\n\nPlease don't reply to this automatically generated message."}]
               [{:to-user "applicant"
-                :subject "Your application has been approved (2001/3, \"Application title\")"
-                :body "Dear Alice Applicant,\n\nYour application 2001/3, \"Application title\" has been approved.\n\nYou can view the application and the decision: http://example.com/#/application/7\n\nPlease do not reply to this automatically generated message."}
+                :subject "Application approved (2001/3, \"Application title\")",
+                :body "Dear Alice Applicant,\n\nYour application 2001/3, \"Application title\" has been approved.\n\nView application: http://example.com/#/application/7\n\nPlease don't reply to this automatically generated message."}
                {:to-user "assistant"
                 :subject "Application approved (2001/3, \"Application title\")"
-                :body "Dear assistant,\n\nHannah Handler has approved the application 2001/3, \"Application title\" from Alice Applicant.\n\nYou can view the application and the decision: http://example.com/#/application/7\n\nPlease do not reply to this automatically generated message."}
-               {:to-user "member"
-                :subject "Your application has been approved (2001/3, \"Application title\")"
-                :body "Dear member,\n\nYour application 2001/3, \"Application title\" has been approved.\n\nYou can view the application and the decision: http://example.com/#/application/7\n\nPlease do not reply to this automatically generated message."}
-               {:to-user "somebody"
-                :subject "Your application has been approved (2001/3, \"Application title\")"
-                :body "Dear somebody,\n\nYour application 2001/3, \"Application title\" has been approved.\n\nYou can view the application and the decision: http://example.com/#/application/7\n\nPlease do not reply to this automatically generated message."}]
+                :body "Dear assistant,\n\nHannah Handler has approved the application 2001/3, \"Application title\" from Alice Applicant.\n\nView application: http://example.com/#/application/7\n\nPlease don't reply to this automatically generated message."}
+               {:to-user "member",
+                :subject "Application approved (2001/3, \"Application title\")",
+                :body "Dear member,\n\nYour application 2001/3, \"Application title\" has been approved.\n\nView application: http://example.com/#/application/7\n\nPlease don't reply to this automatically generated message."}
+               {:to-user "somebody",
+                :subject "Application approved (2001/3, \"Application title\")",
+                :body "Dear somebody,\n\nYour application 2001/3, \"Application title\" has been approved.\n\nView application: http://example.com/#/application/7\n\nPlease don't reply to this automatically generated message."}]
               [{:to-user "applicant"
-                :subject "Your application has been closed (2001/3, \"Application title\")"
-                :body "Dear Alice Applicant,\n\nYour application 2001/3, \"Application title\" has been closed.\n\nYou can view the application: http://example.com/#/application/7\n\nPlease do not reply to this automatically generated message."}
+                :subject "Application closed (2001/3, \"Application title\")",
+                :body "Dear Alice Applicant,\n\nYour application 2001/3, \"Application title\" has been closed.\n\nView application: http://example.com/#/application/7\n\nPlease don't reply to this automatically generated message."}
                {:to-user "handler"
                 :subject "Application closed (2001/3, \"Application title\")"
-                :body "Dear Hannah Handler,\n\nassistant has closed the application 2001/3, \"Application title\" from Alice Applicant.\n\nYou can view the application: http://example.com/#/application/7\n\nPlease do not reply to this automatically generated message."}
-               {:to-user "member"
-                :subject "Your application has been closed (2001/3, \"Application title\")"
-                :body "Dear member,\n\nYour application 2001/3, \"Application title\" has been closed.\n\nYou can view the application: http://example.com/#/application/7\n\nPlease do not reply to this automatically generated message."}
-               {:to-user "somebody"
-                :subject "Your application has been closed (2001/3, \"Application title\")"
-                :body "Dear somebody,\n\nYour application 2001/3, \"Application title\" has been closed.\n\nYou can view the application: http://example.com/#/application/7\n\nPlease do not reply to this automatically generated message."}]]
+                :body "Dear Hannah Handler,\n\nassistant has closed the application 2001/3, \"Application title\" from Alice Applicant.\n\nView application: http://example.com/#/application/7\n\nPlease don't reply to this automatically generated message."}
+               {:to-user "member",
+                :subject "Application closed (2001/3, \"Application title\")",
+                :body "Dear member,\n\nYour application 2001/3, \"Application title\" has been closed.\n\nView application: http://example.com/#/application/7\n\nPlease don't reply to this automatically generated message."}
+               {:to-user "somebody",
+                :subject "Application closed (2001/3, \"Application title\")",
+                :body "Dear somebody,\n\nYour application 2001/3, \"Application title\" has been closed.\n\nView application: http://example.com/#/application/7\n\nPlease don't reply to this automatically generated message."}]]
              (events-to-emails events))))
     (testing "application rejected"
       (let [events (conj base-events
@@ -243,38 +214,38 @@
                           :event/actor "handler"})]
         (is (= [[]
                 []
-                [{:to-user "assistant"
-                  :subject "A new application has been submitted (2001/3, \"Application title\")"
-                  :body "Dear assistant,\n\nAlice Applicant has submitted a new application 2001/3, \"Application title\" to access resource(s) en title 11, en title 21.\n\nYou can view the application: http://example.com/#/application/7\n\nPlease do not reply to this automatically generated message."}
-                 {:to-user "handler"
-                  :subject "A new application has been submitted (2001/3, \"Application title\")"
-                  :body "Dear Hannah Handler,\n\nAlice Applicant has submitted a new application 2001/3, \"Application title\" to access resource(s) en title 11, en title 21.\n\nYou can view the application: http://example.com/#/application/7\n\nPlease do not reply to this automatically generated message."}]
-                [{:to-user "applicant"
-                  :subject "Your application has been rejected (2001/3, \"Application title\")",
-                  :body "Dear Alice Applicant,\n\nYour application 2001/3, \"Application title\" has been rejected.\n\nYou can view the application and the decision: http://example.com/#/application/7\n\nPlease do not reply to this automatically generated message."}
-                 {:to-user "assistant"
-                  :subject "Application rejected (2001/3, \"Application title\")",
-                  :body "Dear assistant,\n\nHannah Handler has rejected the application 2001/3, \"Application title\" from Alice Applicant.\n\nYou can view the application and the decision: http://example.com/#/application/7\n\nPlease do not reply to this automatically generated message."}]]
+                [{:to-user "assistant",
+                  :subject "Application submitted (Alice Applicant: 2001/3, \"Application title\")",
+                  :body "Dear assistant,\n\nAlice Applicant has submitted an application (2001/3, \"Application title\"): en title 11, en title 21.\n\nView application: http://example.com/#/application/7\n\nPlease don't reply to this automatically generated message."}
+                 {:to-user "handler",
+                  :subject "Application submitted (Alice Applicant: 2001/3, \"Application title\")",
+                  :body "Dear Hannah Handler,\n\nAlice Applicant has submitted an application (2001/3, \"Application title\"): en title 11, en title 21.\n\nView application: http://example.com/#/application/7\n\nPlease don't reply to this automatically generated message."}]
+                [{:subject "Application rejected (2001/3, \"Application title\")",
+                  :body "Dear Alice Applicant,\n\nYour application 2001/3, \"Application title\" has been rejected.\n\nView application: http://example.com/#/application/7\n\nPlease don't reply to this automatically generated message.",
+                  :to-user "applicant"}
+                 {:subject "Application rejected (2001/3, \"Application title\")"
+                  :body "Dear assistant,\n\nHannah Handler has rejected the application 2001/3, \"Application title\" from Alice Applicant.\n\nView application: http://example.com/#/application/7\n\nPlease don't reply to this automatically generated message."
+                  :to-user "assistant"}]]
                (events-to-emails events)))))
     (testing "id field can be overrided"
       (with-redefs [rems.config/env (assoc rems.config/env :application-id-column :id)]
         (is (= [[]
                 []
                 [{:to-user "assistant"
-                  :subject "A new application has been submitted (7, \"Application title\")"
-                  :body "Dear assistant,\n\nAlice Applicant has submitted a new application 7, \"Application title\" to access resource(s) en title 11, en title 21.\n\nYou can view the application: http://example.com/#/application/7\n\nPlease do not reply to this automatically generated message."}
+                  :subject "Application submitted (Alice Applicant: 7, \"Application title\")"
+                  :body "Dear assistant,\n\nAlice Applicant has submitted an application (7, \"Application title\"): en title 11, en title 21.\n\nView application: http://example.com/#/application/7\n\nPlease don't reply to this automatically generated message."}
                  {:to-user "handler"
-                  :subject "A new application has been submitted (7, \"Application title\")"
-                  :body "Dear Hannah Handler,\n\nAlice Applicant has submitted a new application 7, \"Application title\" to access resource(s) en title 11, en title 21.\n\nYou can view the application: http://example.com/#/application/7\n\nPlease do not reply to this automatically generated message."}]]
+                  :subject "Application submitted (Alice Applicant: 7, \"Application title\")"
+                  :body "Dear Hannah Handler,\n\nAlice Applicant has submitted an application (7, \"Application title\"): en title 11, en title 21.\n\nView application: http://example.com/#/application/7\n\nPlease don't reply to this automatically generated message."}]]
                (events-to-emails base-events)))))
     (testing "application title is optional"
       (is (= [[]
-              [{:to-user "assistant"
-                :subject "A new application has been submitted (2001/3)"
-                :body "Dear assistant,\n\nAlice Applicant has submitted a new application 2001/3 to access resource(s) en title 11.\n\nYou can view the application: http://example.com/#/application/7\n\nPlease do not reply to this automatically generated message."}
-               {:to-user "handler"
-                :subject "A new application has been submitted (2001/3)"
-                :body "Dear Hannah Handler,\n\nAlice Applicant has submitted a new application 2001/3 to access resource(s) en title 11.\n\nYou can view the application: http://example.com/#/application/7\n\nPlease do not reply to this automatically generated message."}]]
+              [{:to-user "assistant",
+                :subject "Application submitted (Alice Applicant: 2001/3)",
+                :body "Dear assistant,\n\nAlice Applicant has submitted an application (2001/3): en title 11.\n\nView application: http://example.com/#/application/7\n\nPlease don't reply to this automatically generated message."}
+               {:to-user "handler",
+                :subject "Application submitted (Alice Applicant: 2001/3)",
+                :body "Dear Hannah Handler,\n\nAlice Applicant has submitted an application (2001/3): en title 11.\n\nView application: http://example.com/#/application/7\n\nPlease don't reply to this automatically generated message."}]]
              (events-to-emails [{:application/id 7
                                  :application/external-id "2001/3"
                                  :event/type :application.event/created
@@ -286,7 +257,7 @@
                                 {:application/id 7
                                  :event/type :application.event/submitted
                                  :event/actor "applicant"}]))))
-    (testing "returning application to applicant and resubmitting"
+    (testing "returning application to applicant and re-submitting"
       (let [events (conj base-events
                          {:application/id 7
                           :event/type :application.event/returned
@@ -297,22 +268,22 @@
                           :event/actor "applicant"})]
         (is (= [[]
                 []
-                [{:to-user "assistant"
-                  :subject "A new application has been submitted (2001/3, \"Application title\")"
-                  :body "Dear assistant,\n\nAlice Applicant has submitted a new application 2001/3, \"Application title\" to access resource(s) en title 11, en title 21.\n\nYou can view the application: http://example.com/#/application/7\n\nPlease do not reply to this automatically generated message."}
-                 {:to-user "handler"
-                  :subject "A new application has been submitted (2001/3, \"Application title\")"
-                  :body "Dear Hannah Handler,\n\nAlice Applicant has submitted a new application 2001/3, \"Application title\" to access resource(s) en title 11, en title 21.\n\nYou can view the application: http://example.com/#/application/7\n\nPlease do not reply to this automatically generated message."}]
-                [{:to-user "applicant"
-                  :subject "Your application has been returned for modifications (2001/3, \"Application title\")"
-                  :body "Dear Alice Applicant,\n\nYour application 2001/3, \"Application title\" has been returned to you for modifications.\n\nYou can modify and resubmit the application: http://example.com/#/application/7\n\nPlease do not reply to this automatically generated message."}
-                 {:to-user "assistant"
-                  :subject "Application has been returned for modifications (2001/3, \"Application title\")"
-                  :body "Dear assistant,\n\nHannah Handler has returned the application 2001/3, \"Application title\" to the applicant Alice Applicant for modifications.\n\nYou can view the application: http://example.com/#/application/7\n\nPlease do not reply to this automatically generated message."}]
-                [{:to-user "assistant"
-                  :subject "Application has been resubmitted (2001/3, \"Application title\")"
-                  :body "Dear assistant,\n\nApplication 2001/3, \"Application title\" has been resubmitted by Alice Applicant.\n\nYou can view the application: http://example.com/#/application/7\n\nPlease do not reply to this automatically generated message."}
-                 {:to-user "handler"
-                  :subject "Application has been resubmitted (2001/3, \"Application title\")"
-                  :body "Dear Hannah Handler,\n\nApplication 2001/3, \"Application title\" has been resubmitted by Alice Applicant.\n\nYou can view the application: http://example.com/#/application/7\n\nPlease do not reply to this automatically generated message."}]]
+                [{:to-user "assistant",
+                  :subject "Application submitted (Alice Applicant: 2001/3, \"Application title\")",
+                  :body "Dear assistant,\n\nAlice Applicant has submitted an application (2001/3, \"Application title\"): en title 11, en title 21.\n\nView application: http://example.com/#/application/7\n\nPlease don't reply to this automatically generated message."}
+                 {:to-user "handler",
+                  :subject "Application submitted (Alice Applicant: 2001/3, \"Application title\")",
+                  :body "Dear Hannah Handler,\n\nAlice Applicant has submitted an application (2001/3, \"Application title\"): en title 11, en title 21.\n\nView application: http://example.com/#/application/7\n\nPlease don't reply to this automatically generated message."}]
+                [{:to-user "applicant",
+                  :subject "Application returned (2001/3, \"Application title\")",
+                  :body "Dear Alice Applicant,\n\nYour application 2001/3, \"Application title\" has been returned.\n\nView application: http://example.com/#/application/7\n\nPlease don't reply to this automatically generated message."}
+                 {:to-user "assistant",
+                  :subject "Application returned (2001/3, \"Application title\")",
+                  :body "Dear assistant,\n\nHannah Handler has returned the application 2001/3, \"Application title\" from Alice Applicant.\n\nView application: http://example.com/#/application/7\n\nPlease don't reply to this automatically generated message."}]
+                [{:to-user "assistant",
+                  :subject "Application submitted (Alice Applicant: 2001/3, \"Application title\")",
+                  :body "Dear assistant,\n\nAlice Applicant has submitted an application (2001/3, \"Application title\"): en title 11, en title 21.\n\nView application: http://example.com/#/application/7\n\nPlease don't reply to this automatically generated message."}
+                 {:to-user "handler",
+                  :subject "Application submitted (Alice Applicant: 2001/3, \"Application title\")",
+                  :body "Dear Hannah Handler,\n\nAlice Applicant has submitted an application (2001/3, \"Application title\"): en title 11, en title 21.\n\nView application: http://example.com/#/application/7\n\nPlease don't reply to this automatically generated message."}]]
                (events-to-emails events)))))))
diff --git a/test/cljs/rems/cljs_tests.cljs b/test/cljs/rems/cljs_tests.cljs
index 3d97ee9d5..7b28745b3 100644
--- a/test/cljs/rems/cljs_tests.cljs
+++ b/test/cljs/rems/cljs_tests.cljs
@@ -6,6 +6,7 @@
             rems.administration.test-create-resource
             rems.administration.test-create-workflow
             rems.administration.test-items
+            rems.flash-message
             rems.test-fields
             rems.test-table
             rems.test-util))
@@ -16,6 +17,7 @@
            'rems.administration.test-create-resource
            'rems.administration.test-create-workflow
            'rems.administration.test-items
+           'rems.flash-message
            'rems.test-fields
            'rems.test-table
            'rems.test-util)