 
 (defn file-input [name f]
   [:button
-  [:label
-   [:input {:type "file"
-            :on-change f}]
-   name]])
+   [:label
+    [:input {:type "file"
+             :on-change f}]
+    name]])
 
 (defmulti show-change-set (fn [change-set] (:type change-set)))
 
-(defmethod show-change-set :create [change-set k]
-  (def change-set-data (:data change-set))
+(defn raw-property-view [value property]
+  ^{:key property} [:li
+                    [:span.label (str (key->label property) ": ")]
+                    [:span.value ((key->transformer property) value)]])
+
+(defn raw-property-changeset-view [values property]
+  ^{:key property} [:li
+                    [:span.label (str (key->label property) ": ")]
+                    [:span.value
+                     [:span.old (first values)]
+                     [:span.new (second values)]]])
+
+(defmethod show-change-set :create [{change-set-data :data} k]
   ^{:key k} [:ul.change-set
              (map (fn [component k]
                     ^{:key k} [:li.component

    (fn []
      [:div
       [notifications]
       [:label "Search: "
        [:input {:name "search",
                 :type "search"
                 :on-change (fn [e]
                              (swap! app-state assoc :filter {:val (.-target.value e)
                                                              :search (js->clj (.search index (.-target.value e)))}))}]]
       [:a {:href (->> @app-state
                       (util/state->document)
                       (clj->js)
                       (.stringify js/JSON)
                       (.encodeURIComponent js/window)
                       (str "data:text/json;charset=utf-8,"))
            :download "warehouse_components.json"
            }
        [:button "Export"]]
       [file-input "Import" (fn [e]
                              (let [reader (js/FileReader.)
                                    this (aget e "currentTarget")]
                                (aset reader
                                      "onload"
                                      (fn [reader-event]
                                        (->> (.-target.result reader-event)
                                             (.parse js/JSON)
                                             (#(js->clj % :keywordize-keys true))
                                             (util/merge-documents (util/state->document @app-state))
                                             (on-state-load))
                                        (aset this "value" "")))
                                (.readAsText reader (aget e "target" "files" "0"))))]
       (if (false? @adding)
         [:button {:on-click (fn [e]
                               (reset! adding true))} "Add new"])

                                   [:ul
                                    (map (fn [[k v] kvs]
                                           (if-not (= k :id)
                                             ^{:key k} (raw-property-view v k)))
                                         data)]]
                                  [:button {:on-click #(swap! app-state assoc-in [:components (:id metadata) :amount] 0)} "Revert"]])]
                    )
                  change-set-data
                  (range (count change-set-data) 0 -1))])

(defmethod show-change-set :update [{change-set-data :data} k]
  ^{:key k} [:ul.change-set
             (map (fn [component k]
                    ^{:key k} [:li.component
                               (let [data (:data component)
                                     metadata (:metadata component)]
                                 [:ul
                                  [:li (str "Name: " (:name metadata))]
                                  [:li "Data:"
                                   [:ul
                                    (map (fn [[k v] kvs]
                                           (if-not (= k :id)
                                             (raw-property-changeset-view v k)))
                                         data)]]])])
                  change-set-data
                  (range (count change-set-data) 0 -1))])

(defn search []
  [:label "Search: "
   [:input {:name "search",
            :type "search"
            :on-change (fn [e]
                         (swap! app-state assoc :filter {:val (.-target.value e)
                                                         :search (js->clj (.search index (.-target.value e)))}))}]])

(defn export []
  [:a {:href (->> @app-state
                  (util/state->document)
                  (clj->js)
                  (.stringify js/JSON)
                  (.encodeURIComponent js/window)
                  (str "data:text/json;charset=utf-8,"))
       :download "warehouse_components.json"
       }
   [:button "Export"]])

(defn import []
  [file-input "Import" (fn [e]
                         (let [reader (js/FileReader.)
                               this (aget e "currentTarget")]
                           (aset reader
                                 "onload"
                                 (fn [reader-event]
                                   (->> (.-target.result reader-event)
                                        (.parse js/JSON)
                                        (#(js->clj % :keywordize-keys true))
                                        (util/merge-documents (util/state->document @app-state))
                                        (on-state-load))
                                   (aset this "value" "")))
                           (.readAsText reader (aget e "target" "files" "0"))))])

(defn page []
  (let [adding (atom false)
