diff --git a/CHANGELOG.txt b/CHANGELOG.txt index 5fc480801d..f6142c4bba 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -8,6 +8,7 @@ Changelog * Added more informative error message when `|richtext` filter is applied to a non-string value (mukesh5) * Automatic search indexing can now be disabled on a per-model basis via the `search_auto_update` attribute (Karl Hobley) * Improved diffing of StreamFields when comparing page revisions (Karl Hobley) + * Highlight broken links to pages and missing documents in rich text (Brady Moe) * Fix: Set `SERVER_PORT` to 443 in `Page.dummy_request()` for HTTPS sites (Sergey Fedoseev) * Fix: Include port number in `Host` header of `Page.dummy_request()` (Sergey Fedoseev) * Fix: Validation error messages in `InlinePanel` no longer count towards `max_num` when disabling the 'add' button (Todd Dembrey, Thibaud Colas) diff --git a/client/src/components/Draftail/decorators/Document.js b/client/src/components/Draftail/decorators/Document.js index afade79d33..9889f23734 100644 --- a/client/src/components/Draftail/decorators/Document.js +++ b/client/src/components/Draftail/decorators/Document.js @@ -5,18 +5,32 @@ import Icon from '../../Icon/Icon'; import TooltipEntity from '../decorators/TooltipEntity'; +import { STRINGS } from '../../../config/wagtailConfig'; + const documentIcon = ; +const missingDocumentIcon = ; const Document = props => { const { entityKey, contentState } = props; const data = contentState.getEntity(entityKey).getData(); + const url = data.url || null; + let icon; + let label; + + if (!url) { + icon = missingDocumentIcon; + label = STRINGS.MISSING_DOCUMENT; + } else { + icon = documentIcon; + label = data.filename || ''; + } return ( ); }; diff --git a/client/src/components/Draftail/decorators/Link.js b/client/src/components/Draftail/decorators/Link.js index 523dd1f942..5e28ce3909 100644 --- a/client/src/components/Draftail/decorators/Link.js +++ b/client/src/components/Draftail/decorators/Link.js @@ -5,7 +5,10 @@ import Icon from '../../Icon/Icon'; import TooltipEntity from '../decorators/TooltipEntity'; +import { STRINGS } from '../../../config/wagtailConfig'; + const LINK_ICON = ; +const BROKEN_LINK_ICON = ; const MAIL_ICON = ; const getEmailAddress = mailto => mailto.replace('mailto:', '').split('?')[0]; @@ -13,11 +16,14 @@ const getDomainName = url => url.replace(/(^\w+:|^)\/\//, '').split('/')[0]; // Determines how to display the link based on its type: page, mail, or external. export const getLinkAttributes = (data) => { - const url = data.url || ''; + const url = data.url || null; let icon; let label; - if (data.id) { + if (!url) { + icon = BROKEN_LINK_ICON; + label = STRINGS.BROKEN_LINK; + } else if (data.id) { icon = LINK_ICON; label = url; } else if (url.startsWith('mailto:')) { diff --git a/client/src/components/Draftail/decorators/Link.test.js b/client/src/components/Draftail/decorators/Link.test.js index 32fda86813..cab3ed9799 100644 --- a/client/src/components/Draftail/decorators/Link.test.js +++ b/client/src/components/Draftail/decorators/Link.test.js @@ -64,7 +64,7 @@ describe('Link', () => { }); it('no data', () => { - expect(getLinkAttributes({})).toMatchObject({ url: '' }); + expect(getLinkAttributes({})).toMatchObject({ url: null, label: 'Broken link' }); }); }); }); diff --git a/client/src/components/Draftail/decorators/TooltipEntity.js b/client/src/components/Draftail/decorators/TooltipEntity.js index c5631b2ab3..7b7e3afa60 100644 --- a/client/src/components/Draftail/decorators/TooltipEntity.js +++ b/client/src/components/Draftail/decorators/TooltipEntity.js @@ -144,7 +144,11 @@ TooltipEntity.propTypes = { PropTypes.object.isRequired, ]).isRequired, label: PropTypes.string.isRequired, - url: PropTypes.string.isRequired, + url: PropTypes.string, +}; + +TooltipEntity.defaultProps = { + url: null, }; export default TooltipEntity; diff --git a/client/src/components/Draftail/decorators/TooltipEntity.scss b/client/src/components/Draftail/decorators/TooltipEntity.scss index fb86d3d528..b9c9fbd050 100644 --- a/client/src/components/Draftail/decorators/TooltipEntity.scss +++ b/client/src/components/Draftail/decorators/TooltipEntity.scss @@ -7,6 +7,10 @@ $icon-size: 1em; color: $color-teal; } + .icon-warning { + color: $color-red; + } + &__icon { color: $color-teal; margin-right: 0.2em; diff --git a/client/src/components/Draftail/decorators/__snapshots__/Document.test.js.snap b/client/src/components/Draftail/decorators/__snapshots__/Document.test.js.snap index 17b14ffb28..e24e22a549 100644 --- a/client/src/components/Draftail/decorators/__snapshots__/Document.test.js.snap +++ b/client/src/components/Draftail/decorators/__snapshots__/Document.test.js.snap @@ -56,14 +56,14 @@ exports[`Document no data 1`] = ` icon={ } - label="" + label="Missing document" onEdit={[Function]} onRemove={[Function]} - url="" + url={null} > test diff --git a/client/tests/stubs.js b/client/tests/stubs.js index 28724878c6..ad82e10d20 100644 --- a/client/tests/stubs.js +++ b/client/tests/stubs.js @@ -41,6 +41,8 @@ global.wagtailConfig = { SHOW_LATEST_CONTENT: 'Show latest content', SHOW_ERROR: 'Show error', EDITOR_CRASH: 'The editor just crashed. Content has been reset to the last saved version.', + BROKEN_LINK: 'Broken link', + MISSING_DOCUMENT: 'Missing document', }, }; diff --git a/docs/releases/2.5.rst b/docs/releases/2.5.rst index 29afca7c2c..9b6b0a6d88 100644 --- a/docs/releases/2.5.rst +++ b/docs/releases/2.5.rst @@ -18,6 +18,7 @@ Other features * Added more informative error message when ``|richtext`` filter is applied to a non-string value (mukesh5) * Automatic search indexing can now be disabled on a per-model basis via the ``search_auto_update`` attribute (Karl Hobley) * Improved diffing of StreamFields when comparing page revisions (Karl Hobley) + * Highlight broken links to pages and missing documents in rich text (Brady Moe) Bug fixes diff --git a/wagtail/admin/templates/wagtailadmin/admin_base.html b/wagtail/admin/templates/wagtailadmin/admin_base.html index 136214f084..d73e1c63df 100644 --- a/wagtail/admin/templates/wagtailadmin/admin_base.html +++ b/wagtail/admin/templates/wagtailadmin/admin_base.html @@ -49,6 +49,8 @@ SHOW_LATEST_CONTENT: "{% trans 'Show latest content' %}", SHOW_ERROR: "{% trans 'Show error' %}", EDITOR_CRASH: "{% trans 'The editor just crashed. Content has been reset to the last saved version.' %}", + BROKEN_LINK: "{% trans 'Broken link' %}", + MISSING_DOCUMENT: "{% trans 'Missing document' %}" }; wagtailConfig.ADMIN_URLS = {