diff --git a/contracts/admin.py b/contracts/admin.py
index a9093aa47b4f0520b2789d9801801bbc84e76e53..1eb707c2867e341a0bb44c6f9b8e6607d989a431 100644
--- a/contracts/admin.py
+++ b/contracts/admin.py
@@ -2,6 +2,7 @@ from django.contrib import admin
 
 from shared.admin import MarkdownxGuardedModelAdmin
 
+from .forms import ContractAdminForm
 from .models import (
     Contract,
     Contractee,
@@ -22,6 +23,37 @@ class IndexHiddenModelAdmin(MarkdownxGuardedModelAdmin):
         return False
 
 
+class ContractAdmin(MarkdownxGuardedModelAdmin):
+    form = ContractAdminForm
+
+    fields = (
+        "type",
+        "subtype",
+        "signee_signature",
+        "contractee_signatures",
+        "valid_start_date",
+        "valid_end_date",
+        "legal_state",
+        "public_state",
+        "paper_form_state",
+        "publishing_rejection_comment",
+        "tender_url",
+        "identifier",
+        "issues",
+        "notes",
+        "summary",
+        "anonymized_contract_file",
+        "original_contract_file",
+        "primary_contract",
+        "expected_cost_total",
+        "expected_cost_year",
+        "expected_cost_month",
+        "expected_cost_hour",
+        "agreement_url",
+        "filing_area",
+    )
+
+
 for model in (
     SigneeRepresentative,
     SigneeSignature,
@@ -37,6 +69,7 @@ for model in (
     Contractee,
     ContractIssue,
     ContractFilingArea,
-    Contract,
 ):
     admin.site.register(model, MarkdownxGuardedModelAdmin)
+
+admin.site.register(Contract, ContractAdmin)
diff --git a/contracts/forms.py b/contracts/forms.py
new file mode 100644
index 0000000000000000000000000000000000000000..f5d1c5aba5672f7faecf17f1d0e4bf5cb6f6b449
--- /dev/null
+++ b/contracts/forms.py
@@ -0,0 +1,11 @@
+from django import forms
+from webpack_loader.loader import WebpackLoader
+
+
+class ContractAdminForm(forms.ModelForm):
+    class Media:
+        js = (
+            "shared/runtime.js",
+            "shared/shared.js",
+            "shared/admin_contract_form.js",
+        )
diff --git a/contracts/models.py b/contracts/models.py
index f3b62b7e35fab401d49188d5d7b1737d6e40f77b..b9f8446f098c8990d933d66e452840a407e10f9a 100644
--- a/contracts/models.py
+++ b/contracts/models.py
@@ -68,6 +68,7 @@ class SigneeRepresentative(models.Model):
         Signee,
         on_delete=models.CASCADE,
         related_name="representatives",
+        verbose_name="Smluvní strana",
     )
 
     name = models.CharField(
@@ -90,6 +91,7 @@ class SigneeSignature(models.Model):
         Signee,
         on_delete=models.CASCADE,
         related_name="signatures",
+        verbose_name="Smluvní strana",
     )
 
     date = models.DateField(
@@ -162,6 +164,7 @@ class ContracteeRepresentative(models.Model):
         Contractee,
         on_delete=models.CASCADE,
         related_name="representatives",
+        verbose_name="Smluvní strana",
     )
 
     name = models.CharField(
@@ -184,6 +187,7 @@ class ContracteeSignature(models.Model):
         Contractee,
         on_delete=models.CASCADE,
         related_name="signatures",
+        verbose_name="Smluvní strana",
     )
 
     date = models.DateField(
@@ -334,7 +338,7 @@ class Contract(models.Model):
         null=True,
         verbose_name="Důvod nezveřejnění",
         help_text="Obsah není veřejně přístupný.",
-    )  # WARNING: exclude in admin
+    )  # WARNING: public status dependent
 
     tender_url = models.URLField(
         max_length=256,
@@ -406,6 +410,7 @@ class Contract(models.Model):
         blank=True,
         null=True,
         related_name="filed_contracts",
+        verbose_name="Spisovna",
         help_text="Obsah není veřejně přístupný.",
     )  # WARNING: Dependent on the type!
 
@@ -426,6 +431,7 @@ class ContractIntent(models.Model):
         Contract,
         on_delete=models.CASCADE,
         related_name="intents",
+        verbose_name="Smlouva",
     )
 
     class Meta:
diff --git a/static_src/admin/contract_form.js b/static_src/admin/contract_form.js
new file mode 100644
index 0000000000000000000000000000000000000000..a3672ceb00bf5dcb315eb4d38ef64204a37cc961
--- /dev/null
+++ b/static_src/admin/contract_form.js
@@ -0,0 +1,57 @@
+import $ from "jquery";
+
+$(window).ready(
+    () => {
+        $(".field-publishing_rejection_comment").
+        css(
+            "display",
+            (
+                ($("#id_public_state").find(":selected").val() === "no") ?
+                "block": "none"
+            )
+        );
+
+        const allowedPrimaryContractValues = new Set(["amendment", "framework_order"]);
+
+        $(".field-primary_contract").
+        css(
+            "display",
+            (
+                (
+                    allowedPrimaryContractValues.has(
+                        $("#id_type").find(":selected").val()
+                    )
+                ) ?
+                "block": "none"
+            )
+        );
+
+        $("#id_public_state").on(
+            "change",
+            event => {
+                $(".field-publishing_rejection_comment").
+                css(
+                    "display",
+                    (
+                        ($(event.target).val() === "no") ?
+                        "block" : "none"
+                    )
+                );
+            }
+        );
+
+        $("#id_type").on(
+            "change",
+            event => {
+                $(".field-primary_contract").
+                css(
+                    "display",
+                    (
+                        (allowedPrimaryContractValues.has($(event.target).val())) ?
+                        "block": "none"
+                    )
+                );
+            }
+        );
+    }
+);
diff --git a/webpack.config.js b/webpack.config.js
index 5fd34684fb877b918b136bc58fd1e1fe949db07d..579381ee0904acfb069aebc042f5fe9d47d32d9c 100644
--- a/webpack.config.js
+++ b/webpack.config.js
@@ -9,11 +9,15 @@ module.exports = {
       import: path.resolve("static_src", "base.js"),
       dependOn: "shared",
     },
+    admin_contract_form: {
+      import: path.resolve("static_src", "admin", "contract_form.js"),
+      dependOn: "shared",
+    },
     shared: ["jquery"],
   },
   output: {
     path: path.resolve(__dirname, "shared", "static", "shared"),
-    filename: "[name]-[fullhash].js",
+    filename: "[name].js",  // Whitenoise takes care of hashes for us
   },
   module: {
     rules: [