decaporg / decaporg/decap-cms

Image widgets added inside a markdown widget field are not shown in preview

Open
#6,785 0 comments 0 reactions 0 assignees View on GitHub
area: ui/editor/preview-pane type: bug
Dominant language
JavaScript
Stars
19.4k
Forks
3.1k
Avg merge
1d 14h
Merged PRs (30d)
9

Description

## Describe the bug

No preview shown when adding an image in the markdown editor

## To Reproduce

Steps to reproduce the behavior. For example:
1. Go to 'markdown editor' (markdown widget)
2. Click on 'add component' button
3. Select 'Image'
4. Choose an image to insert
5. Add title and alt text for the image
6. Note that no preview of the image is shown and warning shown in chrome developer tools. see below.

Chrome developer console shows the following warning

```
Sent invalid data to remark. Plugin: image. Value: ![alt text](/images/testing.jpg "testing"). Data: {"image":"/images/testing.jpg","alt":"alt text","title":"testing"}
(anonymous) @ netlify-cms-2.0.0.js:654
(anonymous) @ netlify-cms-2.0.0.js:646
e.exports @ netlify-cms-2.0.0.js:646
w.parse @ netlify-cms-2.0.0.js:639
O @ netlify-cms-2.0.0.js:54
t.markdownToHtml @ netlify-cms-2.0.0.js:54
render @ netlify-cms-2.0.0.js:658
Fa @ netlify-cms-2.0.0.js:188
Na @ netlify-cms-2.0.0.js:188
gs @ netlify-cms-2.0.0.js:188
ul @ netlify-cms-2.0.0.js:188
sl @ netlify-cms-2.0.0.js:188
Js @ netlify-cms-2.0.0.js:188
(anonymous) @ netlify-cms-2.0.0.js:188
t.unstable_runWithPriority @ netlify-cms-2.0.0.js:196
qi @ netlify-cms-2.0.0.js:188
Vi @ netlify-cms-2.0.0.js:188
$i @ netlify-cms-2.0.0.js:188
el @ netlify-cms-2.0.0.js:188
notify @ netlify-cms-2.0.0.js:28
notifyNestedSubs @ netlify-cms-2.0.0.js:28
i @ netlify-cms-2.0.0.js:28
v @ netlify-cms-2.0.0.js:48
(anonymous) @ netlify-cms-2.0.0.js:75
(anonymous) @ netlify-cms-2.0.0.js:220
n. @ netlify-cms-2.0.0.js:28
(anonymous) @ netlify-cms-2.0.0.js:280
onChange @ netlify-cms-2.0.0.js:280
onChange @ netlify-cms-2.0.0.js:298
(anonymous) @ netlify-cms-2.0.0.js:631
y @ netlify-cms-2.0.0.js:48
x @ netlify-cms-2.0.0.js:48
w @ netlify-cms-2.0.0.js:48
setTimeout (async)
b @ netlify-cms-2.0.0.js:48
k @ netlify-cms-2.0.0.js:48
(anonymous) @ netlify-cms-2.0.0.js:631
value @ netlify-cms-2.0.0.js:58
n @ netlify-cms-2.0.0.js:58
value @ netlify-cms-2.0.0.js:16
(anonymous) @ netlify-cms-2.0.0.js:16
Promise.then (async)
value @ netlify-cms-2.0.0.js:16
value @ netlify-cms-2.0.0.js:58
tt.setData @ netlify-cms-2.0.0.js:16
value @ netlify-cms-2.0.0.js:16
value @ netlify-cms-2.0.0.js:58
t @ netlify-cms-2.0.0.js:16
u @ netlify-cms-2.0.0.js:16
t @ netlify-cms-2.0.0.js:16
u @ netlify-cms-2.0.0.js:16
t @ netlify-cms-2.0.0.js:16
u @ netlify-cms-2.0.0.js:16
t @ netlify-cms-2.0.0.js:16
u @ netlify-cms-2.0.0.js:16
value @ netlify-cms-2.0.0.js:16
value @ netlify-cms-2.0.0.js:16
r @ netlify-cms-2.0.0.js:16
(anonymous) @ netlify-cms-2.0.0.js:16
Ve.withoutSaving @ netlify-cms-2.0.0.js:16
value @ netlify-cms-2.0.0.js:16
value @ netlify-cms-2.0.0.js:58
t @ netlify-cms-2.0.0.js:16
u @ netlify-cms-2.0.0.js:16
t @ netlify-cms-2.0.0.js:16
u @ netlify-cms-2.0.0.js:16
t @ netlify-cms-2.0.0.js:16
u @ netlify-cms-2.0.0.js:16
t @ netlify-cms-2.0.0.js:16
u @ netlify-cms-2.0.0.js:16
value @ netlify-cms-2.0.0.js:16
value @ netlify-cms-2.0.0.js:16
r @ netlify-cms-2.0.0.js:16
Ve.save @ netlify-cms-2.0.0.js:16
value @ netlify-cms-2.0.0.js:16
value @ netlify-cms-2.0.0.js:58
t @ netlify-cms-2.0.0.js:16
u @ netlify-cms-2.0.0.js:16
t @ netlify-cms-2.0.0.js:16
u @ netlify-cms-2.0.0.js:16
t @ netlify-cms-2.0.0.js:16
u @ netlify-cms-2.0.0.js:16
t @ netlify-cms-2.0.0.js:16
u @ netlify-cms-2.0.0.js:16
value @ netlify-cms-2.0.0.js:16
value @ netlify-cms-2.0.0.js:16
r @ netlify-cms-2.0.0.js:16
(anonymous) @ netlify-cms-2.0.0.js:16
value @ netlify-cms-2.0.0.js:16
value @ netlify-cms-2.0.0.js:16
value @ netlify-cms-2.0.0.js:58
Ge.select @ netlify-cms-2.0.0.js:16
value @ netlify-cms-2.0.0.js:16
value @ netlify-cms-2.0.0.js:58
t @ netlify-cms-2.0.0.js:16
u @ netlify-cms-2.0.0.js:16
t @ netlify-cms-2.0.0.js:16
u @ netlify-cms-2.0.0.js:16
t @ netlify-cms-2.0.0.js:16
u @ netlify-cms-2.0.0.js:16
t @ netlify-cms-2.0.0.js:16
u @ netlify-cms-2.0.0.js:16
value @ netlify-cms-2.0.0.js:16
value @ netlify-cms-2.0.0.js:16
r @ netlify-cms-2.0.0.js:16
(anonymous) @ netlify-cms-2.0.0.js:16
Ve.withoutMerging @ netlify-cms-2.0.0.js:16
value @ netlify-cms-2.0.0.js:16
value @ netlify-cms-2.0.0.js:58
t @ netlify-cms-2.0.0.js:16
u @ netlify-cms-2.0.0.js:16
t @ netlify-cms-2.0.0.js:16
u @ netlify-cms-2.0.0.js:16
t @ netlify-cms-2.0.0.js:16
u @ netlify-cms-2.0.0.js:16
t @ netlify-cms-2.0.0.js:16
u @ netlify-cms-2.0.0.js:16
value @ netlify-cms-2.0.0.js:16
value @ netlify-cms-2.0.0.js:16
r @ netlify-cms-2.0.0.js:16
Ge.snapshotSelection @ netlify-cms-2.0.0.js:16
value @ netlify-cms-2.0.0.js:16
value @ netlify-cms-2.0.0.js:58
t @ netlify-cms-2.0.0.js:16
u @ netlify-cms-2.0.0.js:16
t @ netlify-cms-2.0.0.js:16
u @ netlify-cms-2.0.0.js:16
t @ netlify-cms-2.0.0.js:16
u @ netlify-cms-2.0.0.js:16
t @ netlify-cms-2.0.0.js:16
u @ netlify-cms-2.0.0.js:16
value @ netlify-cms-2.0.0.js:16
value @ netlify-cms-2.0.0.js:16
r @ netlify-cms-2.0.0.js:16
deleteAtRange @ netlify-cms-2.0.0.js:16
value @ netlify-cms-2.0.0.js:16
value @ netlify-cms-2.0.0.js:58
t @ netlify-cms-2.0.0.js:16
u @ netlify-cms-2.0.0.js:16
t @ netlify-cms-2.0.0.js:16
u @ netlify-cms-2.0.0.js:16
t @ netlify-cms-2.0.0.js:16
u @ netlify-cms-2.0.0.js:16
t @ netlify-cms-2.0.0.js:16
u @ netlify-cms-2.0.0.js:16
value @ netlify-cms-2.0.0.js:16
value @ netlify-cms-2.0.0.js:16
r @ netlify-cms-2.0.0.js:16
deleteBackwardAtRange @ netlify-cms-2.0.0.js:16
value @ netlify-cms-2.0.0.js:16
value @ netlify-cms-2.0.0.js:58
t @ netlify-cms-2.0.0.js:16
u @ netlify-cms-2.0.0.js:16
t @ netlify-cms-2.0.0.js:16
u @ netlify-cms-2.0.0.js:16
t @ netlify-cms-2.0.0.js:16
u @ netlify-cms-2.0.0.js:16
t @ netlify-cms-2.0.0.js:16
u @ netlify-cms-2.0.0.js:16
value @ netlify-cms-2.0.0.js:16
value @ netlify-cms-2.0.0.js:16
r @ netlify-cms-2.0.0.js:16
deleteCharBackwardAtRange @ netlify-cms-2.0.0.js:16
value @ netlify-cms-2.0.0.js:16
value @ netlify-cms-2.0.0.js:58
t @ netlify-cms-2.0.0.js:16
u @ netlify-cms-2.0.0.js:16
t @ netlify-cms-2.0.0.js:16
u @ netlify-cms-2.0.0.js:16
t @ netlify-cms-2.0.0.js:16
u @ netlify-cms-2.0.0.js:16
t @ netlify-cms-2.0.0.js:16
u @ netlify-cms-2.0.0.js:16
value @ netlify-cms-2.0.0.js:16
value @ netlify-cms-2.0.0.js:16
r @ netlify-cms-2.0.0.js:16
_t.deleteCharBackward @ netlify-cms-2.0.0.js:16
value @ netlify-cms-2.0.0.js:16
value @ netlify-cms-2.0.0.js:58
t @ netlify-cms-2.0.0.js:16
u @ netlify-cms-2.0.0.js:16
t @ netlify-cms-2.0.0.js:16
u @ netlify-cms-2.0.0.js:16
t @ netlify-cms-2.0.0.js:16
u @ netlify-cms-2.0.0.js:16
t @ netlify-cms-2.0.0.js:16
u @ netlify-cms-2.0.0.js:16
value @ netlify-cms-2.0.0.js:16
value @ netlify-cms-2.0.0.js:16
r @ netlify-cms-2.0.0.js:16
onKeyDown @ netlify-cms-2.0.0.js:58
u @ netlify-cms-2.0.0.js:16
onKeyDown @ netlify-cms-2.0.0.js:58
u @ netlify-cms-2.0.0.js:16
value @ netlify-cms-2.0.0.js:16
value @ netlify-cms-2.0.0.js:58
onEvent @ netlify-cms-2.0.0.js:58
value @ netlify-cms-2.0.0.js:58
r.handlers.Re.reduce.e. @ netlify-cms-2.0.0.js:58
s @ netlify-cms-2.0.0.js:188
p @ netlify-cms-2.0.0.js:188
(anonymous) @ netlify-cms-2.0.0.js:188
v @ netlify-cms-2.0.0.js:188
at @ netlify-cms-2.0.0.js:188
it @ netlify-cms-2.0.0.js:188
st @ netlify-cms-2.0.0.js:188
pt @ netlify-cms-2.0.0.js:188
N @ netlify-cms-2.0.0.js:188
U @ netlify-cms-2.0.0.js:188
Zt @ netlify-cms-2.0.0.js:188
Xt @ netlify-cms-2.0.0.js:188
t.unstable_runWithPriority @ netlify-cms-2.0.0.js:196
qi @ netlify-cms-2.0.0.js:188
L @ netlify-cms-2.0.0.js:188
Yt @ netlify-cms-2.0.0.js:188
```

## Expected behavior

images (image widgets) added inline should be shown in the preview

## Screenshots

![image](https://github.com/decaporg/decap-cms/assets/128751492/e63e3345-3337-45c3-9abc-0a78707dcbaa)

## Applicable Versions:

- Netlify CMS version: 2.10.192
- Git provider: GitHub
- OS: Pop!_OS 22.04 LTS
- Browser version: Version 112.0.5615.165 (Official Build) (64-bit)
- Node.JS version: v16.13.0

## CMS configuration

config.yml

```
locale: 'sv'
publish_mode: editorial_workflow
display_url: https://redacted.com
backend:
name: github
repo: redacted/redacted.com
branch: main # Branch to update (optional; defaults to master)
base_url: https://redacted.com
auth_endpoint: /api/auth
media_folder: src/images
public_folder: /images
collections:
- name: 'config'
label: 'konfiguration'
files:
- name: 'contact_form'
label: 'Kontakt formulär'
file: 'src/_data/contact_form.json'
widget: "object"
fields:
- name: sv
widget: list
fields:
- { name: subject, widget: string }
- { name: email, widget: string }
- name: en
widget: list
fields:
- { name: subject, widget: string }
- { name: email, widget: string }
- name: default
widget: list
fields:
- { name: subject, widget: string }
- { name: email, widget: string }

- name: 'blog-swedish'
label: 'Blogginlägg (svenska)'
folder: 'src/pages/_cms_content'
create: true
filter: {field: "language", value: "sv"}
summary: '{{day}}/{{month}}/{{year}} {{hour}}:{{minute}} | {{title}}' # optional summary for a tree node, defaults to the inferred title field
view_groups:
- label: År
field: date
# groups items based on the value matched by the pattern
pattern: \d{4}
view_filters:
- label: Utkast
field: draft
pattern: true
slug: '{{slug}}'
editor:
preview: true
nested:
depth: 100 # max depth to show in the collection tree
summary: '{{title}}' # optional summary for a tree node, defaults to the inferred title field
fields:
- { label: 'Language', name: 'language', widget: 'hidden', default: 'sv' }
- { label: 'Datum', name: 'date', widget: 'datetime', date_format: "DD.MM.YYYY", time_format: "HH:mm", format: "YYYY-MM-DDTHH:mmZ", hint: 'Datum som visar när inlägget gjordes. Om datumet och tiden är i framtiden
kommer inlägget att släppas ut på siten först vid den tiden.' }
- { label: 'Utkast', name: 'draft', widget: 'boolean', default: true, hint: 'Inlägget kommer inte att visas på sidan även fast det är publicerat.' }
- { label: 'Visa i flödet', name: 'show_in_flow', widget: 'boolean', default: true, hint: 'Inlägget visas i flödet på hemsidan.' }
- { label: 'Visa som prioriterat tills', name: 'sticky_until', widget: 'datetime', date_format: "DD.MM.YYYY", time_format: "HH:mm", format: "YYYY-MM-DDTHH:mmZ", hint: 'Inlägget visas högst upp i flödet på hemsidan tills denna tidpunkt.' }
- { label: "Huvudbild", name: "image", widget: "image", required: false, choose_url: true, allow_multiple: false, hint: 'Bild som visas högst upp i inlägget och då det visas i flödet på hemsidan. Använd t.ex. **[Squoosh.app](http://squoosh.app)** för att se till att bilden är lagom stor innan du laddar upp den.' }
- { label: 'Titel', name: 'title', widget: 'string', hint: 'Sidans titel som visas i inläggets intro och då det visas i flödet på sidan.' }
- { label: 'Beskrivning', name: 'short_description', widget: 'string', required: false, hint: 'Kort beskrivning av inlägget då det visas i flödet på sidan.' }
- { label: 'Sidinnehåll', name: 'body', widget: 'markdown', sanitize_preview: true, hint: 'Sidans innehåll, Se t.ex. **[markdown cheat-sheet](/markdown-cheat-sheet)** för exempel.' }
- { label: "Taggar", name: "tags", widget: "list", required: false, hint: 'taggar som beskriver innehållet' }
meta: { path: { widget: string, label: 'Path', index_file: 'index', default: "/{{year}/{{month}}/{{}}"} }

- name: 'blog-english'
label: 'Blogginlägg (engelska)'
folder: 'src/pages/_cms_content/en'
create: true
filter: {field: "language", value: "en"}
summary: '{{day}}/{{month}}/{{year}} {{hour}}:{{minute}} | {{title}}' # optional summary for a tree node, defaults to the inferred title field
view_groups:
- label: År
field: date
# groups items based on the value matched by the pattern
pattern: \d{4}
view_filters:
- label: Utkast
field: draft
pattern: true
slug: '{{slug}}'
editor:
preview: true
nested:
depth: 100 # max depth to show in the collection tree
summary: '{{title}}' # optional summary for a tree node, defaults to the inferred title field
fields:
- { label: 'Language', name: 'language', widget: 'hidden', default: 'en' }
- { label: 'Datum', name: 'date', widget: 'datetime', date_format: "DD.MM.YYYY", time_format: "HH:mm", format: "YYYY-MM-DDTHH:mmZ", hint: 'Datum som visar när inlägget gjordes. Om datumet och tiden är i framtiden
kommer inlägget att släppas ut på siten först vid den tiden.' }
- { label: 'Utkast', name: 'draft', widget: 'boolean', default: true, hint: 'Inlägget kommer inte att visas på sidan även fast det är publicerat.' }
- { label: 'Visa i flödet', name: 'show_in_flow', widget: 'boolean', default: true, hint: 'Inlägget visas i flödet på hemsidan.' }
- { label: 'Visa som prioriterat tills', name: 'sticky_until', widget: 'datetime', date_format: "DD.MM.YYYY", time_format: "HH:mm", format: "YYYY-MM-DDTHH:mmZ", hint: 'Inlägget visas högst upp i flödet på hemsidan tills denna tidpunkt.' }
- { label: "Huvudbild", name: "image", widget: "image", required: false, choose_url: true, allow_multiple: false, hint: 'Bild som visas högst upp i inlägget och då det visas i flödet på hemsidan. Använd t.ex. **[Squoosh.app](http://squoosh.app)** för att se till att bilden är lagom stor innan du laddar upp den.' }
- { label: 'Titel', name: 'title', widget: 'string', hint: 'Sidans titel som visas i inläggets intro och då det visas i flödet på sidan.' }
- { label: 'Beskrivning', name: 'short_description', widget: 'string', required: false, hint: 'Kort beskrivning av inlägget då det visas i flödet på sidan.' }
- { label: 'Sidinnehåll', name: 'body', widget: 'markdown', sanitize_preview: true, hint: 'Sidans innehåll, Se t.ex. **[markdown cheat-sheet](/markdown-cheat-sheet)** för exempel.' }
- { label: "Taggar", name: "tags", widget: "list", required: false, hint: 'taggar som beskriver innehållet' }

- name: 'blog-german'
label: 'Blogginlägg (tyska)'
folder: 'src/pages/_cms_content/de'
create: true
filter: {field: "language", value: "de"}
summary: '{{day}}/{{month}}/{{year}} {{hour}}:{{minute}} | {{title}}' # optional summary for a tree node, defaults to the inferred title field
view_groups:
- label: År
field: date
# groups items based on the value matched by the pattern
pattern: \d{4}
view_filters:
- label: Utkast
field: draft
pattern: true
slug: '{{slug}}'
editor:
preview: true
nested:
depth: 100 # max depth to show in the collection tree
summary: '{{title}}' # optional summary for a tree node, defaults to the inferred title field
fields:
- { label: 'Language', name: 'language', widget: 'hidden', default: 'de' }
- { label: 'Datum', name: 'date', widget: 'datetime', date_format: "DD.MM.YYYY", time_format: "HH:mm", format: "YYYY-MM-DDTHH:mmZ", hint: 'Datum som visar när inlägget gjordes. Om datumet och tiden är i framtiden
kommer inlägget att släppas ut på siten först vid den tiden.' }
- { label: 'Utkast', name: 'draft', widget: 'boolean', default: true, hint: 'Inlägget kommer inte att visas på sidan även fast det är publicerat.' }
- { label: 'Visa i flödet', name: 'show_in_flow', widget: 'boolean', default: true, hint: 'Inlägget visas i flödet på hemsidan.' }
- { label: 'Visa som prioriterat tills', name: 'sticky_until', widget: 'datetime', date_format: "DD.MM.YYYY", time_format: "HH:mm", format: "YYYY-MM-DDTHH:mmZ", hint: 'Inlägget visas högst upp i flödet på hemsidan tills denna tidpunkt.' }
- { label: "Huvudbild", name: "image", widget: "image", required: false, choose_url: true, allow_multiple: false, hint: 'Bild som visas högst upp i inlägget och då det visas i flödet på hemsidan. Använd t.ex. **[Squoosh.app](http://squoosh.app)** för att se till att bilden är lagom stor innan du laddar upp den.' }
- { label: 'Titel', name: 'title', widget: 'string', hint: 'Sidans titel som visas i inläggets intro och då det visas i flödet på sidan.' }
- { label: 'Beskrivning', name: 'short_description', widget: 'string', required: false, hint: 'Kort beskrivning av inlägget då det visas i flödet på sidan.' }
- { label: 'Sidinnehåll', name: 'body', widget: 'markdown', sanitize_preview: true, hint: 'Sidans innehåll, Se t.ex. **[markdown cheat-sheet](/markdown-cheat-sheet)** för exempel.' }
- { label: "Taggar", name: "tags", widget: "list", required: false, hint: 'taggar som beskriver innehållet' }

- name: 'blog-finnish'
label: 'Blogginlägg (finska)'
folder: 'src/pages/_cms_content/fi'
create: true
filter: {field: "language", value: "fi"}
summary: '{{day}}/{{month}}/{{year}} {{hour}}:{{minute}} | {{title}}' # optional summary for a tree node, defaults to the inferred title field
view_groups:
- label: År
field: date
# groups items based on the value matched by the pattern
pattern: \d{4}
view_filters:
- label: Utkast
field: draft
pattern: true
slug: '{{slug}}'
editor:
preview: true
nested:
depth: 100 # max depth to show in the collection tree
summary: '{{title}}' # optional summary for a tree node, defaults to the inferred title field
fields:
- { label: 'Language', name: 'language', widget: 'hidden', default: 'fi' }
- { label: 'Datum', name: 'date', widget: 'datetime', date_format: "DD.MM.YYYY", time_format: "HH:mm", format: "YYYY-MM-DDTHH:mmZ", hint: 'Datum som visar när inlägget gjordes. Om datumet och tiden är i framtiden
kommer inlägget att släppas ut på siten först vid den tiden.' }
- { label: 'Utkast', name: 'draft', widget: 'boolean', default: true, hint: 'Inlägget kommer inte att visas på sidan även fast det är publicerat.' }
- { label: 'Visa i flödet', name: 'show_in_flow', widget: 'boolean', default: true, hint: 'Inlägget visas i flödet på hemsidan.' }
- { label: 'Visa som prioriterat tills', name: 'sticky_until', widget: 'datetime', date_format: "DD.MM.YYYY", time_format: "HH:mm", format: "YYYY-MM-DDTHH:mmZ", hint: 'Inlägget visas högst upp i flödet på hemsidan tills denna tidpunkt.' }
- { label: "Huvudbild", name: "image", widget: "image", required: false, choose_url: true, allow_multiple: false, hint: 'Bild som visas högst upp i inlägget och då det visas i flödet på hemsidan. Använd t.ex. **[Squoosh.app](http://squoosh.app)** för att se till att bilden är lagom stor innan du laddar upp den.' }
- { label: 'Titel', name: 'title', widget: 'string', hint: 'Sidans titel som visas i inläggets intro och då det visas i flödet på sidan.' }
- { label: 'Beskrivning', name: 'short_description', widget: 'string', required: false, hint: 'Kort beskrivning av inlägget då det visas i flödet på sidan.' }
- { label: 'Sidinnehåll', name: 'body', widget: 'markdown', sanitize_preview: true, hint: 'Sidans innehåll, Se t.ex. **[markdown cheat-sheet](/markdown-cheat-sheet)** för exempel.' }
- { label: "Taggar", name: "tags", widget: "list", required: false, hint: 'taggar som beskriver innehållet' }

```

## Additional context

By modifying the markdown manually, after adding the image widget, you can force the image to show up in the preview (of course the image widget will no longer be shown in the rich text view)

### before
```
There is no character before or after the image - and no image is in the preview

![alt text](/images/testing.jpg "testing")
```

### after
```
There is a whitespace before the image (could be any character) -and image is shown in preview

![alt text](/images/testing.jpg "testing")
```

Contributor guide

Open the contributing guide

Research direction

Start by reproducing the issue in the markdown editor's Image widget and inspect the Chrome warning about invalid data sent to the remark image plugin. Trace the preview rendering path for inline image widgets; done means inserted images render in the markdown preview without the warning.

Written by the indexing model from the issue text.

Assessment

Tech stack
javascript, react
Domain
frontend
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
38/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.