') + ')', 'gi'); if (regex.test(text)) { found = true; var frag = document.createDocumentFragment(); var parts = text.split(regex); parts.forEach(function(part, i) { if (i % 2 === 0) { frag.appendChild(document.createTextNode(part)); } else { var span = document.createElement('span'); span.className = 'userscript-highlight'; span.textContent = part; frag.appendChild(span); } }); node.parentNode.replaceChild(frag, node); } }); } else if (node.nodeType === 1 && node.childNodes) { // element var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT']; if (!skipTags.includes(node.tagName)) { Array.from(node.childNodes).forEach(highlight); } } } highlight(document.body); // Re-highlight on dynamic content var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1 || node.nodeType === 3) highlight(node); }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ', 'i'); if (__m === '*' || __re.test(location.href)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + ', 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ', 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); })(); Fix display of stack traces within RStudio's viewer pane by rpkyle · Pull Request #996 · plotly/dash · GitHub
Skip to content

Fix display of stack traces within RStudio's viewer pane - #996

Merged
rpkyle merged 9 commits into
devfrom
994-fix-viewer
Dec 9, 2019
Merged

Fix display of stack traces within RStudio's viewer pane#996
rpkyle merged 9 commits into
devfrom
994-fix-viewer

Conversation

@rpkyle

@rpkylerpkyle commented Nov 4, 2019

Copy link
Copy Markdown
Contributor

This PR proposes to modify dash-renderer to check whether the stack trace being sent up by the backend includes the string <!DOCTYPE HTML. If it does, the content is embedded within an iframe to avoid CSS leaking caused by the Werkzeug HTML which Dash for Python provides.

If it does not, the content is included in a simple nested div instead, with customized CSS to properly line-wrap the preformatted content, and to automatically use a scrollbar if the stack trace is sufficiently long.

After merging, the stack trace within the dev tools UI for Dash for R apps will look like this:

Viewer Pane Screenshot

To be merged concurrently with plotly/dashR#137. Fixes#994.

@rpkylerpkyle added the dash-renderer related to Dash renderer label Nov 4, 2019
@rpkylerpkyle self-assigned this Nov 4, 2019
Comment threaddash-renderer/src/components/error/FrontEnd/FrontEndError.react.js Outdated
style={{
width: 'calc(600px - 67px)',
height: '75vh',
border: 'none',

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we actually need any of these style attrs?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I kept them because we used them previously, but it might be ok to 🔪 from both R and Python. The important bits are in the FrontEndError.css file anyhow.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The <iframe> needs explicit sizing because the containing page doesn't know what's in it, and border because perhaps iframes have a border by default. But the unframed string version should be closer to the front-end version, which gets most of its styling from .dash-fe-error__info.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed in bf08944

…t.js
Co-Authored-By: alexcjohnson <johnson.alex.c@gmail.com>
@rpkyle
rpkyle requested review from alexcjohnson and removed request for byronzDecember 4, 2019 18:00

@alexcjohnsonalexcjohnson left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks great! 💃

@rpkyle
rpkyle merged commit 19fe714 into devDec 9, 2019
@rpkyle
rpkyle deleted the 994-fix-viewer branch December 9, 2019 03:49
@rpkyle
rpkyle restored the 994-fix-viewer branch December 24, 2019 19:32
@rpkyle
rpkyle deleted the 994-fix-viewer branch December 25, 2019 04:29
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dash-rendererrelated to Dash renderer

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Stack traces do not render in the dev tools UI when using RStudio's viewer pane

3 participants

@rpkyle@alexcjohnson@Marc-Andre-Rivet