{"action":"created","comment":{"url":"https://api.github.com/repos/wagtail/rfcs/pulls/comments/187798116","pull_request_review_id":119651882,"id":187798116,"diff_hunk":"@@ -0,0 +1,539 @@\n+# RFC 26: New `StreamField` and `InlinePanel` user interfaces\n+\n+* RFC: 26\n+* Author: Bertrand Bordage\n+* Created: 2018-05-11\n+* Last-Modified: 2018-05-11\n+\n+## Abstract\n+\n+This RFC proposes a brand new user interface for editing `StreamField`\n+and `InlinePanel` to improve ergonomics and consistency while adding\n+missing features: drag-and-drop, collapsible blocks, and duplication.\n+\n+This work was funded via [a Kickstarter project launched by NoriPyt](https://www.kickstarter.com/projects/noripyt/wagtails-first-hatch).\n+\n+## Current state of both technologies\n+\n+`InlinePanel` arrived first in Wagtail, inspired by the Django admin inlines.\n+It’s a way to edit a list of structured data within the same form.\n+\n+`StreamField` was originally designed by Torchbox to be an clean way to edit\n+rich text data instead of stuffing every content in a `RichTextField`.\n+But the community mostly saw in `StreamField` a solution to edit complex\n+structured data. Indeed, `StreamField` has potentially an unlimited flexibility\n+compared to `InlinePanel` that can only edit one level of blocks\n+of the same type.\n+\n+`InlinePanel` & `StreamField` have very different user interfaces,\n+with different possibilities. For example, `InlinePanel` can only append inlines\n+at the end of the list, whereas `StreamField` allows it anywhere.\n+\n+Note that dropping `InlinePanel` is out of the question.\n+The reason is that it stores strong links between data in the database,\n+which is safer than `StreamField`, especially in long-term projects.\n+\n+## Structure of the proposal\n+\n+For consistency, both `StreamField` and `InlinePanel` will look the same,\n+except that there will be no icon or block name in `InlinePanel`.\n+\n+Both `StreamField` blocks and `InlinePanel` items\n+will have two types of layout:\n+- `SIMPLE`: all content is visible, best on simple sites (default)\n+- `COLLAPSIBLE`: most content is hidden, best for complex sites\n+                 with large inlines or nested blocks\n+\n+`panels` will be usable in `StructBlock` like in `InlinePanel` and `Page`,\n+so we can define more complex layouts using e.g. `FieldRowPanel`.\n+\n+To optimise spacing within a block/item, labels will have three different\n+positions (configurable in `FieldPanel``):\n+- `LEFT` (default)\n+- `ABOVE`\n+- `HIDDEN`\n+\n+## Proposed interfaces\n+\n+Given that most of the work will be front-end, most of the specification work\n+consists in design mockups.\n+\n+There is a corresponding models.py for each proposal to show the backend\n+changes required by this work. \n+\n+### `SIMPLE` `StreamField`\n+\n+```python\n+# models.py\n+\n+from wagtail.admin.edit_handlers import (\n+    FieldPanel, FieldRowPanel, StreamFieldPanel,\n+)\n+from wagtail.core.blocks import (\n+    CharBlock, RichTextBlock, StructBlock, ChoiceBlock, DateBlock, ListBlock,\n+    EmbedBlock,\n+)\n+from wagtail.core.fields import StreamField\n+from wagtail.core.models import Page\n+from wagtail.images.blocks import ImageChooserBlock\n+from wagtail.images.edit_handlers import ImageChooserPanel\n+\n+\n+class TitleBlock(CharBlock):\n+    class Meta:\n+        icon = 'header'\n+        label = 'Titre'\n+        form_classname = 'full title'\n+\n+\n+class TextBlock(RichTextBlock):\n+    class Meta:\n+        icon = 'align-justify'\n+        label = 'Texte'\n+        form_classname = 'full'\n+\n+\n+class ImageBlock(StructBlock):\n+    image = ImageChooserBlock()\n+    format = ChoiceBlock(choices=[('left', 'Alignée à gauche'),\n+                                  ('center', 'Centrée'),\n+                                  ('right', 'Alignée à droite')])\n+    \n+    panels = [\n+        ImageChooserPanel('image', label_position=ImageChooserPanel.HIDDEN),\n+        FieldPanel('format'),\n+    ]\n+    \n+    class Meta:\n+        icon = 'image'\n+        label = 'Image'\n+\n+\n+class EventBlock(StructBlock):\n+    start = DateBlock(label='Début')\n+    end = DateBlock(required=False, label='Fin')\n+    images = ListBlock(ImageBlock())\n+\n+    panels = [\n+        FieldRowPanel([\n+            FieldPanel('start'),\n+            FieldPanel('end'),\n+        ]),\n+        StreamFieldPanel('images', label_position=StreamFieldPanel.ABOVE),\n+    ]\n+\n+    class Meta:\n+        icon = 'date'\n+        label = 'Événement'\n+\n+\n+# This class is for customising the block type name.\n+class MediaBlock(EmbedBlock):\n+    class Meta:\n+        icon = 'media'\n+        label = 'Média'\n+\n+\n+class Article(Page):\n+    body = StreamField([\n+        ('title', TitleBlock()),\n+        ('text', TextBlock()),\n+        ('image', ImageBlock()),\n+        ('event', EventBlock()),\n+        ('media', MediaBlock()),\n+    ])\n+    \n+    content_panels = Page.content_panels + [\n+        StreamFieldPanel('body'),\n+    ]\n+```\n+\n+As you can see, we do not have to specify a layout,\n+by default it uses `SIMPLE`:\n+\n+![Simple StreamField](026-data/streamfield-simple.png)\n+\n+The action bar (move, duplicate & delete) is visible when the block has focus\n+or the mouse goes over it. Below it lies the block type. To avoid collisions,\n+all fields end before that action bar, so the inner width of the block\n+is reduced a bit. In case the width reduction poses is an issue for users,\n+switch to a `COLLAPSIBLE` block instead.\n+\n+The vertical bar containing the block icon shows an open hand pointer when\n+the mouse goes over it, and it can be grabbed to drag the block\n+to a new position:\n+\n+![Drag simple StreamField](026-data/streamfield-simple-drag.png)\n+\n+### `COLLAPSIBLE` `StreamField`\n+\n+The models are the same, except that we use\n+`form_layout = CharBlock.COLLAPSIBLE` in each `Block` `Meta`.\n+There is no way to set the layout in `StreamFieldPanel`, and that’s on purpose:\n+switching to `COLLAPSIBLE` must be considered for each block type.\n+Here, all blocks are made `COLLAPSIBLE` for demonstration only.\n+\n+As you will read later in that document, it is possible to mix `SIMPLE`\n+with `COLLAPSIBLE` blocks within the same `StreamField`.\n+\n+```python\n+# models.py\n+\n+from wagtail.admin.edit_handlers import (\n+    FieldPanel, FieldRowPanel, StreamFieldPanel,\n+)\n+from wagtail.core.blocks import (\n+    CharBlock, RichTextBlock, StructBlock, ChoiceBlock, DateBlock, ListBlock,\n+    EmbedBlock,\n+)\n+from wagtail.core.fields import StreamField\n+from wagtail.core.models import Page\n+from wagtail.images.blocks import ImageChooserBlock\n+from wagtail.images.edit_handlers import ImageChooserPanel\n+\n+\n+class TitleBlock(CharBlock):\n+    class Meta:\n+        icon = 'header'\n+        label = 'Titre'\n+        form_classname = 'full title'\n+        form_layout = CharBlock.COLLAPSIBLE\n+\n+\n+class TextBlock(RichTextBlock):\n+    class Meta:\n+        icon = 'align-justify'\n+        label = 'Texte'\n+        form_classname = 'full'\n+        form_layout = CharBlock.COLLAPSIBLE\n+\n+\n+class ImageBlock(StructBlock):\n+    image = ImageChooserBlock()\n+    format = ChoiceBlock(choices=[('left', 'Alignée à gauche'),\n+                                  ('center', 'Centrée'),\n+                                  ('right', 'Alignée à droite')])\n+    \n+    panels = [\n+        ImageChooserPanel('image', label_position=ImageChooserPanel.HIDDEN),\n+        FieldPanel('format'),\n+    ]\n+    \n+    class Meta:\n+        icon = 'image'\n+        label = 'Image'\n+        form_layout = CharBlock.COLLAPSIBLE\n+\n+\n+class EventBlock(StructBlock):\n+    start = DateBlock(label='Début')\n+    end = DateBlock(required=False, label='Fin')\n+    images = ListBlock(ImageBlock())\n+\n+    panels = [\n+        FieldRowPanel([\n+            FieldPanel('start'),\n+            FieldPanel('end'),\n+        ]),\n+        StreamFieldPanel('images', label_position=StreamFieldPanel.ABOVE),\n+    ]\n+\n+    class Meta:\n+        icon = 'date'\n+        label = 'Événement'\n+        form_layout = CharBlock.COLLAPSIBLE\n+\n+\n+# This class is for customising the block type name.\n+class MediaBlock(EmbedBlock):\n+    class Meta:\n+        icon = 'media'\n+        label = 'Média'\n+        form_layout = CharBlock.COLLAPSIBLE\n+\n+\n+class Article(Page):\n+    body = StreamField([\n+        ('title', TitleBlock()),\n+        ('text', TextBlock()),\n+        ('image', ImageBlock()),\n+        ('event', EventBlock()),\n+        ('media', MediaBlock()),\n+    ])\n+    \n+    content_panels = Page.content_panels + [\n+        StreamFieldPanel('body'),\n+    ]\n+```\n+\n+![Collapsible StreamField](026-data/streamfield-collapsible.png)\n+\n+A truncated abstract of the block is displayed in the horizontal bar. Its data\n+is dynamically updated from the first readable input. Optionally, we’ll allow\n+developers to define it in Python, which will be called via AJAX.\n+\n+Like with `SIMPLE` layouts, `COLLAPSIBLE` blocks have actions that only show\n+when it has focus or when the mouse is over it.\n+\n+It can also be grabbed by its horizontal bar: \n+\n+![Drag collapsible StreamField](026-data/streamfield-collapsible-drag.png)\n+\n+A single click on the horizontal bar without dragging opens the block: \n+\n+![Open collapsible StreamField](026-data/streamfield-collapsible-open.png)\n+\n+### Mix `SIMPLE` & `COLLAPSIBLE` in `StreamField`\n+\n+Here, only `EventBlock` is made collapsible,\n+ending up with a mix of block layouts.\n+\n+```python\n+# models.py\n+\n+from wagtail.admin.edit_handlers import (\n+    FieldPanel, FieldRowPanel, StreamFieldPanel,\n+)\n+from wagtail.core.blocks import (\n+    CharBlock, RichTextBlock, StructBlock, ChoiceBlock, DateBlock, ListBlock,\n+    EmbedBlock,\n+)\n+from wagtail.core.fields import StreamField\n+from wagtail.core.models import Page\n+from wagtail.images.blocks import ImageChooserBlock\n+from wagtail.images.edit_handlers import ImageChooserPanel\n+\n+\n+class TitleBlock(CharBlock):\n+    class Meta:\n+        icon = 'header'\n+        label = 'Titre'\n+        form_classname = 'full title'\n+\n+\n+class TextBlock(RichTextBlock):\n+    class Meta:\n+        icon = 'align-justify'\n+        label = 'Texte'\n+        form_classname = 'full'\n+\n+\n+class ImageBlock(StructBlock):\n+    image = ImageChooserBlock()\n+    format = ChoiceBlock(choices=[('left', 'Alignée à gauche'),\n+                                  ('center', 'Centrée'),\n+                                  ('right', 'Alignée à droite')])\n+    \n+    panels = [\n+        ImageChooserPanel('image', label_position=ImageChooserPanel.HIDDEN),\n+        FieldPanel('format'),\n+    ]\n+    \n+    class Meta:\n+        icon = 'image'\n+        label = 'Image'\n+\n+\n+class EventBlock(StructBlock):\n+    start = DateBlock(label='Début')\n+    end = DateBlock(required=False, label='Fin')\n+    images = ListBlock(ImageBlock())\n+\n+    panels = [\n+        FieldRowPanel([\n+            FieldPanel('start'),\n+            FieldPanel('end'),\n+        ]),\n+        StreamFieldPanel('images', label_position=StreamFieldPanel.ABOVE),\n+    ]\n+\n+    class Meta:\n+        icon = 'date'\n+        label = 'Événement'\n+\n+\n+# This class is for customising the block type name.\n+class MediaBlock(EmbedBlock):\n+    class Meta:\n+        icon = 'media'\n+        label = 'Média'\n+        form_layout = CharBlock.COLLAPSIBLE\n+\n+\n+class Article(Page):\n+    body = StreamField([\n+        ('title', TitleBlock()),\n+        ('text', TextBlock()),\n+        ('image', ImageBlock()),\n+        ('event', EventBlock()),\n+        ('media', MediaBlock()),\n+    ])\n+    \n+    content_panels = Page.content_panels + [\n+        StreamFieldPanel('body'),\n+    ]\n+```\n+\n+![Mixed StreamField](026-data/streamfield-mixed.png)\n+\n+### `SIMPLE` `InlinePanel`\n+\n+```python\n+# models.py\n+\n+from django.conf import settings\n+from django.db.models import ForeignKey, PROTECT, CharField\n+from modelcluster.fields import ParentalKey\n+from wagtail.admin.edit_handlers import InlinePanel\n+from wagtail.core.models import Page, Orderable\n+from wagtail.images.edit_handlers import ImageChooserPanel\n+\n+\n+class CarouselImage(Orderable):\n+    page = ParentalKey('wagtailcore.Page', related_name='carousel_images')\n+    image = ForeignKey(settings.WAGTAILIMAGES_IMAGE_MODEL, related_name='+',\n+                       on_delete=PROTECT)\n+    format = CharField(max_length=10, choices=[('left', 'Alignée à gauche'),\n+                                               ('center', 'Centrée'),\n+                                               ('right', 'Alignée à droite')])\n+\n+    panels = [\n+        ImageChooserPanel('image', label_position=ImageChooserPanel.HIDDEN),\n+        \n+    ]\n+\n+    class Meta:\n+        verbose_name = 'image de carrousel'\n+        verbose_name_plural = 'images de carrousel'\n+\n+\n+class Article(Page):\n+    content_panels = Page.content_panels + [\n+        InlinePanel('carousel_images', heading='Carrousel'),\n+    ]\n+```\n+\n+Like with `SIMPLE` `StreamField`, it is possible to grab each item using\n+the vertical bar, here with a grip icon.\n+\n+![Simple InlinePanel](026-data/inlinepanel-simple.png)\n+\n+In case the inline model doesn’t inherit from `Orderable`,\n+these interactions are removed:\n+- drag-and-drop\n+- move arrows\n+- all “+” buttons except the last one.\n+\n+![Unsortable simple InlinePanel](026-data/inlinepanel-simple-unsortable.png)\n+\n+### `COLLAPSIBLE` `InlinePanel`\n+\n+Same as `SIMPLE`, except we pass `layout=InlinePanel.COLLAPSIBLE` when creating\n+the inline panel.\n+\n+```python\n+# models.py\n+\n+from django.conf import settings\n+from django.db.models import ForeignKey, PROTECT, CharField\n+from modelcluster.fields import ParentalKey\n+from wagtail.admin.edit_handlers import InlinePanel\n+from wagtail.core.models import Page, Orderable\n+from wagtail.images.edit_handlers import ImageChooserPanel\n+\n+\n+class CarouselImage(Orderable):\n+    page = ParentalKey('wagtailcore.Page', related_name='carousel_images')\n+    image = ForeignKey(settings.WAGTAILIMAGES_IMAGE_MODEL, related_name='+',\n+                       on_delete=PROTECT)\n+    format = CharField(max_length=10, choices=[('left', 'Alignée à gauche'),\n+                                               ('center', 'Centrée'),\n+                                               ('right', 'Alignée à droite')])\n+\n+    panels = [\n+        ImageChooserPanel('image', label_position=ImageChooserPanel.HIDDEN),\n+        \n+    ]\n+\n+    class Meta:\n+        verbose_name = 'image de carrousel'\n+        verbose_name_plural = 'images de carrousel'\n+\n+\n+class Article(Page):\n+    content_panels = Page.content_panels + [\n+        InlinePanel('carousel_images', heading='Carrousel',\n+                    layout=InlinePanel.COLLAPSIBLE),\n+    ]\n+```\n+\n+![Open collapsible InlinePanel](026-data/inlinepanel-collapsible-open.png)\n+\n+In case the inline model doesn’t inherit from `Orderable`,\n+these interactions are removed:\n+- drag-and-drop\n+- move arrows\n+- all “+” buttons except the last one.\n+\n+![Open unsortable collapsible InlinePanel](026-data/inlinepanel-collapsible-open-unsortable.png)\n+\n+## Responsiveness\n+\n+It is very tricky to create a StreamField interface that would work\n+flawlessly on mobile phones. The main reason is that multiple levels of blocks\n+can be nested. The `SIMPLE` layout is out of the question on mobile, due to the\n+decreased width of the block content caused by the vertical bar\n+and the action bar.\n+\n+The mobile version of `StreamField` and `InlinePanel` will always use\n+the `COLLAPSIBLE` layout, since it is the only one working great even\n+without nesting.\n+\n+Switching between `SIMPLE` and `COLLAPSIBLE` will therefore have to be\n+`SASS`-only for optimal performance.","path":"text/026-new-streamfield-and-inlinepanel-uis.md","position":493,"original_position":493,"commit_id":"f8b3a6fe5ad5d82e96dfc666933673512c111d81","original_commit_id":"f8b3a6fe5ad5d82e96dfc666933673512c111d81","user":{"login":"thibaudcolas","id":877585,"avatar_url":"https://avatars1.githubusercontent.com/u/877585?v=4","gravatar_id":"","url":"https://api.github.com/users/thibaudcolas","html_url":"https://github.com/thibaudcolas","followers_url":"https://api.github.com/users/thibaudcolas/followers","following_url":"https://api.github.com/users/thibaudcolas/following{/other_user}","gists_url":"https://api.github.com/users/thibaudcolas/gists{/gist_id}","starred_url":"https://api.github.com/users/thibaudcolas/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/thibaudcolas/subscriptions","organizations_url":"https://api.github.com/users/thibaudcolas/orgs","repos_url":"https://api.github.com/users/thibaudcolas/repos","events_url":"https://api.github.com/users/thibaudcolas/events{/privacy}","received_events_url":"https://api.github.com/users/thibaudcolas/received_events","type":"User","site_admin":false},"body":"👍 gotcha.","created_at":"2018-05-13T11:54:27Z","updated_at":"2018-05-13T11:54:27Z","html_url":"https://github.com/wagtail/rfcs/pull/26#discussion_r187798116","pull_request_url":"https://api.github.com/repos/wagtail/rfcs/pulls/26","author_association":"MEMBER","_links":{"self":{"href":"https://api.github.com/repos/wagtail/rfcs/pulls/comments/187798116"},"html":{"href":"https://github.com/wagtail/rfcs/pull/26#discussion_r187798116"},"pull_request":{"href":"https://api.github.com/repos/wagtail/rfcs/pulls/26"}},"in_reply_to_id":187745768},"pull_request":{"url":"https://api.github.com/repos/wagtail/rfcs/pulls/26","id":187342336,"html_url":"https://github.com/wagtail/rfcs/pull/26","diff_url":"https://github.com/wagtail/rfcs/pull/26.diff","patch_url":"https://github.com/wagtail/rfcs/pull/26.patch","issue_url":"https://api.github.com/repos/wagtail/rfcs/issues/26","number":26,"state":"open","locked":false,"title":"RFC 026: New StreamField & InlinePanel UIs.","user":{"login":"BertrandBordage","id":1119169,"avatar_url":"https://avatars1.githubusercontent.com/u/1119169?v=4","gravatar_id":"","url":"https://api.github.com/users/BertrandBordage","html_url":"https://github.com/BertrandBordage","followers_url":"https://api.github.com/users/BertrandBordage/followers","following_url":"https://api.github.com/users/BertrandBordage/following{/other_user}","gists_url":"https://api.github.com/users/BertrandBordage/gists{/gist_id}","starred_url":"https://api.github.com/users/BertrandBordage/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/BertrandBordage/subscriptions","organizations_url":"https://api.github.com/users/BertrandBordage/orgs","repos_url":"https://api.github.com/users/BertrandBordage/repos","events_url":"https://api.github.com/users/BertrandBordage/events{/privacy}","received_events_url":"https://api.github.com/users/BertrandBordage/received_events","type":"User","site_admin":false},"body":"[Rendered](https://github.com/wagtail/rfcs/blob/026-new-streamfield-and-inlinepanel-uis/text/026-new-streamfield-and-inlinepanel-uis.md)","created_at":"2018-05-11T00:48:33Z","updated_at":"2018-05-13T11:54:27Z","closed_at":null,"merged_at":null,"merge_commit_sha":"13e01d7d82eacaceb7138e4a503827005f65365b","assignee":null,"assignees":[],"requested_reviewers":[{"login":"tmsndrs","id":7290588,"avatar_url":"https://avatars1.githubusercontent.com/u/7290588?v=4","gravatar_id":"","url":"https://api.github.com/users/tmsndrs","html_url":"https://github.com/tmsndrs","followers_url":"https://api.github.com/users/tmsndrs/followers","following_url":"https://api.github.com/users/tmsndrs/following{/other_user}","gists_url":"https://api.github.com/users/tmsndrs/gists{/gist_id}","starred_url":"https://api.github.com/users/tmsndrs/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/tmsndrs/subscriptions","organizations_url":"https://api.github.com/users/tmsndrs/orgs","repos_url":"https://api.github.com/users/tmsndrs/repos","events_url":"https://api.github.com/users/tmsndrs/events{/privacy}","received_events_url":"https://api.github.com/users/tmsndrs/received_events","type":"User","site_admin":false}],"requested_teams":[],"labels":[],"milestone":null,"commits_url":"https://api.github.com/repos/wagtail/rfcs/pulls/26/commits","review_comments_url":"https://api.github.com/repos/wagtail/rfcs/pulls/26/comments","review_comment_url":"https://api.github.com/repos/wagtail/rfcs/pulls/comments{/number}","comments_url":"https://api.github.com/repos/wagtail/rfcs/issues/26/comments","statuses_url":"https://api.github.com/repos/wagtail/rfcs/statuses/f8b3a6fe5ad5d82e96dfc666933673512c111d81","head":{"label":"wagtail:026-new-streamfield-and-inlinepanel-uis","ref":"026-new-streamfield-and-inlinepanel-uis","sha":"f8b3a6fe5ad5d82e96dfc666933673512c111d81","user":{"login":"wagtail","id":23708009,"avatar_url":"https://avatars3.githubusercontent.com/u/23708009?v=4","gravatar_id":"","url":"https://api.github.com/users/wagtail","html_url":"https://github.com/wagtail","followers_url":"https://api.github.com/users/wagtail/followers","following_url":"https://api.github.com/users/wagtail/following{/other_user}","gists_url":"https://api.github.com/users/wagtail/gists{/gist_id}","starred_url":"https://api.github.com/users/wagtail/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/wagtail/subscriptions","organizations_url":"https://api.github.com/users/wagtail/orgs","repos_url":"https://api.github.com/users/wagtail/repos","events_url":"https://api.github.com/users/wagtail/events{/privacy}","received_events_url":"https://api.github.com/users/wagtail/received_events","type":"Organization","site_admin":false},"repo":{"id":40007822,"name":"rfcs","full_name":"wagtail/rfcs","owner":{"login":"wagtail","id":23708009,"avatar_url":"https://avatars3.githubusercontent.com/u/23708009?v=4","gravatar_id":"","url":"https://api.github.com/users/wagtail","html_url":"https://github.com/wagtail","followers_url":"https://api.github.com/users/wagtail/followers","following_url":"https://api.github.com/users/wagtail/following{/other_user}","gists_url":"https://api.github.com/users/wagtail/gists{/gist_id}","starred_url":"https://api.github.com/users/wagtail/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/wagtail/subscriptions","organizations_url":"https://api.github.com/users/wagtail/orgs","repos_url":"https://api.github.com/users/wagtail/repos","events_url":"https://api.github.com/users/wagtail/events{/privacy}","received_events_url":"https://api.github.com/users/wagtail/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/wagtail/rfcs","description":"Wagtail RFCs","fork":false,"url":"https://api.github.com/repos/wagtail/rfcs","forks_url":"https://api.github.com/repos/wagtail/rfcs/forks","keys_url":"https://api.github.com/repos/wagtail/rfcs/keys{/key_id}","collaborators_url":"https://api.github.com/repos/wagtail/rfcs/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/wagtail/rfcs/teams","hooks_url":"https://api.github.com/repos/wagtail/rfcs/hooks","issue_events_url":"https://api.github.com/repos/wagtail/rfcs/issues/events{/number}","events_url":"https://api.github.com/repos/wagtail/rfcs/events","assignees_url":"https://api.github.com/repos/wagtail/rfcs/assignees{/user}","branches_url":"https://api.github.com/repos/wagtail/rfcs/branches{/branch}","tags_url":"https://api.github.com/repos/wagtail/rfcs/tags","blobs_url":"https://api.github.com/repos/wagtail/rfcs/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/wagtail/rfcs/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/wagtail/rfcs/git/refs{/sha}","trees_url":"https://api.github.com/repos/wagtail/rfcs/git/trees{/sha}","statuses_url":"https://api.github.com/repos/wagtail/rfcs/statuses/{sha}","languages_url":"https://api.github.com/repos/wagtail/rfcs/languages","stargazers_url":"https://api.github.com/repos/wagtail/rfcs/stargazers","contributors_url":"https://api.github.com/repos/wagtail/rfcs/contributors","subscribers_url":"https://api.github.com/repos/wagtail/rfcs/subscribers","subscription_url":"https://api.github.com/repos/wagtail/rfcs/subscription","commits_url":"https://api.github.com/repos/wagtail/rfcs/commits{/sha}","git_commits_url":"https://api.github.com/repos/wagtail/rfcs/git/commits{/sha}","comments_url":"https://api.github.com/repos/wagtail/rfcs/comments{/number}","issue_comment_url":"https://api.github.com/repos/wagtail/rfcs/issues/comments{/number}","contents_url":"https://api.github.com/repos/wagtail/rfcs/contents/{+path}","compare_url":"https://api.github.com/repos/wagtail/rfcs/compare/{base}...{head}","merges_url":"https://api.github.com/repos/wagtail/rfcs/merges","archive_url":"https://api.github.com/repos/wagtail/rfcs/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/wagtail/rfcs/downloads","issues_url":"https://api.github.com/repos/wagtail/rfcs/issues{/number}","pulls_url":"https://api.github.com/repos/wagtail/rfcs/pulls{/number}","milestones_url":"https://api.github.com/repos/wagtail/rfcs/milestones{/number}","notifications_url":"https://api.github.com/repos/wagtail/rfcs/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/wagtail/rfcs/labels{/name}","releases_url":"https://api.github.com/repos/wagtail/rfcs/releases{/id}","deployments_url":"https://api.github.com/repos/wagtail/rfcs/deployments","created_at":"2015-07-31T13:58:46Z","updated_at":"2018-05-01T08:57:26Z","pushed_at":"2018-05-11T13:16:59Z","git_url":"git://github.com/wagtail/rfcs.git","ssh_url":"git@github.com:wagtail/rfcs.git","clone_url":"https://github.com/wagtail/rfcs.git","svn_url":"https://github.com/wagtail/rfcs","homepage":"","size":1806,"stargazers_count":11,"watchers_count":11,"language":null,"has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":14,"mirror_url":null,"archived":false,"open_issues_count":8,"license":{"key":"mit","name":"MIT License","spdx_id":"MIT","url":"https://api.github.com/licenses/mit"},"forks":14,"open_issues":8,"watchers":11,"default_branch":"master"}},"base":{"label":"wagtail:master","ref":"master","sha":"6d692232b6fe0c661a03a27c24296807387b6fa9","user":{"login":"wagtail","id":23708009,"avatar_url":"https://avatars3.githubusercontent.com/u/23708009?v=4","gravatar_id":"","url":"https://api.github.com/users/wagtail","html_url":"https://github.com/wagtail","followers_url":"https://api.github.com/users/wagtail/followers","following_url":"https://api.github.com/users/wagtail/following{/other_user}","gists_url":"https://api.github.com/users/wagtail/gists{/gist_id}","starred_url":"https://api.github.com/users/wagtail/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/wagtail/subscriptions","organizations_url":"https://api.github.com/users/wagtail/orgs","repos_url":"https://api.github.com/users/wagtail/repos","events_url":"https://api.github.com/users/wagtail/events{/privacy}","received_events_url":"https://api.github.com/users/wagtail/received_events","type":"Organization","site_admin":false},"repo":{"id":40007822,"name":"rfcs","full_name":"wagtail/rfcs","owner":{"login":"wagtail","id":23708009,"avatar_url":"https://avatars3.githubusercontent.com/u/23708009?v=4","gravatar_id":"","url":"https://api.github.com/users/wagtail","html_url":"https://github.com/wagtail","followers_url":"https://api.github.com/users/wagtail/followers","following_url":"https://api.github.com/users/wagtail/following{/other_user}","gists_url":"https://api.github.com/users/wagtail/gists{/gist_id}","starred_url":"https://api.github.com/users/wagtail/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/wagtail/subscriptions","organizations_url":"https://api.github.com/users/wagtail/orgs","repos_url":"https://api.github.com/users/wagtail/repos","events_url":"https://api.github.com/users/wagtail/events{/privacy}","received_events_url":"https://api.github.com/users/wagtail/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/wagtail/rfcs","description":"Wagtail RFCs","fork":false,"url":"https://api.github.com/repos/wagtail/rfcs","forks_url":"https://api.github.com/repos/wagtail/rfcs/forks","keys_url":"https://api.github.com/repos/wagtail/rfcs/keys{/key_id}","collaborators_url":"https://api.github.com/repos/wagtail/rfcs/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/wagtail/rfcs/teams","hooks_url":"https://api.github.com/repos/wagtail/rfcs/hooks","issue_events_url":"https://api.github.com/repos/wagtail/rfcs/issues/events{/number}","events_url":"https://api.github.com/repos/wagtail/rfcs/events","assignees_url":"https://api.github.com/repos/wagtail/rfcs/assignees{/user}","branches_url":"https://api.github.com/repos/wagtail/rfcs/branches{/branch}","tags_url":"https://api.github.com/repos/wagtail/rfcs/tags","blobs_url":"https://api.github.com/repos/wagtail/rfcs/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/wagtail/rfcs/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/wagtail/rfcs/git/refs{/sha}","trees_url":"https://api.github.com/repos/wagtail/rfcs/git/trees{/sha}","statuses_url":"https://api.github.com/repos/wagtail/rfcs/statuses/{sha}","languages_url":"https://api.github.com/repos/wagtail/rfcs/languages","stargazers_url":"https://api.github.com/repos/wagtail/rfcs/stargazers","contributors_url":"https://api.github.com/repos/wagtail/rfcs/contributors","subscribers_url":"https://api.github.com/repos/wagtail/rfcs/subscribers","subscription_url":"https://api.github.com/repos/wagtail/rfcs/subscription","commits_url":"https://api.github.com/repos/wagtail/rfcs/commits{/sha}","git_commits_url":"https://api.github.com/repos/wagtail/rfcs/git/commits{/sha}","comments_url":"https://api.github.com/repos/wagtail/rfcs/comments{/number}","issue_comment_url":"https://api.github.com/repos/wagtail/rfcs/issues/comments{/number}","contents_url":"https://api.github.com/repos/wagtail/rfcs/contents/{+path}","compare_url":"https://api.github.com/repos/wagtail/rfcs/compare/{base}...{head}","merges_url":"https://api.github.com/repos/wagtail/rfcs/merges","archive_url":"https://api.github.com/repos/wagtail/rfcs/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/wagtail/rfcs/downloads","issues_url":"https://api.github.com/repos/wagtail/rfcs/issues{/number}","pulls_url":"https://api.github.com/repos/wagtail/rfcs/pulls{/number}","milestones_url":"https://api.github.com/repos/wagtail/rfcs/milestones{/number}","notifications_url":"https://api.github.com/repos/wagtail/rfcs/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/wagtail/rfcs/labels{/name}","releases_url":"https://api.github.com/repos/wagtail/rfcs/releases{/id}","deployments_url":"https://api.github.com/repos/wagtail/rfcs/deployments","created_at":"2015-07-31T13:58:46Z","updated_at":"2018-05-01T08:57:26Z","pushed_at":"2018-05-11T13:16:59Z","git_url":"git://github.com/wagtail/rfcs.git","ssh_url":"git@github.com:wagtail/rfcs.git","clone_url":"https://github.com/wagtail/rfcs.git","svn_url":"https://github.com/wagtail/rfcs","homepage":"","size":1806,"stargazers_count":11,"watchers_count":11,"language":null,"has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":14,"mirror_url":null,"archived":false,"open_issues_count":8,"license":{"key":"mit","name":"MIT License","spdx_id":"MIT","url":"https://api.github.com/licenses/mit"},"forks":14,"open_issues":8,"watchers":11,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/wagtail/rfcs/pulls/26"},"html":{"href":"https://github.com/wagtail/rfcs/pull/26"},"issue":{"href":"https://api.github.com/repos/wagtail/rfcs/issues/26"},"comments":{"href":"https://api.github.com/repos/wagtail/rfcs/issues/26/comments"},"review_comments":{"href":"https://api.github.com/repos/wagtail/rfcs/pulls/26/comments"},"review_comment":{"href":"https://api.github.com/repos/wagtail/rfcs/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/wagtail/rfcs/pulls/26/commits"},"statuses":{"href":"https://api.github.com/repos/wagtail/rfcs/statuses/f8b3a6fe5ad5d82e96dfc666933673512c111d81"}},"author_association":"MEMBER"}}
{"actor":{"display_login":"thibaudcolas"}}