diff --git a/district/forms.py b/district/forms.py
index d4e7108c72d82cabe6f99761962e686b32b6d690..16147c8fe4c1109a72b20775505f079425582dfb 100644
--- a/district/forms.py
+++ b/district/forms.py
@@ -1,5 +1,4 @@
 from django import forms
-from django.contrib.messages import ERROR, WARNING
 from wagtail.admin.forms import WagtailAdminPageForm
 from wagtail.core.models.collections import Collection
 
@@ -70,12 +69,6 @@ class JekyllImportForm(WagtailAdminPageForm):
         if len(self.errors):
             return cleaned_data
 
-        # if cleaned_data.get("dry_run"):
-        # import_message_list = self.handle_import()
-        # for message in import_message_list:
-        #     if message["level"] in (WARNING, ERROR):
-        #         self.add_error("jekyll_repo_url", message["text"])
-
         return cleaned_data
 
     def handle_import(self):
diff --git a/district/tasks.py b/district/tasks.py
index e0d9c6cd61bb29b8ecb6f027fd739d596c6c7598..0bb2aa59c97005d902a0192601d3e953609930e6 100644
--- a/district/tasks.py
+++ b/district/tasks.py
@@ -1,8 +1,7 @@
 import logging
 
 from majak.celery import app
-
-from .jekyll_import import JekyllArticleImporter
+from shared.jekyll_import import JekyllArticleImporter
 
 logger = logging.getLogger(__name__)
 
diff --git a/region/forms.py b/region/forms.py
new file mode 100644
index 0000000000000000000000000000000000000000..16147c8fe4c1109a72b20775505f079425582dfb
--- /dev/null
+++ b/region/forms.py
@@ -0,0 +1,87 @@
+from django import forms
+from wagtail.admin.forms import WagtailAdminPageForm
+from wagtail.core.models.collections import Collection
+
+from .tasks import import_jekyll_articles
+
+
+class JekyllImportForm(WagtailAdminPageForm):
+    do_import = forms.BooleanField(
+        initial=False, required=False, label="Provést import z Jekyllu"
+    )
+    collection = forms.ModelChoiceField(
+        queryset=Collection.objects.all(), required=False, label="Kolekce obrázků"
+    )
+    dry_run = forms.BooleanField(
+        initial=True,
+        required=False,
+        label="Jenom na zkoušku",
+        help_text="Žádné články se neuloží, vypíše případné problémy či "
+        "již existující články - 'ostrému' importu existující "
+        "články nevadí, přeskočí je",
+    )
+    use_git = forms.BooleanField(
+        initial=False,
+        required=False,
+        label="Použít Git",
+        help_text="Umožňuje jednodušší zpracování, ale vyžaduje nainstalovaný Git.",
+    )
+    jekyll_repo_url = forms.URLField(
+        max_length=512,
+        required=False,
+        help_text="V GitHubu tlačítko Code -> a odkaz z Download zip"
+        "např. 'https://github.com/pirati-web/cb.pirati.cz/archive/refs/heads/gh-pages.zip',"
+        "pokud máte nainstalovaný Git, zvolte Použít Git a vložte"
+        "jednoduše URL repozitáře "
+        "např. 'https://github.com/pirati-web/cb.pirati.cz'",
+    )
+    readonly_log = forms.CharField(
+        disabled=True,
+        label="Log z posledního importu",
+        required=False,
+        widget=forms.Textarea,
+    )
+
+    def __init__(self, *args, **kwargs):
+        super().__init__(*args, **kwargs)
+        self.fields["readonly_log"].initial = self.instance.last_import_log
+
+    def clean(self):
+        cleaned_data = super().clean()
+
+        if not cleaned_data.get("do_import"):
+            return cleaned_data
+        else:
+            if not cleaned_data.get("collection"):
+                self.add_error("collection", "Pro import je toto pole povinné")
+            if not cleaned_data.get("jekyll_repo_url"):
+                self.add_error("jekyll_repo_url", "Pro import je toto pole povinné")
+
+        if cleaned_data.get("use_git"):
+            if cleaned_data.get("jekyll_repo_url", "").endswith(".zip"):
+                self.add_error(
+                    "jekyll_repo_url", "Vložte odkaz pouze na repozitář, ne na zip"
+                )
+        else:
+            if not cleaned_data.get("jekyll_repo_url", "").endswith(".zip"):
+                self.add_error("jekyll_repo_url", "Odkaz nesměřuje na soubor '.zip'")
+
+        if len(self.errors):
+            return cleaned_data
+
+        return cleaned_data
+
+    def handle_import(self):
+        import_jekyll_articles.delay(
+            article_parent_page_id=self.instance.id,
+            collection_id=self.cleaned_data["collection"].id,
+            url=self.cleaned_data["jekyll_repo_url"],
+            dry_run=self.cleaned_data["dry_run"],
+            use_git=self.cleaned_data["use_git"],
+        )
+
+    def save(self, commit=True):
+        if self.cleaned_data.get("do_import") and not self.cleaned_data["dry_run"]:
+            self.handle_import()
+
+        return super().save(commit=commit)
diff --git a/region/models.py b/region/models.py
index b23ccd0ada5604f5bda07de84874c74900fb2bf8..d75865e039084e501a4953a7910a810b9d2166da 100644
--- a/region/models.py
+++ b/region/models.py
@@ -11,6 +11,7 @@ from taggit.models import Tag, TaggedItemBase
 from wagtail.admin.edit_handlers import (
     CommentPanel,
     FieldPanel,
+    HelpPanel,
     MultiFieldPanel,
     ObjectList,
     PageChooserPanel,
@@ -30,6 +31,7 @@ from shared.models import ArticleMixin, MenuMixin, SubpageMixin
 from uniweb.constants import RICH_TEXT_FEATURES
 
 from . import blocks
+from .forms import JekyllImportForm
 
 
 class RegionHomePage(MenuMixin, MetadataPageMixin, CalendarMixin, Page):
@@ -365,6 +367,9 @@ class RegionArticlePage(ArticleMixin, SubpageMixin, MetadataPageMixin, Page):
 class RegionArticlesPage(SubpageMixin, MetadataPageMixin, Page):
     ### FIELDS
 
+    last_import_log = models.TextField(
+        "Výstup z posledního importu", null=True, blank=True
+    )
     max_items = models.IntegerField("Počet článků na stránce", default=12)
 
     ### PANELS
@@ -375,6 +380,38 @@ class RegionArticlesPage(SubpageMixin, MetadataPageMixin, Page):
 
     settings_panels = [CommentPanel()]
 
+    import_panels = [
+        MultiFieldPanel(
+            [
+                FieldPanel("do_import"),
+                FieldPanel("collection"),
+                FieldPanel("dry_run"),
+                FieldPanel("use_git"),
+                FieldPanel("jekyll_repo_url"),
+                FieldPanel("readonly_log"),
+                HelpPanel(
+                    "Import provádějte vždy až po vytvoření stránky aktualit. "
+                    'Pro uložení logu je nutné volit možnost "Publikovat", nikoliv'
+                    'pouze "Uložit koncept". '
+                    "Import proběhne na pozadí a může trvat až několik minut. "
+                    "Dejte si po spuštění importu kávu a potom obnovte stránku pro "
+                    "zobrazení výsledku importu."
+                ),
+            ],
+            "import z Jekyll repozitáře",
+        ),
+    ]
+
+    ### EDIT HANDLERS
+
+    edit_handler = TabbedInterface(
+        [
+            ObjectList(content_panels, heading="Obsah"),
+            ObjectList(settings_panels, heading="Nastavení"),
+            ObjectList(import_panels, heading="Import"),
+        ]
+    )
+
     ### RELATIONS
 
     parent_page_types = ["region.RegionHomePage"]
@@ -382,6 +419,8 @@ class RegionArticlesPage(SubpageMixin, MetadataPageMixin, Page):
 
     ### OTHERS
 
+    base_form_class = JekyllImportForm
+
     class Meta:
         verbose_name = "Aktuality"
 
diff --git a/region/tasks.py b/region/tasks.py
new file mode 100644
index 0000000000000000000000000000000000000000..8eb9c6d1de7b5f6892c2c0a058d22862cca16a2d
--- /dev/null
+++ b/region/tasks.py
@@ -0,0 +1,27 @@
+import logging
+
+from majak.celery import app
+from shared.jekyll_import import JekyllArticleImporter
+
+logger = logging.getLogger(__name__)
+
+
+@app.task
+def import_jekyll_articles(
+    article_parent_page_id: int,
+    collection_id: int,
+    url: str,
+    dry_run: bool,
+    use_git: bool,
+):
+    from .models import RegionArticlePage, RegionArticlesPage
+
+    return JekyllArticleImporter(
+        article_parent_page_id=article_parent_page_id,
+        collection_id=collection_id,
+        url=url,
+        dry_run=dry_run,
+        use_git=use_git,
+        parent_page_model=RegionArticlesPage,
+        page_model=RegionArticlePage,
+    ).perform_import()
diff --git a/district/jekyll_import.py b/shared/jekyll_import.py
similarity index 97%
rename from district/jekyll_import.py
rename to shared/jekyll_import.py
index 1f083b296a581f4c5739f562a8fd74feaac1876b..2871f3783ae4968dc5b068bbefbe8f0729afc34d 100644
--- a/district/jekyll_import.py
+++ b/shared/jekyll_import.py
@@ -27,7 +27,7 @@ from wagtail.images.models import Image
 from yaml.scanner import ScannerError
 
 logger = logging.getLogger(__name__)
-# from django.utils.dateparse import parse_date TODO enable date check again...
+# from django.utils.dateparse import parse_date # pro hledani krome title i podle data
 
 image_params = {}  # filled on JekyllArticleImporter init and used globally
 
@@ -170,7 +170,12 @@ def get_or_create_image(
 
                 file = ImageFile(open(img_path, "rb"), name=img_path)
                 image = Image(title=file_path, file=file, collection=collection)
-                image.save()
+                try:
+                    image.save()
+                except Exception as e:
+                    msg = "Nelze uložit obrázek"
+                    logger.warning(msg, extra={"exc": e})
+                    return None, msg
                 return image, ""
 
 
@@ -310,7 +315,7 @@ class JekyllArticleImporter:
         d = match.group(3)
         slug = match.group(4)
 
-        if article and self.article_path:  # asi jenom Ceske Budejovice
+        if self.article_path:  # asi jenom Ceske Budejovice
             Redirect.objects.get_or_create(
                 site=self.site,
                 old_path="/%s/%s/%s/%s/%s"
@@ -318,7 +323,7 @@ class JekyllArticleImporter:
                 defaults={"is_permanent": True, "redirect_page": article},
             )
 
-        elif article and self.permalink:
+        elif self.permalink:
             Redirect.objects.get_or_create(
                 site=self.site,
                 old_path=self.permalink.replace(":title", slug),
@@ -433,7 +438,6 @@ class JekyllArticleImporter:
         except (Page.DoesNotExist, Page.MultipleObjectsReturned):
             article = self.page_model()
 
-        # article.text = html
         article.content = [("text", RichText(html))]
         article.perex = self.get_perex(md) or "..."
 
@@ -517,7 +521,7 @@ class JekyllArticleImporter:
             if ext == "md":
                 article = self.import_post(file_path)
 
-                if self.dry_run:
+                if self.dry_run or not article:
                     return
 
                 article.save()  # ujistím se, že mám "redirect_page" pro Redirect uloženou