Repository: CSCfi/rems
Pull request #1387 (2019-06-28 08:34:33)

Fix incorrect Finnish translation


Patch:
diff --git a/.circleci/config.yml b/.circleci/config.yml
index e7688cc81..2395b1f20 100644
--- a/.circleci/config.yml
+++ b/.circleci/config.yml
@@ -61,7 +61,6 @@ jobs:
           - v2-dependencies-{{ checksum "project.clj" }}
       - run: sudo apt remove google-chrome-stable
       - run: sudo rm /usr/local/bin/chromedriver
-      - run: sudo apt update
       - run: sudo apt install chromium-chromedriver
       - run: FOR_TESTS=1 ./dev_db.sh
       - run: lein cljtests
diff --git a/example-theme/extra-translations/en.edn b/example-theme/extra-translations/en.edn
index ec7c24640..5b4c9eb9b 100644
--- a/example-theme/extra-translations/en.edn
+++ b/example-theme/extra-translations/en.edn
@@ -1,3 +1,3 @@
 {:t
  {:administration {:catalogue-items "Catalogue"}
-  :create-license {:license-text "Text"}}}
+  :create-license {:license-text "Licence text"}}}
diff --git a/example-theme/extra-translations/fi.edn b/example-theme/extra-translations/fi.edn
index 12d7172cd..cd331eae9 100644
--- a/example-theme/extra-translations/fi.edn
+++ b/example-theme/extra-translations/fi.edn
@@ -1,1 +1,11 @@
-{:t {}}
+{:t
+ {:actions {:resource "Kielivara"}
+  :administration {:catalogue-item "Kielivara"
+                   :catalogue-items "Kielivarat"
+                   :create-catalogue-item "Uusi kielivara"}
+  :cart {:apply-for-bundle "Hae näitä kielivaroja (%1 kpl) yhdessä "
+         :header "%1 kielivaraa korissa"}
+  :catalogue {:catalogue "Kielivarat"
+              :header "Kielivarat"
+              :apply-resources "Hae uusia kielivaroja"}
+  :navigation {:catalogue "Kielivarat"}}}
\ No newline at end of file
diff --git a/resources/sql/queries.sql b/resources/sql/queries.sql
index 3876d0c56..6dcbbac4b 100644
--- a/resources/sql/queries.sql
+++ b/resources/sql/queries.sql
@@ -237,16 +237,6 @@ VALUES
  :fields::jsonb
 );
 
--- :name edit-form-template! :!
-UPDATE form_template
-SET (organization, title, modifierUserId, fields) =
-(:organization,
- :title,
- :user,
- :fields::jsonb)
-WHERE
-id = :id;
-
 -- :name set-form-template-state! :!
 -- TODO set modifieruserid?
 UPDATE form_template
diff --git a/resources/translations/en.edn b/resources/translations/en.edn
index 779baaee1..383c8dc7c 100644
--- a/resources/translations/en.edn
+++ b/resources/translations/en.edn
@@ -65,7 +65,6 @@
                    :disable "Disable"
                    :display-old "Display old"
                    :edit "Edit"
-                   :edit-form "Edit form"
                    :edit-workflow "Edit workflow"
                    :enable "Enable"
                    :end "End"
@@ -76,7 +75,6 @@
                             :workflow-in-use "Workflow in use:"}
                    :form "Form"
                    :forms "Forms"
-                   :intro [:div.intro [:p "From here you can manage the REMS datasets. See the menu above."]]
                    :license "License"
                    :license-field "License \"%1\""
                    :licenses "Licenses"
@@ -126,7 +124,6 @@
                           :returned "Changes requested"
                           :submitted "Applied"
                           :unknown "Unknown"}
-                 :intro [:div.intro [:p "By filling and sending in this application, the applicants may be granted the applied resources. All the applicable terms of use must also be accepted by each applicant."]]
                  :my-applications "My Applications"
                  :state "State"
                  :states {:approved "Approved"
@@ -136,23 +133,19 @@
                           :returned "Returned"
                           :submitted "Applied"
                           :unknown "Unknown"}
-                 :latest-activity "Latest activity"
+                 :latest-activity "Latest activity %1"
                  :view "View"}
   :autocomplete {:no-results "No results"
                  :placeholder "Choose or type"}
   :cart {:add "Add to cart"
          :apply "Apply"
          :apply-for-bundle "Apply for %1 resources as a bundle "
-         :empty [:div.intro [:p "Select resources to apply:"]]
          :header "%1 resources in the cart"
-         :intro [:div.intro [:p "Here are the selected resources. If several resources can be applied to with the same application, they will be automatically grouped into a bundle."]]
          :remove "Remove"}
   :catalogue {:catalogue "Catalogue"
               :header "Resource"
-              :intro [:p "The catalogue contains all the resources that you can apply for in this system."]
               :more-info "More info"
-              :continue-existing-application "Continue application"
-              :continue-existing-application-intro [:div.intro [:p "You have unfinished applications that you can continue from here:"]]
+              :continue-existing-application "Continue existing application"
               :apply-resources "Apply for resources"}
   :collapse {:show-less "Show less"
              :show-more "Show more"}
@@ -206,8 +199,6 @@
                                  :message "Dear %1,\n\nYour application %2 has been rejected.\n\nView application: %3"}
           :application-closed {:subject "Application closed (%2)"
                                :message "Dear %1,\n\nYour application %2 has been closed.\n\nView application: %3"}
-          :application-returned {:subject "Application returned (%2)"
-                                 :message "Dear %1,\n\nYour application %2 has been returned.\n\nView application: %3"}
           :application-submitted {:subject "Application submitted (%2: %3)"
                                   :message "Dear %1,\n\n%2 has submitted an application (%3): %4.\n\nView application: %5"}
           :comment-requested {:subject "Comment requested (%2: %3)"
@@ -259,7 +250,7 @@
                       :invalid-value "Invalid value."
                       :required "Field \"%1\" is required."
                       :toolong "Text in field \"%1\" too long."}}
-  :header {:title "REMS"}
+  :header {:title "Welcome to REMS"}
   :item-lists {:move-down "Move down"
                :move-up "Move up"
                :remove "Remove"}
@@ -270,9 +261,7 @@
          :username "Username"}
   :link {:download-file "Download file"
          :opens-in-new-window "Opens in a new window"}
-:login {:alternative "Other login options"
-:intro [:div [:h1 "Welcome to REMS"] [:p "This is a demo environment for testing the REMS software. The demo environment has a couple of fictional datasets to which you can apply for access. More information is available on " [:a {:href "#/extra-pages/about"} "About"] " page."]
-                  [:p "Please, login to access REMS."]]
+  :login {:alternative "Other login options"
           :text "Login with Haka credentials"
           :title "Login"}
   :missing "Missing translation %1"
diff --git a/resources/translations/fi.edn b/resources/translations/fi.edn
index 095c48869..56362c00d 100644
--- a/resources/translations/fi.edn
+++ b/resources/translations/fi.edn
@@ -65,7 +65,6 @@
                    :disable "Poista käytöstä"
                    :display-old "Näytä vanhat"
                    :edit "Muokkaa"
-                   :edit-form "Muokkaa lomaketta"
                    :edit-workflow "Muokkaa työvuota"
                    :enable "Ota käyttöön"
                    :end "Loppu"
@@ -76,7 +75,6 @@
                             :workflow-in-use "Työvuo on käytössä:"}
                    :form "Lomake"
                    :forms "Lomakkeet"
-                   :intro [:div.intro [:p "Täällä voit hallinnoida REMSin aineistoja. Valitse alue valikoista yläpuolelta."]]
                    :license "Lisenssi"
                    :license-field "Lisenssi \"%1\""
                    :licenses "Lisenssit"
@@ -126,7 +124,6 @@
                           :returned "Palautettu muokattavaksi"
                           :submitted "Haettu"
                           :unknown "Tuntematon"}
-                 :intro [:div.intro [:p "Täyttämällä ja lähettämällä tämän hakemuksen kaikki hakijat voivat saada oikeuden haettuihin resursseihin. Kunkin hakijan on lisäksi hyväksyttävä käyttöehdot viimeistään hakemuksen käsittelyn jälkeen."]]
                  :my-applications "Omat hakemukset"
                  :state "Tila"
                  :states {:approved "Hyväksytty"
@@ -136,23 +133,19 @@
                           :returned "Palautettu"
                           :submitted "Haettu"
                           :unknown "Tuntematon"}
-                 :latest-activity "Viimeisin toimenpide"
+                 :latest-activity "Viimeisin toimenpide %1"
                  :view "Näytä"}
   :autocomplete {:no-results "Ei tuloksia"
                  :placeholder "Valitse tai kirjoita"}
   :cart {:add "Lisää koriin"
          :apply "Hae"
          :apply-for-bundle "Hae %1 aineistoa yhdessä "
-         :empty [:div.intro [:p "Valitse resursseja haettavaksi:"]]
          :header "%1 aineistoa korissa"
-         :intro [:div.intro [:p "Tässä ovat valitsemasi resurssit. Samalla hakemuksella haettavat resurssit ryhmitellään automaattisesti yhteen."]]
          :remove "Poista"}
   :catalogue {:catalogue "Aineistoluettelo"
               :header "Aineistoluettelo"
-              :intro [:p "Aineistoluettelossa on listattuna kaikki resurssit joita voit tästä järjestelmästä hakea."]
               :more-info "Lisätietoja"
               :continue-existing-application "Jatka hakemusta"
-              :continue-existing-application-intro [:div.intro [:p "Sinulla on keskeneräisiä hakemuksia, joita voit jatkaa tästä:"]]
               :apply-resources "Hae uusia resursseja"}
   :collapse {:show-less "Näytä vähemmän"
              :show-more "Näytä lisää"}
@@ -206,8 +199,6 @@
                                  :message "Hyvä %1,\n\nHakemuksesi %2 on hylätty.\n\nTarkastele hakemusta: %3"}
           :application-closed {:subject "Hakemus suljettu (%2)"
                                :message "Hyvä %1,\n\nHakemuksesi %2 on suljettu.\n\nTarkastele hakemusta: %3"}
-          :application-returned {:subject "Hakemus palautettu (%2)"
-                               :message "Hyvä %1,\n\nHakemuksesi %2 on palautettu.\n\nTarkastele hakemusta: %3"}
           :application-submitted {:subject "Hakemus lähetetty (%2: %3)"
                                   :message "Hyvä %1,\n\n%2 on lähettänyt käyttöoikeushakemuksen (%3): %4.\n\nTarkastele hakemusta: %5"}
           :comment-requested {:subject "Kommenttipyyntö (%2: %3)"
@@ -222,7 +213,7 @@
           :member-added {:subject "Lisätty hakemuksen jäseneksi (%2)"
                          :message "Hyvä %1,\n\nSinut on lisätty hakemuksen %2 jäseneksi.\n\nTarkastele hakemusta: %3"}
           :member-invited {:subject "Kutsu osallistumaan hakemukseen"
-                           :message "Hei,\n\nTämä sähköpostiosoite (%1) on kutsuttu osallistumaan kielivarojen käyttöoikeushakemukseen.\n\nOsallistumislinkki: %2"}}
+                           :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"
@@ -259,7 +250,7 @@
                       :invalid-value "Arvo ei kelpaa."
                       :required "Kenttä \"%1\" on pakollinen."
                       :toolong "Kentän \"%1\" sisältö on liian pitkä."}}
-  :header {:title "REMS"}
+  :header {:title "Tervetuloa REMSiin"}
   :item-lists {:move-down "Siirrä alas"
                :move-up "Siirrä ylös"
                :remove "Poista"}
@@ -271,8 +262,6 @@
   :link {:download-file "Lataa tiedosto"
          :opens-in-new-window "Aukeaa uuteen ikkunaan"}
   :login {:alternative "Muut kirjautumisvaihtoehdot"
-          :intro [:div [:h1 "Tervetuloa REMSiin"] [:p "Tämä on demo-ympäristö, joka on tarkoitettu REMS-ohjelmiston kokeilemiseen. Demo-ympäristöön on luotu valmiiksi joitain kuvitteellisia tietoaineistoja, joihin voit hakea käyttöoikeutta. Lisätietoja " [:a {:href "#/extra-pages/about"} "Info-sivulla"] "."]
-                  [:p "Ole hyvä ja kirjaudu sisään."]]
           :text "Kirjaudu sisään Haka-tunnuksin"
           :title "Kirjaudu sisään"}
   :missing "Käännös puuttuu %1"
diff --git a/src/clj/rems/api/forms.clj b/src/clj/rems/api/forms.clj
index 9161c57b3..91abd9e25 100644
--- a/src/clj/rems/api/forms.clj
+++ b/src/clj/rems/api/forms.clj
@@ -56,12 +56,12 @@
    (for [wf (form/get-form-templates filters)]
      (format-form wf))))
 
-(s/defschema FormCommand
+(s/defschema CreateFormCommand
   {:organization s/Str
    :title s/Str
    :fields [FormField]})
 
-(s/defschema FormResponse
+(s/defschema CreateFormResponse
   {:success s/Bool
    :id s/Num})
 
@@ -80,13 +80,6 @@
                                      (when-not disabled {:enabled true})
                                      (when-not archived {:archived false})))))
 
-    (POST "/create" []
-      :summary "Create form"
-      :roles #{:owner}
-      :body [command FormCommand]
-      :return FormResponse
-      (ok (form/create-form! (getx-user-id) command)))
-
     (GET "/:form-id" []
       :summary "Get form by id"
       :roles #{:owner}
@@ -94,29 +87,13 @@
       :return FullForm
       (ok (form/get-form-template form-id)))
 
-    (GET "/:form-id/editable" []
-      :summary "Check if the form is editable"
-      :roles #{:owner}
-      :path-params [form-id :- (describe s/Num "form-id")]
-      :return SuccessResponse
-      (ok (form/form-editable form-id)))
-
-    ;; TODO: PATCH would be more appropriate, but we use PUT elsewhere in the API
-    (PUT "/:form-id/edit" []
-      :summary "Edit form"
+    (POST "/create" []
+      :summary "Create form"
       :roles #{:owner}
-      :path-params [form-id :- (describe s/Num "form-id")]
-      :body [command FormCommand]
-      :return SuccessResponse
-      (ok (form/edit-form! (getx-user-id) form-id command)))
+      :body [command CreateFormCommand]
+      :return CreateFormResponse
+      (ok (form/create-form! (getx-user-id) command)))
 
-    ;; TODO: Change endpoint for updating form to be consistent with
-    ;;   the endpoint for editing form (/:form-id/edit). Also change
-    ;;   terminology to be less easily confused with form editing, e.g.,
-    ;;   from /update to /:form-id/update-state.
-    ;;
-    ;;   For consistency, do similar change for catalogue items, licenses,
-    ;;   and resources.
     (PUT "/update" []
       :summary "Update form"
       :roles #{:owner}
diff --git a/src/clj/rems/css/styles.clj b/src/clj/rems/css/styles.clj
index b880ed89b..bce10174d 100644
--- a/src/clj/rems/css/styles.clj
+++ b/src/clj/rems/css/styles.clj
@@ -281,7 +281,6 @@
    [:h1 :h2 {:font-weight 400}]
    [:h1 :h2 :h3 {:letter-spacing (u/rem 0.17)}]
    [:h4 :h5 :h6 {:letter-spacing (u/rem 0.12)}]
-   [:h1 {:margin-bottom (u/rem 2)}]
    [:#app {:min-height (u/percent 100)
            :flex 1
            :display :flex}]
@@ -464,8 +463,9 @@
    [:.jumbotron
     {:background-color "#fff"
      :text-align "center"
+     :max-width (u/px 420)
+     :margin "30px auto"
      :color "#000"
-     :margin-top (u/rem 2)
      :border-style "solid"
      :border-width (u/px 1)
      :box-shadow (util/get-theme-attribute :collapse-shadow :table-shadow)}
@@ -473,7 +473,6 @@
    [:.login-btn {:max-height (u/px 70)
                  :margin-bottom (u/px 20)}
     [:&:hover {:filter "brightness(80%)"}]]
-   [:.login-component {:max-width (u/px 420)}]
    (generate-rems-table-styles)
    [:.btn.disabled {:opacity 0.25}]
    [:.catalogue-item-link {:color "#fff"
@@ -578,7 +577,6 @@
    [:.new-form-field-option {:text-align "center"}]
 
    [:.full {:width "100%"}]
-   [:.intro {:margin-bottom (u/rem 2)}]
    [:.rectangle {:width (u/px 50)
                  :height (u/px 50)}]
    [:.color-1 {:background-color (util/get-theme-attribute :color1)}]
@@ -636,7 +634,7 @@
                              (-> (util/get-theme-attribute :color1)
                                  (c/saturate -50)
                                  (c/lighten 33)))}]
-   [:h2 {:margin [[(u/rem 3) 0 (u/rem 1) 0]]}]
+   [:h2 {:margin [[(u/rem 1) 0]]}]
 
    ;; application list
    [:.rems-table
diff --git a/src/clj/rems/db/form.clj b/src/clj/rems/db/form.clj
index b10beca29..a15d0f358 100644
--- a/src/clj/rems/db/form.clj
+++ b/src/clj/rems/db/form.clj
@@ -45,59 +45,30 @@
                                :inputprompt (get input-prompt lang)}))
     item-id))
 
-(defn- catalogue-items-for-form [id]
-  (->> (catalogue/get-localized-catalogue-items {:form id :archived false})
-       (map #(select-keys % [:id :title :localizations]))))
-
-(defn- form-in-use-error [form-id]
-  (let [catalogue-items (catalogue-items-for-form form-id)]
-    (when (seq catalogue-items)
-      {:success false
-       :errors [{:type :t.administration.errors/form-in-use :catalogue-items catalogue-items}]})))
-
-(defn form-editable [form-id]
-    (or (form-in-use-error form-id)
-        {:success true}))
-
-(defn- generate-fields-with-ids! [user-id form-id fields]
-  ;; Mirror field ids to form template so that form templates
-  ;; can be cross-referenced with form answers. Once old-style
-  ;; forms are gone, will need to allocate ids here (just use
-  ;; order, or generate UUIDs)
-  (map-indexed (fn [order field]
-                 (let [id (create-form-item! user-id form-id order field)]
-                   (assoc field :id id)))
-               fields))
-
 (defn create-form! [user-id {:keys [organization title fields] :as form}]
   ;; FIXME Remove saving old style forms only when we have a db migration.
   ;;       Otherwise it will get reeealy tricky to return both versions in get-api.
-  (let [;; NB: Legacy forms (created by db/create-form!) are not updated
-        ;;   when the form is edited. This is on purpose: this whole legacy
-        ;;   codepath will be removed soon.
-        form-id (:id (db/create-form! {:organization organization
+  (let [form-id (:id (db/create-form! {:organization organization
                                        :title title
                                        :user user-id}))
-        fields-with-ids (generate-fields-with-ids! user-id form-id fields)]
-    (db/save-form-template!
-     (assoc form
-            :id form-id
-            :user user-id
-            :fields (json/generate-string fields-with-ids)))
+        ;; Mirror field ids to form template so that form templates
+        ;; can be cross-referenced with form answers. Once old-style
+        ;; forms are gone, will need to allocate ids here (just use
+        ;; order, or generate UUIDs)
+        fields-with-ids (map-indexed (fn [order field]
+                                       (let [id (create-form-item! user-id form-id order field)]
+                                         (assoc field :id id)))
+                                     fields)]
+    (db/save-form-template! (assoc form
+                                   :id form-id
+                                   :user user-id
+                                   :fields (json/generate-string fields-with-ids)))
     {:success (not (nil? form-id))
      :id form-id}))
 
-(defn edit-form! [user-id form-id {:keys [fields] :as form}]
-  (or (form-in-use-error form-id)
-      (do (db/edit-form-template!
-           (assoc form
-                  :id form-id
-                  :user user-id
-                  :fields (json/generate-string (generate-fields-with-ids! user-id form-id fields))))
-          {:success true})))
-
 (defn update-form! [command]
-  (let [catalogue-items (catalogue-items-for-form (:id command))]
+  (let [catalogue-items (->> (catalogue/get-localized-catalogue-items {:form (:id command) :archived false})
+                             (map #(select-keys % [:id :title :localizations])))]
     (if (and (:archived command) (seq catalogue-items))
       {:success false
        :errors [{:type :t.administration.errors/form-in-use :catalogue-items catalogue-items}]}
diff --git a/src/clj/rems/form_validation.clj b/src/clj/rems/form_validation.clj
index 2c27b16ec..84aff5773 100644
--- a/src/clj/rems/form_validation.clj
+++ b/src/clj/rems/form_validation.clj
@@ -1,23 +1,16 @@
 (ns rems.form-validation
-  "Pure functions for form validation logic"
-  (:require [clojure.string :as str]))
-
-(defn- required? [field]
-  (and (not (:field/optional field))
-       (not= :label (:field/type field))
-       (str/blank? (:field/value field))))
-
-(defn- too-long? [field]
-  (and (:field/max-length field)
-       (> (count (:field/value field))
-          (:field/max-length field))))
+  "Pure functions for form validation logic")
 
 (defn- validate-field [field]
-  (cond
-    (required? field) {:field-id (:field/id field)
-                       :type :t.form.validation/required}
-    (too-long? field) {:field-id (:field/id field)
-                       :type :t.form.validation/toolong}))
+  (if (empty? (:field/value field))
+    (when-not (or (:field/optional field) (= "label" (:field/type field)))
+      ;; TODO: use field/id in output
+      {:field-id (:field/id field)
+       :type :t.form.validation/required})
+    (when (and (:field/maxlength field)
+               (> (count (:field/value field)) (:field/maxlength field)))
+      {:field-id (:field/id field)
+       :type :t.form.validation/toolong})))
 
 (defn validate-fields [fields]
   (->> (sort-by :field/id fields)
diff --git a/src/clj/rems/migrations/missing_form_templates.clj b/src/clj/rems/migrations/missing_form_templates.clj
index 827116a0f..ef5753e99 100644
--- a/src/clj/rems/migrations/missing_form_templates.clj
+++ b/src/clj/rems/migrations/missing_form_templates.clj
@@ -101,10 +101,8 @@ WHERE itemId = :item;
 
 (defn process-localizations [localizations]
   (reduce merge-maps (for [{:keys [langcode title inputprompt]} localizations]
-                       (do (when (or title inputprompt)
-                             (assert langcode "Missing langcode in application_form_item_localization table!"))
-                           (merge (when title {:title {(keyword langcode) title}})
-                                  (when inputprompt {:input-prompt {(keyword langcode) inputprompt}}))))))
+                       (merge (when title {:title {(keyword langcode) title}})
+                              (when inputprompt {:input-prompt {(keyword langcode) inputprompt}})))))
 
 (deftest process-localizations-test
   (is (= {:title {:fi "fi title" :en "en title" :es "es title"}
diff --git a/src/clj/rems/poller/email.clj b/src/clj/rems/poller/email.clj
index bb5f3afab..7f88346c7 100644
--- a/src/clj/rems/poller/email.clj
+++ b/src/clj/rems/poller/email.clj
@@ -68,38 +68,44 @@
 ;; There's a slight inconsistency here: we look at current members, so
 ;; a member might get an email for an event that happens before he was
 ;; added.
-(defn- emails-to-applicant-and-members [event application subject-text body-text]
+(defmethod event-to-emails-impl :application.event/approved [event application]
   (vec
    (for [member (applicant-and-members application)]
      {:to-user (:userid member)
-      :subject (text-format subject-text
+      :subject (text-format :t.email.application-approved/subject
                             (:userid member)
                             (application-id-for-email application)
                             (link-to-application (:application/id event)))
-      :body (text-format body-text
+      :body (text-format :t.email.application-approved/message
                          (:userid member)
                          (application-id-for-email application)
                          (link-to-application (:application/id event)))})))
 
-(defmethod event-to-emails-impl :application.event/approved [event application]
-  (emails-to-applicant-and-members event application
-                                   :t.email.application-approved/subject
-                                   :t.email.application-approved/message))
-
 (defmethod event-to-emails-impl :application.event/rejected [event application]
-  (emails-to-applicant-and-members event application
-                                   :t.email.application-rejected/subject
-                                   :t.email.application-rejected/message))
+  (vec
+   (for [member (applicant-and-members application)]
+     {:to-user (:userid member)
+      :subject (text-format :t.email.application-rejected/subject
+                            (:userid member)
+                            (application-id-for-email application)
+                            (link-to-application (:application/id event)))
+      :body (text-format :t.email.application-rejected/message
+                         (:userid member)
+                         (application-id-for-email application)
+                         (link-to-application (:application/id event)))})))
 
 (defmethod event-to-emails-impl :application.event/closed [event application]
-  (emails-to-applicant-and-members event application
-                                   :t.email.application-closed/subject
-                                   :t.email.application-closed/message))
-
-(defmethod event-to-emails-impl :application.event/returned [event application]
-  (emails-to-applicant-and-members event application
-                                   :t.email.application-returned/subject
-                                   :t.email.application-returned/message))
+  (vec
+   (for [member (applicant-and-members application)]
+     {:to-user (:userid member)
+      :subject (text-format :t.email.application-closed/subject
+                            (:userid member)
+                            (application-id-for-email application)
+                            (link-to-application (:application/id event)))
+      :body (text-format :t.email.application-closed/message
+                         (:userid member)
+                         (application-id-for-email application)
+                         (link-to-application (:application/id event)))})))
 
 (defmethod event-to-emails-impl :application.event/comment-requested [event application]
   (vec
diff --git a/src/cljs/rems/administration/administration.cljs b/src/cljs/rems/administration/administration.cljs
index ab81445fa..08931fbda 100644
--- a/src/cljs/rems/administration/administration.cljs
+++ b/src/cljs/rems/administration/administration.cljs
@@ -93,7 +93,15 @@
        [document-title (text :t.navigation/administration)]
        (if @loading?
          [spinner/big]
-         (text :t.administration/intro))])))
+         [:div.spaced-sections
+          {:style {:display :flex
+                   :flex-direction :column
+                   :max-width "15rem"}}
+          [to-catalogue-items [:btn :btn-primary]]
+          [to-resources [:btn :btn-primary]]
+          [to-forms [:btn :btn-primary]]
+          [to-workflows [:btn :btn-primary]]
+          [to-licenses [:btn :btn-primary]]])])))
 
 
 (defn guide []
diff --git a/src/cljs/rems/administration/create_form.cljs b/src/cljs/rems/administration/create_form.cljs
index 4a927e5d2..de7490858 100644
--- a/src/cljs/rems/administration/create_form.cljs
+++ b/src/cljs/rems/administration/create_form.cljs
@@ -5,22 +5,18 @@
             [rems.administration.administration :refer [administration-navigator-container]]
             [rems.administration.components :refer [checkbox localized-text-field radio-button-group text-field]]
             [rems.administration.items :as items]
-            [rems.administration.status-flags :as status-flags]
             [rems.atoms :refer [document-title]]
             [rems.collapsible :as collapsible]
             [rems.fields :as fields]
             [rems.spinner :as spinner]
             [rems.status-modal :as status-modal]
             [rems.text :refer [text text-format]]
-            [rems.util :refer [dispatch! fetch put! post! normalize-option-key parse-int remove-empty-keys]]))
+            [rems.util :refer [dispatch! fetch post! normalize-option-key parse-int remove-empty-keys]]))
 
 (rf/reg-event-fx
  ::enter-page
- (fn [{:keys [db]} [_ form-id edit-form?]]
-   {:db (assoc db
-               ::form {:fields []}
-               ::form-id form-id
-               ::edit-form? edit-form?)
+ (fn [{:keys [db]} [_ form-id]]
+   {:db (assoc db ::form {:fields []})
     :dispatch-n [[::fetch-form form-id]]}))
 
 (rf/reg-event-fx
@@ -44,7 +40,6 @@
 (rf/reg-sub ::form (fn [db _] (::form db)))
 (rf/reg-sub ::form-errors (fn [db _] (::form-errors db)))
 (rf/reg-sub ::loading-form? (fn [db _] (::loading-form? db)))
-(rf/reg-sub ::edit-form? (fn [db _] (::edit-form? db)))
 (rf/reg-event-db ::set-form-field (fn [db [_ keys value]] (assoc-in db (concat [::form] keys) value)))
 
 (rf/reg-event-db ::add-form-field (fn [db [_]] (update-in db [::form :fields] items/add {:type "text"})))
@@ -154,27 +149,16 @@
              {:fields (apply merge (mapv #(validate-field %1 %2 languages) (form :fields) (range)))})
       remove-empty-keys))
 
-(defn- page-title [edit-form?]
-  (if edit-form?
-    (text :t.administration/edit-form)
-    (text :t.administration/create-form)))
-
 (rf/reg-event-fx
- ::send-form
- (fn [{:keys [db]} [_]]
-   (let [edit? (db ::edit-form?)
-         form-errors (validate-form (db ::form) (db :languages))
-         send-verb (if edit? put! post!)]
+ ::create-form
+ (fn [{:keys [db]} [_ request]]
+   (let [form-errors (validate-form (db ::form) (db :languages))]
      (when (empty? form-errors)
-       (status-modal/common-pending-handler! (page-title edit?))
-       (send-verb (str "/api/forms/"
-                       (if edit?
-                         (str (db ::form-id) "/edit")
-                         "create"))
-                  {:params (build-request (db ::form) (db :languages))
-                   :handler (partial status-modal/common-success-handler! #(dispatch! (str "#/administration/forms/" (or (db ::form-id) (:id %)))))
-                   :error-handler status-modal/common-error-handler!})
-      {:db (assoc db ::form-errors form-errors)}))))
+       (status-modal/common-pending-handler! (text :t.administration/create-form))
+       (post! "/api/forms/create" {:params request
+                                   :handler (partial status-modal/common-success-handler! #(dispatch! (str "#/administration/forms/" (:id %))))
+                                   :error-handler status-modal/common-error-handler!}))
+     {:db (assoc db ::form-errors form-errors)})))
 
 ;;;; UI
 
@@ -276,10 +260,13 @@
   [items/move-down-button #(rf/dispatch [::move-form-field-down field-index])])
 
 (defn- save-form-button [on-click]
-  [:button.btn.btn-primary
-   {:type :button
-    :on-click on-click}
-   (text :t.administration/save)])
+  (let [form @(rf/subscribe [::form])
+        languages @(rf/subscribe [:languages])
+        request (build-request form languages)]
+    [:button.btn.btn-primary
+     {:type :button
+      :on-click #(on-click request)}
+     (text :t.administration/save)]))
 
 (defn- cancel-button []
   [:button.btn.btn-secondary
@@ -337,11 +324,10 @@
 
 (defn create-form-page []
   (let [form @(rf/subscribe [::form])
-        edit-form? @(rf/subscribe [::edit-form?])
         loading-form? @(rf/subscribe [::loading-form?])]
     [:div
      [administration-navigator-container]
-     [document-title (page-title edit-form?)]
+     [document-title (text :t.administration/create-form)]
      (if loading-form?
        [:div [spinner/big]]
        [:div.container-fluid.editor-content
@@ -349,7 +335,7 @@
          [:div.col-lg
           [collapsible/component
            {:id "create-form"
-            :title (page-title edit-form?)
+            :title (text :t.administration/create-form)
             :always [:div
                      [form-organization-field]
                      [form-title-field]
@@ -360,6 +346,6 @@
 
                      [:div.col.commands
                       [cancel-button]
-                      [save-form-button #(rf/dispatch [::send-form])]]]}]]
+                      [save-form-button #(rf/dispatch [::create-form %])]]]}]]
          [:div.col-lg
           [form-preview form]]]])]))
diff --git a/src/cljs/rems/administration/form.cljs b/src/cljs/rems/administration/form.cljs
index f044dda8d..6434cdf66 100644
--- a/src/cljs/rems/administration/form.cljs
+++ b/src/cljs/rems/administration/form.cljs
@@ -3,14 +3,12 @@
             [rems.administration.administration :refer [administration-navigator-container]]
             [rems.administration.components :refer [inline-info-field]]
             [rems.administration.create-form :refer [form-preview]]
-            [rems.administration.status-flags :as status-flags]
             [rems.atoms :refer [info-field readonly-checkbox document-title]]
             [rems.collapsible :as collapsible]
             [rems.common-util :refer [andstr]]
             [rems.spinner :as spinner]
-            [rems.status-modal :as status-modal]
             [rems.text :refer [localize-time text text-format]]
-            [rems.util :refer [dispatch! fetch put!]]))
+            [rems.util :refer [dispatch! fetch]]))
 
 (rf/reg-event-fx
  ::enter-page
@@ -34,29 +32,12 @@
 (rf/reg-sub ::form (fn [db _] (::form db)))
 (rf/reg-sub ::loading? (fn [db _] (::loading? db)))
 
-(rf/reg-event-fx
- ::edit-form
- (fn [_ [_ id]]
-   (status-modal/set-pending! {:title (text :t.administration/edit)})
-   (fetch (str "/api/forms/" id "/editable")
-          {:handler #(if (:success %)
-                       (dispatch! (str "/#/administration/edit-form/" id))
-                       (status-flags/update-error-handler! %))
-           :error-handler status-modal/common-error-handler!})
-   {}))
-
 (defn- back-button []
   [:button.btn.btn-secondary
    {:type :button
     :on-click #(dispatch! "/#/administration/forms")}
    (text :t.administration/back)])
 
-(defn- edit-button [id]
-  [:button.btn.btn-primary
-   {:type :button
-    :on-click #(rf/dispatch [::edit-form id])}
-   (text :t.administration/edit)])
-
 (defn- copy-as-new-button [id]
   [:button.btn.btn-primary
    {:type :button
@@ -74,10 +55,7 @@
               [inline-info-field (text :t.administration/start) (localize-time (:start form))]
               [inline-info-field (text :t.administration/end) (localize-time (:end form))]
               [inline-info-field (text :t.administration/active) [readonly-checkbox (not (:expired form))]]]}]
-   [:div.col.commands
-    [back-button]
-    [edit-button (:id form)]
-    [copy-as-new-button (:id form)]]
+   [:div.col.commands [back-button] [copy-as-new-button (:id form)]]
    [form-preview form]])
 ;; TODO Do we support form licenses?
 
diff --git a/src/cljs/rems/administration/forms.cljs b/src/cljs/rems/administration/forms.cljs
index 199c4bf1a..266ee5505 100644
--- a/src/cljs/rems/administration/forms.cljs
+++ b/src/cljs/rems/administration/forms.cljs
@@ -1,7 +1,6 @@
 (ns rems.administration.forms
   (:require [re-frame.core :as rf]
             [rems.administration.administration :refer [administration-navigator-container]]
-            [rems.administration.form :as form]
             [rems.administration.status-flags :as status-flags]
             [rems.atoms :refer [readonly-checkbox document-title]]
             [rems.spinner :as spinner]
@@ -60,16 +59,10 @@
    (text :t.administration/create-form)])
 
 (defn- to-view-form [form]
-   [:a.btn.btn-primary
+  [:a.btn.btn-primary
    {:href (str "/#/administration/forms/" (:id form))}
    (text :t.administration/view)])
 
-(defn- to-edit-form [form]
-  [:button.btn.btn-primary
-   {:type :button
-    :on-click #(rf/dispatch [:rems.administration.form/edit-form (:id form)])}
-   (text :t.administration/edit)])
-
 (defn- copy-as-new-form [form]
   [:a.btn.btn-primary
    {:href (str "/#/administration/create-form/" (:id form))}
@@ -96,7 +89,6 @@
                       :sort-value (if checked? 1 2)})
            :commands {:td [:td.commands
                            [to-view-form form]
-                           [to-edit-form form]
                            [copy-as-new-form form]
                            [status-flags/enabled-toggle form #(rf/dispatch [::update-form %1 %2])]
                            [status-flags/archived-toggle form #(rf/dispatch [::update-form %1 %2])]]}})
diff --git a/src/cljs/rems/administration/status_flags.cljs b/src/cljs/rems/administration/status_flags.cljs
index 3aa842f65..dd478855b 100644
--- a/src/cljs/rems/administration/status_flags.cljs
+++ b/src/cljs/rems/administration/status_flags.cljs
@@ -73,10 +73,7 @@
   (into [:div]
         (map format-update-error errors)))
 
-(defn update-error-handler! [response]
-  (status-modal/set-error! {:error-content (format-update-failure response)}))
-
 (defn common-update-handler! [on-close response]
   (if (:success response)
     (status-modal/set-success! {:on-close on-close})
-    (update-error-handler! response)))
+    (status-modal/set-error! {:error-content (format-update-failure response)})))
diff --git a/src/cljs/rems/application.cljs b/src/cljs/rems/application.cljs
index 7f4f47149..3080b1b9a 100644
--- a/src/cljs/rems/application.cljs
+++ b/src/cljs/rems/application.cljs
@@ -389,14 +389,7 @@
          {:phase :approve :text :t.phases/approve}
          {:phase :result :text :t.phases/approved}]))
 
-(defn- application-id-value [config application]
-  (let [id-column (get config :application-id-column :id)]
-    (case id-column
-      :external-id (:application/external-id application)
-      :id (:application/id application)
-      (:application/id application))))
-
-(defn- application-state [application config]
+(defn- application-header [application]
   (let [state (:application/state application)
         last-activity (:application/last-activity application)
         event-groups (->> (:application/events application)
@@ -409,26 +402,14 @@
                           (map #(map format-event %)))]
     [collapsible/component
      {:id "header"
-      :title (text :t.applications/state)
+      :title [:span#application-state
+              (str
+               (text :t.applications/state)
+               (str ": " (localize-state state)))]
       :always (into [:div
                      [:div.mb-3 {:class (str "state-" (name state))}
                       (phases (get-application-phases state))]
-                     [info-field
-                      (text :t.applications/application)
-                      [:span#application-id (application-id-value config application)]
-                      {:inline? true}]
-                     [info-field
-                      (text :t.actions/description)
-                      (:application/description application)
-                      {:inline? true}]
-                     [info-field
-                      (text :t.applications/state)
-                      [:span#application-state (localize-state state)]
-                      {:inline? true}]
-                     [info-field
-                      (text :t.applications/latest-activity)
-                      (localize-time last-activity)
-                      {:inline? true}]]
+                     [:h3 (text-format :t.applications/latest-activity (localize-time last-activity))]]
                     (when-let [g (first event-groups)]
                       (into [[:h3 (text :t.form/events)]]
                             (render-event-groups [g]))))
@@ -590,7 +571,7 @@
                [:div#resource-action-forms
                 [change-resources-form application can-bundle-all? can-comment? (partial reload! application-id)]]]}]))
 
-(defn- render-application [application edit-application config userid]
+(defn- render-application [application edit-application userid]
   (let [messages (remove nil?
                          [(disabled-items-warning application) ; NB: eval this here so we get nil or a warning
                           (when-let [errors (:validation-errors edit-application)]
@@ -599,10 +580,9 @@
                               :contents [format-validation-errors application errors]}])])]
     [:div
      [:div {:class "float-right"} [pdf-button (:application/id application)]]
-     [document-title (str (text :t.applications/application) " " (application-id-value config application))]
-     (text :t.applications/intro)
+     [document-title (text :t.applications/application)]
      (into [:div] messages)
-     [application-state application config]
+     [application-header application]
      [:div.mt-3 [applicants-info application]]
      [:div.mt-3 [applied-resources application userid]]
      [:div.my-3 [application-fields application edit-application]]
@@ -612,8 +592,7 @@
 ;;;; Entrypoint
 
 (defn application-page []
-  (let [config @(rf/subscribe [:rems.config/config])
-        application @(rf/subscribe [::application])
+  (let [application @(rf/subscribe [::application])
         edit-application @(rf/subscribe [::edit-application])
         userid (get-in @(rf/subscribe [:identity]) [:user :eppn])
         loading? (not application)]
@@ -621,7 +600,7 @@
       [:div
        [document-title (text :t.applications/application)]
        [spinner/big]]
-      [render-application application edit-application config userid])))
+      [render-application application edit-application userid])))
 
 
 ;;;; Guide
diff --git a/src/cljs/rems/auth/auth.cljs b/src/cljs/rems/auth/auth.cljs
index e106af13d..f589ba1f8 100644
--- a/src/cljs/rems/auth/auth.cljs
+++ b/src/cljs/rems/auth/auth.cljs
@@ -6,15 +6,12 @@
 
 (defn login-component []
   (let [config @(rf/subscribe [:rems.config/config])
-        alternative-endpoint (:alternative-login-url config)
-        login-component (case (:authentication config)
-                          :shibboleth (shibboleth/login-component alternative-endpoint)
-                          :fake-shibboleth (shibboleth/login-component alternative-endpoint)
-                          :ldap (ldap/login-component)
-                          nil)]
-    (when login-component
-      [:div.jumbotron.login-component
-       login-component])))
+        alternative-endpoint (:alternative-login-url config)]
+    (case (:authentication config)
+      :shibboleth (shibboleth/login-component alternative-endpoint)
+      :fake-shibboleth (shibboleth/login-component alternative-endpoint)
+      :ldap (ldap/login-component)
+      nil)))
 
 (defn guide []
   [:div
diff --git a/src/cljs/rems/auth/ldap.cljs b/src/cljs/rems/auth/ldap.cljs
index bfb3e357a..3608850ad 100644
--- a/src/cljs/rems/auth/ldap.cljs
+++ b/src/cljs/rems/auth/ldap.cljs
@@ -3,7 +3,7 @@
             [rems.text :refer [text]]))
 
 (defn login-component []
-  [:div
+  [:div.jumbotron
    [document-title (text :t.ldap/title)]
    [:form
     {:action "/ldap/login" :method "post"}
diff --git a/src/cljs/rems/auth/shibboleth.cljs b/src/cljs/rems/auth/shibboleth.cljs
index e6ac20c4a..d7eea41a3 100644
--- a/src/cljs/rems/auth/shibboleth.cljs
+++ b/src/cljs/rems/auth/shibboleth.cljs
@@ -5,10 +5,10 @@
             [rems.text :refer [text]]))
 
 (defn login-component [alternative-endpoint]
-  [:div
+  [:div.jumbotron
    [document-title (text :t.login/title)]
    [:p (text :t.login/text)]
-   [:div
+   [:div.col-md6
     [atoms/link-to nil
                    (nav/url-dest "/Shibboleth.sso/Login")
                    [atoms/image {:class "login-btn" :alt "Haka"} "/img/haka-logo.jpg"]]]
diff --git a/src/cljs/rems/cart.cljs b/src/cljs/rems/cart.cljs
index b6504dcd1..53fe43285 100644
--- a/src/cljs/rems/cart.cljs
+++ b/src/cljs/rems/cart.cljs
@@ -69,21 +69,18 @@
 (defn cart-list
   "List of shopping cart items"
   [items language]
-  (if (seq items)
-    [:div
-     (text :t.cart/intro)
-     [:div.outer-cart.mb-3
-      [:div.inner-cart
-       [:div.cart-title
-        [:i.fa.fa-shopping-cart]
-        [:span (text-format :t.cart/header (count items))]]
-       [:table.rems-table.cart
-        (into [:tbody]
-              (let [key-fn #(select-vals % [:wfid :formid])]
-                (apply concat
-                       (for [group (vals (into (sorted-map) (group-by key-fn items)))]
-                         (group-view (sort-by get-localized-title group) language)))))]]]]
-    (text :t.cart/empty)))
+  (when (seq items)
+    [:div.outer-cart.mb-3
+     [:div.inner-cart
+      [:div.cart-title
+       [:i.fa.fa-shopping-cart]
+       [:span (text-format :t.cart/header (count items))]]
+      [:table.rems-table.cart
+       (into [:tbody]
+             (let [key-fn #(select-vals % [:wfid :formid])]
+               (apply concat
+                      (for [group (vals (into (sorted-map) (group-by key-fn items)))]
+                        (group-view (sort-by get-localized-title group) language)))))]]]))
 
 (defn cart-list-container []
   (let [language @(rf/subscribe [:language])
diff --git a/src/cljs/rems/catalogue.cljs b/src/cljs/rems/catalogue.cljs
index dc63fd90e..6827ae24d 100644
--- a/src/cljs/rems/catalogue.cljs
+++ b/src/cljs/rems/catalogue.cljs
@@ -100,7 +100,6 @@
     (when (seq @(rf/subscribe [applications]))
       [:div
        [:h2 (text :t.catalogue/continue-existing-application)]
-       (text :t.catalogue/continue-existing-application-intro)
        [application-list/component
         {:id applications
          :applications applications
@@ -127,7 +126,6 @@
         loading-drafts? @(rf/subscribe [::loading-drafts?])]
     [:div
      [document-title (text :t.catalogue/catalogue)]
-     (text :t.catalogue/intro)
      (if (or loading-catalogue? loading-drafts?)
        [spinner/big]
        [:div
diff --git a/src/cljs/rems/language_switcher.cljs b/src/cljs/rems/language_switcher.cljs
index 0145c33a3..f1aeb84a4 100644
--- a/src/cljs/rems/language_switcher.cljs
+++ b/src/cljs/rems/language_switcher.cljs
@@ -14,17 +14,16 @@
   []
   (let [current-language @(rf/subscribe [:language])
         languages @(rf/subscribe [:languages])]
-    (when (> (count languages) 1)
-      (into [:div.language-switcher]
-            (for [language languages]
-              (let [lang-str (str/upper-case (name language))]
-                [:form.inline
-                 [:button {:type :button
-                           :class (lang-link-classes current-language language)
-                           :on-click (fn []
-                                       (rf/dispatch [:set-current-language language])
-                                       (rf/dispatch [:rems.spa/user-triggered-navigation]))}
-                  lang-str]]))))))
+    (into [:div.language-switcher]
+          (for [language languages]
+            (let [lang-str (str/upper-case (name language))]
+              [:form.inline
+               [:button {:type :button
+                         :class (lang-link-classes current-language language)
+                         :on-click (fn []
+                                     (rf/dispatch [:set-current-language language])
+                                     (rf/dispatch [:rems.spa/user-triggered-navigation]))}
+                lang-str]])))))
 
 (defn guide []
   [:div
diff --git a/src/cljs/rems/spa.cljs b/src/cljs/rems/spa.cljs
index 87b5df665..21127686e 100644
--- a/src/cljs/rems/spa.cljs
+++ b/src/cljs/rems/spa.cljs
@@ -191,13 +191,7 @@
     (do
       (rf/dispatch [:rems.catalogue/enter-page])
       [catalogue-page])
-    [:div
-     [:div.row.justify-content-center
-      [:div.col-md-6.row.justify-content-center
-       (text :t.login/intro)]]
-     [:div.row.justify-content-center
-      [:div.col-md-6.row.justify-content-center
-       [auth/login-component]]]]))
+    [auth/login-component]))
 
 (defn unauthorized-page []
   [:div
@@ -387,10 +381,6 @@
   (rf/dispatch [:rems.administration.create-form/enter-page (parse-int form-id)])
   (rf/dispatch [:set-active-page :rems.administration/create-form]))
 
-(secretary/defroute "/administration/edit-form/:form-id" [form-id]
-  (rf/dispatch [:rems.administration.create-form/enter-page (parse-int form-id) true])
-  (rf/dispatch [:set-active-page :rems.administration/create-form]))
-
 (secretary/defroute "/administration/create-license" []
   (rf/dispatch [:rems.administration.create-license/enter-page])
   (rf/dispatch [:set-active-page :rems.administration/create-license]))
diff --git a/src/cljs/rems/status_modal.cljs b/src/cljs/rems/status_modal.cljs
index 96adfcb39..9fc5fb22d 100644
--- a/src/cljs/rems/status_modal.cljs
+++ b/src/cljs/rems/status_modal.cljs
@@ -1,10 +1,10 @@
 (ns rems.status-modal
   "Component for showing a status modal dialog.
 
-  There should only be one `status-modal` at the root of the component hierarchy.
+  There should only be one `status-modal` at the root of the component hieararchy.
 
   Use the functions `set-pending!`, `set-success!` and `set-error!` to control its state.
-  See `rems.status-modal/status-modal` for values to use in the calls."
+  See `rems.status-modal/status-model` for values to use in the calls."
   (:require [re-frame.core :as rf]
             [reagent.core :as r]
             [rems.common-util :refer [deep-merge]]
@@ -42,7 +42,6 @@
 
    `initial-state` can contain:
 
-  `:open?`         - A boolean indicating if the modal is shown or not.
   `:result`        - Either {:success? true} one of {:error ...} or {:errors ...}
                      Shows the status based on the values or a spinner while neither.
     `:error`       - error that may contain `:key`, `:type`, `:status` and `:status-text`
@@ -81,7 +80,7 @@
 
   The modal will be shown."
   [state]
-  (rf/dispatch [::set-state state]))
+  (rf/dispatch [::set-state (merge {:open? true} state)]))
 
 (defn set-success!
   "Globally set the modal state to reflect a successful operation.
@@ -107,11 +106,9 @@
                                           state)]))
 
 (defn common-pending-handler!
-  "Common variant of `set-pending!` where you wish to open the modal and
-  customize the `title`."
+  "Common variant of `set-pending!` where you only wish to customize the `title`."
   [title]
-  (set-pending! {:open? true
-                 :title title}))
+  (set-pending! {:title title}))
 
 (defn common-success-handler!
   "Common variant of `set-success!` where you only wish to customize the `on-close`


Test patch:
diff --git a/src/clj/rems/db/test_data.clj b/src/clj/rems/db/test_data.clj
index 80befed14..7caf95b48 100644
--- a/src/clj/rems/db/test_data.clj
+++ b/src/clj/rems/db/test_data.clj
@@ -121,11 +121,6 @@
                    :input-prompt {:en "Project"
                                   :fi "Projekti"}}
 
-                  {:title {:en "Here would be some helpful instructions."
-                           :fi "Tässä olisi jotain täyttöohjeita."}
-                   :optional false
-                   :type "label"}
-
                   {:title {:en "Purpose of the project"
                            :fi "Projektin tarkoitus"}
                    :optional false
diff --git a/test/clj/rems/api/test_forms.clj b/test/clj/rems/api/test_forms.clj
index d177a7f0b..e3e588182 100644
--- a/test/clj/rems/api/test_forms.clj
+++ b/test/clj/rems/api/test_forms.clj
@@ -128,65 +128,6 @@
             (is (= (:fields form-spec)
                    (mapv #(dissoc % :id) (:fields form))))))))))
 
-(deftest form-editable-test
-  (let [api-key "42"
-        user-id "owner"
-        form-id (-> (request :post "/api/forms/create")
-                    (authenticate api-key user-id)
-                    (json-body {:organization "abc" :title "form editable test"
-                                :fields []})
-                    handler
-                    read-ok-body
-                    :id)]
-    (testing "New form is editable"
-      (is (:success (-> (request :get (str "/api/forms/" form-id "/editable"))
-                        (authenticate api-key user-id)
-                        handler
-                        read-ok-body))))
-    (let [data (-> (request :post "/api/catalogue-items/create")
-                   (authenticate api-key user-id)
-                   (json-body {:title "test-item-title"
-                               :form form-id
-                               :resid 1
-                               :wfid 1
-                               :archived false})
-                   handler
-                   read-body)]
-      (testing "Form is non-editable after in use by a catalogue item"
-        (is (not (:success (-> (request :get (str "/api/forms/" form-id "/editable"))
-                               (authenticate api-key user-id)
-                               handler
-                               read-ok-body))))))))
-
-(deftest form-edit-test
-  (let [api-key "42"
-        user-id "owner"
-        form-id (-> (request :post "/api/forms/create")
-                    (authenticate api-key user-id)
-                    (json-body {:organization "abc" :title "form edit test"
-                                :fields []})
-                    handler
-                    read-ok-body
-                    :id)]
-    (testing "form content before editing"
-      (let [form (-> (request :get (str "/api/forms/" form-id))
-                     (authenticate api-key user-id)
-                     handler
-                     read-ok-body)]
-        (is (= (form :organization) "abc")))
-     (let [response (-> (request :put (str "/api/forms/" form-id "/edit"))
-                        (authenticate api-key user-id)
-                        (json-body {:organization "def" :title "form edit test"
-                                    :fields []})
-                        handler
-                        read-ok-body)]
-       (testing "form content after editing"
-         (let [form (-> (request :get (str "/api/forms/" form-id))
-                        (authenticate api-key user-id)
-                        handler
-                        read-ok-body)]
-           (is (= (form :organization) "def"))))))))
-
 (deftest form-update-test
   (let [api-key "42"
         user-id "owner"
diff --git a/test/clj/rems/migrations/test_convert_to_dynamic_applications.clj b/test/clj/rems/migrations/test_convert_to_dynamic_applications.clj
index 231cd6961..f1a48fb79 100644
--- a/test/clj/rems/migrations/test_convert_to_dynamic_applications.clj
+++ b/test/clj/rems/migrations/test_convert_to_dynamic_applications.clj
@@ -3,12 +3,13 @@
             [clojure.pprint :refer [pprint]]
             [clojure.test :refer :all]
             [conman.core :as conman]
-            [rems.api.testing :refer [api-fixture]]
+            [rems.db.applications :as applications]
             [rems.db.applications.legacy :as legacy]
             [rems.db.core :refer [*db*]]
             [rems.db.test-data :as test-data]
             [rems.db.workflow :as workflow]
             [rems.migrations.convert-to-dynamic-applications :refer :all]
+            [rems.api.testing :refer [api-fixture]]
             [rems.validate :as validate])
   (:import [java.util UUID]))
 
@@ -142,12 +143,11 @@ INSERT INTO entitlement (resid, catappid, userid, start, endt) VALUES (1, 24, 'a
                                 :application/field-values {1 "draft application"
                                                            2 "draft application"
                                                            3 "draft application"
-                                                           4 "draft application"
-                                                           5 ""
+                                                           4 ""
+                                                           5 "draft application"
                                                            6 "draft application"
-                                                           7 "draft application"
-                                                           8 "draft appl"
-                                                           9 "draft application"}}
+                                                           7 "draft appl"
+                                                           8 "draft application"}}
                                {:event/type :application.event/licenses-accepted
                                 :event/time test-data/creation-time
                                 :event/actor "developer"
@@ -184,12 +184,11 @@ INSERT INTO entitlement (resid, catappid, userid, start, endt) VALUES (1, 24, 'a
                                 :application/field-values {1 "applied application"
                                                            2 "applied application"
                                                            3 "applied application"
-                                                           4 "applied application"
-                                                           5 ""
+                                                           4 ""
+                                                           5 "applied application"
                                                            6 "applied application"
-                                                           7 "applied application"
-                                                           8 "applied ap"
-                                                           9 "applied application"}}
+                                                           7 "applied ap"
+                                                           8 "applied application"}}
                                {:event/type :application.event/licenses-accepted
                                 :event/time test-data/creation-time
                                 :event/actor "developer"
@@ -231,12 +230,11 @@ INSERT INTO entitlement (resid, catappid, userid, start, endt) VALUES (1, 24, 'a
                                 :application/field-values {1 "rejected application"
                                                            2 "rejected application"
                                                            3 "rejected application"
-                                                           4 "rejected application"
-                                                           5 ""
+                                                           4 ""
+                                                           5 "rejected application"
                                                            6 "rejected application"
-                                                           7 "rejected application"
-                                                           8 "rejected a"
-                                                           9 "rejected application"}}
+                                                           7 "rejected a"
+                                                           8 "rejected application"}}
                                {:event/type :application.event/licenses-accepted
                                 :event/time test-data/creation-time
                                 :event/actor "developer"
@@ -284,12 +282,11 @@ INSERT INTO entitlement (resid, catappid, userid, start, endt) VALUES (1, 24, 'a
                                 :application/field-values {1 "accepted application"
                                                            2 "accepted application"
                                                            3 "accepted application"
-                                                           4 "accepted application"
-                                                           5 ""
+                                                           4 ""
+                                                           5 "accepted application"
                                                            6 "accepted application"
-                                                           7 "accepted application"
-                                                           8 "accepted a"
-                                                           9 "accepted application"}}
+                                                           7 "accepted a"
+                                                           8 "accepted application"}}
                                {:event/type :application.event/licenses-accepted
                                 :event/time test-data/creation-time
                                 :event/actor "developer"
@@ -337,12 +334,11 @@ INSERT INTO entitlement (resid, catappid, userid, start, endt) VALUES (1, 24, 'a
                                 :application/field-values {1 "returned application"
                                                            2 "returned application"
                                                            3 "returned application"
-                                                           4 "returned application"
-                                                           5 ""
+                                                           4 ""
+                                                           5 "returned application"
                                                            6 "returned application"
-                                                           7 "returned application"
-                                                           8 "returned a"
-                                                           9 "returned application"}}
+                                                           7 "returned a"
+                                                           8 "returned application"}}
                                {:event/type :application.event/licenses-accepted
                                 :event/time test-data/creation-time
                                 :event/actor "developer"
@@ -393,12 +389,11 @@ INSERT INTO entitlement (resid, catappid, userid, start, endt) VALUES (1, 24, 'a
                                 :application/field-values {1 "bundled application"
                                                            2 "bundled application"
                                                            3 "bundled application"
-                                                           4 "bundled application"
-                                                           5 ""
+                                                           4 ""
+                                                           5 "bundled application"
                                                            6 "bundled application"
-                                                           7 "bundled application"
-                                                           8 "bundled ap"
-                                                           9 "bundled application"}}
+                                                           7 "bundled ap"
+                                                           8 "bundled application"}}
                                {:event/type :application.event/licenses-accepted
                                 :event/time test-data/creation-time
                                 :event/actor "alice"
@@ -451,12 +446,11 @@ INSERT INTO entitlement (resid, catappid, userid, start, endt) VALUES (1, 24, 'a
                                 :application/field-values {1 "application with review"
                                                            2 "application with review"
                                                            3 "application with review"
-                                                           4 "application with review"
-                                                           5 ""
+                                                           4 ""
+                                                           5 "application with review"
                                                            6 "application with review"
-                                                           7 "application with review"
-                                                           8 "applicatio"
-                                                           9 "application with review"}}
+                                                           7 "applicatio"
+                                                           8 "application with review"}}
                                {:event/type :application.event/licenses-accepted
                                 :event/time test-data/creation-time
                                 :event/actor "alice"
@@ -511,12 +505,11 @@ INSERT INTO entitlement (resid, catappid, userid, start, endt) VALUES (1, 24, 'a
                                 :application/field-values {1 "application in review"
                                                            2 "application in review"
                                                            3 "application in review"
-                                                           4 "application in review"
-                                                           5 ""
+                                                           4 ""
+                                                           5 "application in review"
                                                            6 "application in review"
-                                                           7 "application in review"
-                                                           8 "applicatio"
-                                                           9 "application in review"}}
+                                                           7 "applicatio"
+                                                           8 "application in review"}}
                                {:event/type :application.event/licenses-accepted
                                 :event/time test-data/creation-time
                                 :event/actor "alice"
@@ -562,8 +555,7 @@ INSERT INTO entitlement (resid, catappid, userid, start, endt) VALUES (1, 24, 'a
                                                            5 ""
                                                            6 ""
                                                            7 ""
-                                                           8 ""
-                                                           9 ""}}
+                                                           8 ""}}
                                {:event/type :application.event/licenses-accepted
                                 :event/time (-> application :dynamic-events (nth 2) :event/time)
                                 :event/actor "alice"
@@ -617,8 +609,7 @@ INSERT INTO entitlement (resid, catappid, userid, start, endt) VALUES (1, 24, 'a
                                                            5 ""
                                                            6 ""
                                                            7 ""
-                                                           8 ""
-                                                           9 ""}}
+                                                           8 ""}}
                                {:event/type :application.event/licenses-accepted
                                 :event/time (-> application :dynamic-events (nth 2) :event/time)
                                 :event/actor "alice"
@@ -679,8 +670,7 @@ INSERT INTO entitlement (resid, catappid, userid, start, endt) VALUES (1, 24, 'a
                                                            5 ""
                                                            6 ""
                                                            7 ""
-                                                           8 ""
-                                                           9 ""}}
+                                                           8 ""}}
                                {:event/type :application.event/licenses-accepted
                                 :event/time (-> application :dynamic-events (nth 2) :event/time)
                                 :event/actor "alice"
@@ -732,8 +722,7 @@ INSERT INTO entitlement (resid, catappid, userid, start, endt) VALUES (1, 24, 'a
                                                            5 ""
                                                            6 ""
                                                            7 ""
-                                                           8 ""
-                                                           9 ""}}
+                                                           8 ""}}
                                {:event/type :application.event/licenses-accepted
                                 :event/time (-> application :dynamic-events (nth 2) :event/time)
                                 :event/actor "alice"
diff --git a/test/clj/rems/poller/test_email.clj b/test/clj/rems/poller/test_email.clj
index 55369e00c..703fc7e1c 100644
--- a/test/clj/rems/poller/test_email.clj
+++ b/test/clj/rems/poller/test_email.clj
@@ -154,22 +154,21 @@
                 :subject "Application closed (2001/3)",
                 :body "Dear somebody,\n\nYour application 2001/3 has been closed.\n\nView application: http://example.com/#/application/7"}]]
              (events-to-emails events))))
-    (testing "application rejected"
-      (let [events (conj base-events
-                         {:application/id 7
-                          :event/type :application.event/rejected
-                          :event/actor "handler"})]
-        (is (= [[]
-                [{:to-user "assistant",
-                  :subject "Application submitted (applicant: 2001/3)",
-                  :body "Dear assistant,\n\napplicant has submitted an application (2001/3): en title 11, en title 21.\n\nView application: http://example.com/#/application/7"}
-                 {:to-user "handler",
-                  :subject "Application submitted (applicant: 2001/3)",
-                  :body "Dear handler,\n\napplicant has submitted an application (2001/3): en title 11, en title 21.\n\nView application: http://example.com/#/application/7"}]
-                [{:subject "Application rejected (2001/3)",
-                  :body "Dear applicant,\n\nYour application 2001/3 has been rejected.\n\nView application: http://example.com/#/application/7",
-                  :to-user "applicant"}]]
-               (events-to-emails events)))))
+    (let [events (conj base-events
+                       {:application/id 7
+                        :event/type :application.event/rejected
+                        :event/actor "handler"})]
+      (is (= [[]
+              [{:to-user "assistant",
+                :subject "Application submitted (applicant: 2001/3)",
+                :body "Dear assistant,\n\napplicant has submitted an application (2001/3): en title 11, en title 21.\n\nView application: http://example.com/#/application/7"}
+               {:to-user "handler",
+                :subject "Application submitted (applicant: 2001/3)",
+                :body "Dear handler,\n\napplicant has submitted an application (2001/3): en title 11, en title 21.\n\nView application: http://example.com/#/application/7"}]
+              [{:subject "Application rejected (2001/3)",
+                :body "Dear applicant,\n\nYour application 2001/3 has been rejected.\n\nView application: http://example.com/#/application/7",
+                :to-user "applicant"}]]
+             (events-to-emails events))))
     (testing "id field can be overrided"
       (with-redefs [rems.config/env (assoc rems.config/env :application-id-column :id)]
         (is (= [[]
@@ -179,30 +178,4 @@
                  {:to-user "handler"
                   :subject "Application submitted (applicant: 7)"
                   :body "Dear handler,\n\napplicant has submitted an application (7): en title 11, en title 21.\n\nView application: http://example.com/#/application/7"}]]
-               (events-to-emails base-events)))))
-    (testing "returning application to applicant and re-submitting"
-      (let [events (conj base-events
-                         {:application/id 7
-                          :event/type :application.event/returned
-                          :event/actor "handler"
-                          :application/comment ["requesting changes"]}
-                         {:application/id 7
-                          :event/type :application.event/submitted
-                          :event/actor "applicant"})]
-        (is (= [[]
-                [{:to-user "assistant",
-                  :subject "Application submitted (applicant: 2001/3)",
-                  :body "Dear assistant,\n\napplicant has submitted an application (2001/3): en title 11, en title 21.\n\nView application: http://example.com/#/application/7"}
-                 {:to-user "handler",
-                  :subject "Application submitted (applicant: 2001/3)",
-                  :body "Dear handler,\n\napplicant has submitted an application (2001/3): en title 11, en title 21.\n\nView application: http://example.com/#/application/7"}]
-                [{:to-user "applicant",
-                  :subject "Application returned (2001/3)",
-                  :body "Dear applicant,\n\nYour application 2001/3 has been returned.\n\nView application: http://example.com/#/application/7"}]
-                [{:to-user "assistant",
-                  :subject "Application submitted (applicant: 2001/3)",
-                  :body "Dear assistant,\n\napplicant has submitted an application (2001/3): en title 11, en title 21.\n\nView application: http://example.com/#/application/7"}
-                 {:to-user "handler",
-                  :subject "Application submitted (applicant: 2001/3)",
-                  :body "Dear handler,\n\napplicant has submitted an application (2001/3): en title 11, en title 21.\n\nView application: http://example.com/#/application/7"}]]
-               (events-to-emails events)))))))
+               (events-to-emails base-events)))))))
diff --git a/test/clj/rems/test_browser.clj b/test/clj/rems/test_browser.clj
index e24646d77..83a265f22 100644
--- a/test/clj/rems/test_browser.clj
+++ b/test/clj/rems/test_browser.clj
@@ -112,7 +112,7 @@
                               {:fn/text resource-name}
                               {:xpath "./ancestor::tr"}
                               {:css "button.apply-for-catalogue-items"}])
-  (wait-visible *driver* {:tag :h1, :fn/has-text "Application"})
+  (wait-visible *driver* {:tag :h1, :fn/text "Application"})
   (wait-page-loaded)
   (screenshot *driver* (io/file reporting-dir "application-page.png")))
 
@@ -222,7 +222,7 @@
     (check-box "disease_prevention")
 
     (send-application)
-    (is (= "Applied" (get-element-text *driver* :application-state)))
+    (is (= "State: Applied" (get-element-text *driver* :application-state)))
 
     (accept-licenses)
 
diff --git a/test/clj/rems/test_form_validation.clj b/test/clj/rems/test_form_validation.clj
index 2891f24b7..6c1f8359f 100644
--- a/test/clj/rems/test_form_validation.clj
+++ b/test/clj/rems/test_form_validation.clj
@@ -1,5 +1,4 @@
 (ns rems.test-form-validation
-  (:refer-clojure :exclude [validate-fields])
   (:require [clojure.test :refer :all]
             [rems.form-validation :refer [validate-fields]]))
 
@@ -10,7 +9,7 @@
                                  :field/value "a"}]))))
 
 
-  (testing "optional fields do not need to be filled"
+  (testing "optional fields"
     (is (nil? (validate-fields [{:field/title "A"
                                  :field/optional true
                                  :field/value nil}
@@ -18,36 +17,24 @@
                                  :field/optional true
                                  :field/value ""}]))))
 
-  (testing "labels are always effectively optional"
-    (is (nil? (validate-fields [{:field/type :label
-                                 :field/optional false
-                                 :field/value ""}
-                                {:field/type :label
-                                 :field/optional true
-                                 :field/value ""}]))))
-
   (testing "error: field required"
     (is (= [{:type :t.form.validation/required :field-id 2}
-            {:type :t.form.validation/required :field-id 3}
-            {:type :t.form.validation/required :field-id 4}]
+            {:type :t.form.validation/required :field-id 3}]
            (validate-fields [{:field/id 1
                               :field/optional true
                               :field/value nil}
                              {:field/id 2
-                              :field/optional false
-                              :field/value nil}
-                             {:field/id 3
                               :field/optional false
                               :field/value ""}
-                             {:field/id 4
+                             {:field/id 3
                               :field/optional false
-                              :field/value "    "}]))))
+                              :field/value nil}]))))
 
   (testing "error: field input too long"
     (is (= [{:type :t.form.validation/toolong :field-id 2}]
            (validate-fields [{:field/id 1
-                              :field/max-length 5
+                              :field/maxlength 5
                               :field/value "abcde"}
                              {:field/id 2
-                              :field/max-length 5
+                              :field/maxlength 5
                               :field/value "abcdef"}])))))
diff --git a/test/clj/rems/test_locales.clj b/test/clj/rems/test_locales.clj
index e031e491d..599bdf03a 100644
--- a/test/clj/rems/test_locales.clj
+++ b/test/clj/rems/test_locales.clj
@@ -94,7 +94,7 @@
                                                    :translations-directory "translations/"
                                                    :theme-path "./example-theme/theme.edn"})]
       (is (= "Catalogue" (getx-in translations [:en :t :administration :catalogue-items])))
-      (is (= "Text" (getx-in translations [:en :t :create-license :license-text])))))
+      (is (= "Licence text" (getx-in translations [:en :t :create-license :license-text])))))
   (testing "extra translations don't override keys that are not defined in extras"
     (let [translations (locales/load-translations {:languages [:en]
                                                    :translations-directory "translations/"
diff --git a/tests.edn b/tests.edn
index 8f5eb530d..191a5f1f2 100644
--- a/tests.edn
+++ b/tests.edn
@@ -9,11 +9,7 @@
                     {:id :integration
                      :ns-patterns ["rems"]
                      :test-paths ["src" "test"]
-                     :focus-meta [:integration]}
-                    {:id :focused
-                     :ns-patterns ["rems"]
-                     :test-paths ["src" "test"]
-                     :focus-meta [:focused]}]
+                     :focus-meta [:integration]}]
             :kaocha/reporter kaocha.report/dots
             :plugins [:kaocha.plugin/print-invocations
                       :kaocha.plugin/notifier