Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions draftlogs/7896_add.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
- Add ability to use custom URL for chart upload from the dialog UI [#7896](https://github.com/plotly/plotly.js/pull/7896)
6 changes: 4 additions & 2 deletions src/components/modebar/buttons.js
Original file line number Diff line number Diff line change
Expand Up @@ -89,8 +89,10 @@ modeBarButtons.sendChartToCloud = {
return;
}

confirmCloudDialog(gd, baseUrl, function() {
Plots.sendDataToCloud(gd, baseUrl);
// The dialog pre-fills baseUrl but lets the user override it with a
// custom server URL, which is passed back here as `chosenUrl`.
confirmCloudDialog(gd, baseUrl, function(chosenUrl) {
Plots.sendDataToCloud(gd, chosenUrl);
});
}
};
Expand Down
88 changes: 79 additions & 9 deletions src/components/modebar/cloud_confirm.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,15 @@ var _ = require('../../lib')._;
* so it is centered over the plot rather than the whole viewport. It can be
* dismissed by clicking Cancel, clicking the backdrop, or pressing Escape.
*
* By default the chart is uploaded to the configured plotlyServerURL. A
* "Use a custom server URL" link reveals an editable "Server URL" field
* pre-filled with that default; whatever the user leaves in the field when they
* confirm becomes the destination, so a custom URL entered here overrides the
* plotlyServerURL config for that upload.
*
* @param {DOM node} gd - the graph div, used to scope the dialog to the plot
* @param {string} serverUrl - destination shown in the dialog message
* @param {function} onConfirm - called when the user confirms the upload
* @param {string} serverUrl - default destination
* @param {function} onConfirm - called with the (possibly edited) server URL when confirmed
*/
module.exports = function confirmCloudDialog(gd, serverUrl, onConfirm) {
var container = d3.select(gd._fullLayout._paperdiv.node());
Expand All @@ -30,11 +36,34 @@ module.exports = function confirmCloudDialog(gd, serverUrl, onConfirm) {

dialog.append('div')
.classed('plotly-cloud-dialog-title', true)
.text(_(gd, 'Share with Plotly Cloud'));
.text(_(gd, 'Share Chart'));

dialog.append('div')
var description = dialog.append('div')
.classed('plotly-cloud-dialog-message', true)
.text(_(gd, 'This chart and its data will be sent to') + ' ' + serverUrl + '.');
.text(_(gd, 'This chart and its data will be sent to') + ' ' + serverUrl + '. ');

// The custom-URL field stays hidden until the user opts in. By default the
// chart is shared to the configured serverUrl; a button in the button row
// reveals this input for anyone who wants to override that destination.
var urlField = dialog.append('div')
.classed('plotly-cloud-dialog-url-field', true)
.style('display', 'none');

urlField.append('label')
.classed('plotly-cloud-dialog-label', true)
.attr('for', 'plotly-cloud-dialog-url')
.text(_(gd, 'Dash Enterprise URL'));

var input = urlField.append('input')
.classed('plotly-cloud-dialog-input', true)
.attr('id', 'plotly-cloud-dialog-url')
.attr('type', 'text')
.attr('spellcheck', false)
.attr('placeholder', 'https://<your-dash-enterprise-instance>/newchart');

var error = dialog.append('div')
.classed('plotly-cloud-dialog-error', true)
.style('display', 'none');

var buttons = dialog.append('div')
.classed('plotly-cloud-dialog-buttons', true);
Expand All @@ -54,6 +83,50 @@ module.exports = function confirmCloudDialog(gd, serverUrl, onConfirm) {
if(d3.event.target === overlay.node()) close();
});

function confirm() {
var url = (input.property('value') || serverUrl).trim();

if(!url) {
error.text(_(gd, 'Please enter a server URL.')).style('display', '');
input.node().focus();
return;
}

try {
new URL(url);
} catch(e) {
error.text(_(gd, 'Please enter a valid server URL.')).style('display', '');
input.node().focus();
return;
}

close();
onConfirm(url);
}

// Hide the error and allow Enter to confirm from the input.
input.on('input', function() {
error.style('display', 'none');
});
input.on('keydown', function() {
if(d3.event.key === 'Enter' || d3.event.keyCode === 13) confirm();
});

// Sits at the left of the button row, in line with Cancel/Share. Reveals
// the Server URL field and hides itself once a custom URL is requested.
var customBtn = buttons.append('button')
.classed('plotly-cloud-dialog-btn', true)
.classed('plotly-cloud-dialog-btn--custom', true)
.attr('type', 'button')
.text(_(gd, 'Share with Dash Enterprise'));

customBtn.on('click', function() {
customBtn.style('display', 'none');
urlField.style('display', '');
description.text(_(gd, 'This chart and its data will be sent to the server URL you provide.'));
input.node().focus();
});

buttons.append('button')
.classed('plotly-cloud-dialog-btn', true)
.classed('plotly-cloud-dialog-btn--cancel', true)
Expand All @@ -64,8 +137,5 @@ module.exports = function confirmCloudDialog(gd, serverUrl, onConfirm) {
.classed('plotly-cloud-dialog-btn', true)
.classed('plotly-cloud-dialog-btn--confirm', true)
.text(_(gd, 'Share'))
.on('click', function() {
close();
onConfirm();
});
.on('click', confirm);
};
55 changes: 55 additions & 0 deletions src/css/_cloud_dialog.scss
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,37 @@
word-wrap: break-word;
}

.plotly-cloud-dialog-label {
display: block;
margin-top: 16px;
margin-bottom: 6px;
font-weight: bold;
}

.plotly-cloud-dialog-input {
box-sizing: border-box;
width: 100%;
padding: 7px 10px;

font-family: inherit;
font-size: 13px;
color: #2a3f5f;

background-color: vars.$color-bg-light;
border: 1px solid vars.$color-bg-darker;
border-radius: 3px;

&:focus {
outline: none;
border-color: vars.$color-brand-primary;
}
}

.plotly-cloud-dialog-error {
margin-top: 6px;
color: vars.$color-inline-code;
}

.plotly-cloud-dialog-buttons {
display: flex;
justify-content: flex-end;
Expand All @@ -65,6 +96,30 @@
}
}

.plotly-cloud-dialog-btn--custom {
// Push this button to the left so Cancel/Share stay right-aligned,
// while all three share the same row (vertical) baseline.
margin-left: 0;
margin-right: auto;

// Zero the padding and any UA button chrome so the button text
// lines up on its left edge with the message/label text above it.
padding-left: 0;
padding-right: 0;
text-align: left;
appearance: none;
-webkit-appearance: none;

background: none;
border: none;
color: vars.$color-brand-primary;
text-decoration: underline;

&:hover {
color: vars.$color-brand-accent;
}
}

.plotly-cloud-dialog-btn--cancel {
background-color: vars.$color-bg-light;
border-color: vars.$color-bg-darker;
Expand Down
4 changes: 2 additions & 2 deletions src/plot_api/plot_config.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ var configAttributes = {

plotlyServerURL: {
valType: 'string',
dflt: '',
dflt: 'https://cloud.plotly.com/newchart',
description: [
'Sets the URL for the `sendChartToCloud` modebar button.',
'When clicked, the button will send the chart data to this URL.',
Expand Down Expand Up @@ -271,7 +271,7 @@ var configAttributes = {
},
showSendToCloud: {
valType: 'boolean',
dflt: false,
dflt: true,
description: [
'Should we include a modebar button that sends this chart to a URL',
'specified by `plotlyServerURL`, for sharing the chart with others?',
Expand Down
Loading