/*
* decaffeinate suggestions:
* DS101: Remove unnecessary use of Array.from
* DS102: Remove unnecessary code created because of implicit returns
* DS103: Rewrite code to no longer use __guard__, or convert again using --optional-chaining
* DS206: Consider reworking classes to avoid initClass
* DS207: Consider shorter variations of null checks
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/main/docs/suggestions.md
*/
let NotificationElement;
const fs = require('fs-plus');
const path = require('path');
const {shell} = require('electron');
const NotificationIssue = require('./notification-issue');
const TemplateHelper = require('./template-helper');
const UserUtilities = require('./user-utilities');
const NotificationTemplate = `\
Close All
\
`;
const FatalMetaNotificationTemplate = `\
\
`;
const MetaNotificationTemplate = `\
\
`;
const ButtonListTemplate = `\
\
`;
const ButtonTemplate = `\
\
`;
module.exports =
(NotificationElement = (function() {
NotificationElement = class NotificationElement {
static initClass() {
this.prototype.animationDuration = 360;
this.prototype.visibilityDuration = 5000;
this.prototype.autohideTimeout = null;
}
constructor(model, visibilityDuration) {
this.model = model;
this.visibilityDuration = visibilityDuration;
this.fatalTemplate = TemplateHelper.create(FatalMetaNotificationTemplate);
this.metaTemplate = TemplateHelper.create(MetaNotificationTemplate);
this.buttonListTemplate = TemplateHelper.create(ButtonListTemplate);
this.buttonTemplate = TemplateHelper.create(ButtonTemplate);
this.element = document.createElement('atom-notification');
if (this.model.getType() === 'fatal') { this.issue = new NotificationIssue(this.model); }
this.renderPromise = this.render().catch(function(e) {
console.error(e.message);
return console.error(e.stack);
});
this.model.onDidDismiss(() => this.removeNotification());
if (!this.model.isDismissable()) {
this.autohide();
this.element.addEventListener('click', this.makeDismissable.bind(this), {once: true});
}
this.element.issue = this.issue;
this.element.getRenderPromise = this.getRenderPromise.bind(this);
}
getModel() { return this.model; }
getRenderPromise() { return this.renderPromise; }
render() {
let detail, metaContainer, metaContent;
this.element.classList.add(`${this.model.getType()}`);
this.element.classList.add("icon", `icon-${this.model.getIcon()}`, "native-key-bindings");
if (detail = this.model.getDetail()) { this.element.classList.add('has-detail'); }
if (this.model.isDismissable()) { this.element.classList.add('has-close'); }
if (detail && (this.model.getOptions().stack != null)) { this.element.classList.add('has-stack'); }
this.element.setAttribute('tabindex', '-1');
this.element.innerHTML = NotificationTemplate;
const options = this.model.getOptions();
const notificationContainer = this.element.querySelector('.message');
notificationContainer.innerHTML = atom.ui.markdown.render(this.model.getMessage());
if (detail = this.model.getDetail()) {
let stack;
addSplitLinesToContainer(this.element.querySelector('.detail-content'), detail);
if (stack = options.stack) {
const stackToggle = this.element.querySelector('.stack-toggle');
const stackContainer = this.element.querySelector('.stack-container');
addSplitLinesToContainer(stackContainer, stack);
stackToggle.addEventListener('click', e => this.handleStackTraceToggleClick(e, stackContainer));
this.handleStackTraceToggleClick({currentTarget: stackToggle}, stackContainer);
}
}
if (metaContent = options.description) {
this.element.classList.add('has-description');
metaContainer = this.element.querySelector('.meta');
metaContainer.appendChild(TemplateHelper.render(this.metaTemplate));
const description = this.element.querySelector('.description');
description.innerHTML = atom.ui.markdown.render(metaContent);
}
if (options.buttons && (options.buttons.length > 0)) {
this.element.classList.add('has-buttons');
metaContainer = this.element.querySelector('.meta');
metaContainer.appendChild(TemplateHelper.render(this.buttonListTemplate));
const toolbar = this.element.querySelector('.btn-toolbar');
let buttonClass = this.model.getType();
if (buttonClass === 'fatal') { buttonClass = 'error'; }
buttonClass = `btn-${buttonClass}`;
options.buttons.forEach(button => {
toolbar.appendChild(TemplateHelper.render(this.buttonTemplate));
const buttonEl = toolbar.childNodes[toolbar.childNodes.length - 1];
buttonEl.textContent = button.text;
buttonEl.classList.add(buttonClass);
if (button.className != null) {
buttonEl.classList.add.apply(buttonEl.classList, button.className.split(' '));
}
if (button.onDidClick != null) {
return buttonEl.addEventListener('click', e => {
return button.onDidClick.call(this, e);
});
}
});
}
const closeButton = this.element.querySelector('.close');
closeButton.addEventListener('click', () => this.handleRemoveNotificationClick());
const closeAllButton = this.element.querySelector('.close-all');
closeAllButton.classList.add(this.getButtonClass());
closeAllButton.addEventListener('click', () => this.handleRemoveAllNotificationsClick());
if (this.model.getType() === 'fatal') {
return this.renderFatalError();
} else {
return Promise.resolve();
}
}
renderFatalError() {
const repoUrl = this.issue.getRepoUrl();
const packageName = this.issue.getPackageName();
const fatalContainer = this.element.querySelector('.meta');
fatalContainer.appendChild(TemplateHelper.render(this.fatalTemplate));
const fatalNotification = this.element.querySelector('.fatal-notification');
const issueButton = fatalContainer.querySelector('.btn-issue');
const copyReportButton = fatalContainer.querySelector('.btn-copy-report');
atom.tooltips.add(copyReportButton, {title: copyReportButton.getAttribute('title')});
copyReportButton.addEventListener('click', e => {
e.preventDefault();
return this.issue.getIssueBody().then(issueBody => atom.clipboard.write(issueBody));
});
if ((packageName != null) && (repoUrl != null)) {
fatalNotification.innerHTML = `The error was thrown from the ${packageName} package. `;
} else if (packageName != null) {
issueButton.remove();
fatalNotification.textContent = `The error was thrown from the ${packageName} package. `;
} else {
fatalNotification.textContent = "This is likely a bug in Pulsar. ";
}
// We only show the create issue button if it's clearly in atom core or in a package with a repo url
if (issueButton.parentNode != null) {
if ((packageName != null) && (repoUrl != null)) {
issueButton.textContent = `Create issue on the ${packageName} package`;
} else {
issueButton.textContent = "Create issue on pulsar-edit/pulsar";
}
const promises = [];
promises.push(this.issue.findSimilarIssues());
promises.push(UserUtilities.checkPulsarUpToDate());
if (packageName != null) {
promises.push(UserUtilities.checkPackageUpToDate(packageName));
}
return Promise.all(promises).then(allData => {
let issue;
const [issues, atomCheck, packageCheck] = Array.from(allData);
if ((issues != null ? issues.open : undefined) || (issues != null ? issues.closed : undefined)) {
issue = issues.open || issues.closed;
issueButton.setAttribute('href', issue.html_url);
issueButton.textContent = "View Issue";
fatalNotification.innerHTML += " This issue has already been reported.";
} else if ((packageCheck != null) && !packageCheck.upToDate && !packageCheck.isCore) {
issueButton.setAttribute('href', '#');
issueButton.textContent = "Check for package updates";
issueButton.addEventListener('click', function(e) {
e.preventDefault();
const command = 'settings-view:check-for-package-updates';
return atom.commands.dispatch(atom.views.getView(atom.workspace), command);
});
fatalNotification.innerHTML += `\
${packageName}
is out of date: ${packageCheck.installedVersion} installed;
${packageCheck.latestVersion} latest.
Upgrading to the latest version may fix this issue.\
`;
} else if ((packageCheck != null) && !packageCheck.upToDate && packageCheck.isCore) {
issueButton.remove();
fatalNotification.innerHTML += `\
Locally installed core Pulsar package ${packageName}
is out of date: ${packageCheck.installedVersion} installed locally;
${packageCheck.versionShippedWithPulsar} included with the version of Pulsar you're running.
Removing the locally installed version may fix this issue.\
`;
const packagePath = __guard__(atom.packages.getLoadedPackage(packageName), x => x.path);
if (fs.isSymbolicLinkSync(packagePath)) {
fatalNotification.innerHTML += `\
Use: apm unlink ${packagePath}
\
`;
}
} else if ((atomCheck != null) && !atomCheck.upToDate) {
issueButton.remove();
fatalNotification.innerHTML += `\
Pulsar is out of date: ${atomCheck.installedVersion} installed;
${atomCheck.latestVersion} latest.
Upgrading to the latest version may fix this issue.\
`;
} else {
fatalNotification.innerHTML += " You can help by creating an issue. Please explain what actions triggered this error.";
issueButton.addEventListener('click', e => {
e.preventDefault();
issueButton.classList.add('opening');
return this.issue.getIssueUrlForSystem().then(function(issueUrl) {
shell.openExternal(issueUrl);
return issueButton.classList.remove('opening');
});
});
}
});
} else {
return Promise.resolve();
}
}
makeDismissable() {
if (!this.model.isDismissable()) {
clearTimeout(this.autohideTimeout);
this.model.options.dismissable = true;
this.model.dismissed = false;
return this.element.classList.add('has-close');
}
}
removeNotification() {
if (!this.element.classList.contains('remove')) {
this.element.classList.add('remove');
return this.removeNotificationAfterTimeout();
}
}
handleRemoveNotificationClick() {
this.removeNotification();
return this.model.dismiss();
}
handleRemoveAllNotificationsClick() {
const notifications = atom.notifications.getNotifications();
for (var notification of Array.from(notifications)) {
atom.views.getView(notification).removeNotification();
if (notification.isDismissable() && !notification.isDismissed()) {
notification.dismiss();
}
}
}
handleStackTraceToggleClick(e, container) {
if (typeof e.preventDefault === 'function') {
e.preventDefault();
}
if (container.style.display === 'none') {
e.currentTarget.innerHTML = 'Hide Stack Trace';
return container.style.display = 'block';
} else {
e.currentTarget.innerHTML = 'Show Stack Trace';
return container.style.display = 'none';
}
}
autohide() {
return this.autohideTimeout = setTimeout(() => {
return this.removeNotification();
}
, this.visibilityDuration);
}
removeNotificationAfterTimeout() {
if (this.element === document.activeElement) { atom.workspace.getActivePane().activate(); }
return setTimeout(() => {
return this.element.remove();
}
, this.animationDuration); // keep in sync with CSS animation
}
getButtonClass() {
const type = `btn-${this.model.getType()}`;
if (type === 'btn-fatal') { return 'btn-error'; } else { return type; }
}
};
NotificationElement.initClass();
return NotificationElement;
})());
var addSplitLinesToContainer = function(container, content) {
if (typeof content !== 'string') { content = content.toString(); }
for (var line of Array.from(content.split('\n'))) {
var div = document.createElement('div');
div.classList.add('line');
div.textContent = line;
container.appendChild(div);
}
};
function __guard__(value, transform) {
return (typeof value !== 'undefined' && value !== null) ? transform(value) : undefined;
}