plugin.ts 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343
  1. // Copyright (c) Jupyter Development Team.
  2. // Distributed under the terms of the Modified BSD License.
  3. import $ = require('jquery');
  4. import {
  5. Message
  6. } from 'phosphor/lib/core/messaging';
  7. import {
  8. Widget
  9. } from 'phosphor/lib/ui/widget';
  10. import {
  11. JupyterLab, JupyterLabPlugin
  12. } from '../application';
  13. import {
  14. ICommandPalette
  15. } from '../commandpalette';
  16. /**
  17. * The faq page extension.
  18. */
  19. export
  20. const faqExtension: JupyterLabPlugin<void> = {
  21. id: 'jupyter.extensions.faq',
  22. requires: [ICommandPalette],
  23. activate: activateFAQ,
  24. autoStart: true
  25. };
  26. /**
  27. * A widget that displays FAQ information.
  28. */
  29. class FAQWidget extends Widget {
  30. /**
  31. * A handler for `after-attach` messages.
  32. */
  33. protected onAfterAttach(msg: Message): void {
  34. let answerNodeList = this.node.querySelectorAll('li.jp-FAQ-answer');
  35. let answerArray = Array.prototype.slice.call(answerNodeList);
  36. for (let answerElement of answerArray) {
  37. answerElement.className += ' jp-FAQ-hide';
  38. }
  39. $('li.jp-FAQ-question').click(function(){
  40. $(this).data('clicked', false).next().slideToggle(200)
  41. .siblings('li.jp-FAQ-answer').slideUp(200);
  42. });
  43. }
  44. }
  45. /**
  46. * Activate the faq plugin.
  47. */
  48. function activateFAQ(app: JupyterLab, palette: ICommandPalette): void {
  49. let widget = new FAQWidget();
  50. let commandId = 'faq-jupyterlab:show';
  51. widget.id = 'faq-jupyterlab';
  52. widget.title.label = 'FAQ';
  53. widget.title.closable = true;
  54. // Create Frequently Asked Questions Header Section.
  55. let faq = document.createElement('section');
  56. faq.id = 'faq-header';
  57. widget.node.appendChild(faq);
  58. let questionIcon = document.createElement('span');
  59. questionIcon.className = 'jp-QuestionMark jp-FAQ-QuestionMark';
  60. faq.appendChild(questionIcon);
  61. let faqHeader = document.createElement('h1');
  62. faqHeader.className = 'jp-FAQ-h1';
  63. let faqTitle = document.createElement('span');
  64. faqTitle.className = 'jp-FAQ-title';
  65. faqTitle.textContent = 'Frequently Asked Questions';
  66. faq.appendChild(faqHeader);
  67. faqHeader.appendChild(faqTitle);
  68. let paragraph = document.createElement('p');
  69. widget.node.appendChild(paragraph);
  70. // Create a section element that all other FAQ Content will go under.
  71. let faqContent = document.createElement('section');
  72. faqContent.id = 'faq-content';
  73. paragraph.appendChild(faqContent);
  74. // Create Basics section.
  75. let basicsHeading = document.createElement('h2');
  76. basicsHeading.className = 'jp-FAQ-h2';
  77. basicsHeading.textContent = 'THE BASICS';
  78. faqContent.appendChild(basicsHeading);
  79. // Create unordered list of questions/answers under the Basics section.
  80. let basicsQA = document.createElement('ul');
  81. basicsQA.className = 'jp-FAQ-ul';
  82. let basicsQ1 = document.createElement('li');
  83. basicsQ1.className = 'jp-FAQ-question';
  84. basicsQ1.textContent = 'What is JupyterLab?';
  85. let basicsQ1Ans = document.createElement('li');
  86. basicsQ1Ans.className = 'jp-FAQ-answer';
  87. basicsQ1Ans.textContent = 'JupyterLab allows users to arrange multiple Jupyter notebooks, '
  88. + 'text editors, terminals, output areas, etc. on a single page with multiple panels '
  89. + 'and tabs into one application. The codebase and UI of JupyterLab is based on a flexible '
  90. + 'plugin system that makes it easy to extend with new components.';
  91. faqContent.appendChild(basicsQA);
  92. basicsQA.appendChild(basicsQ1);
  93. basicsQA.appendChild(basicsQ1Ans);
  94. let basicsQ2 = document.createElement('li');
  95. basicsQ2.className = 'jp-FAQ-question';
  96. basicsQ2.textContent = 'What is a Jupyter Notebook?';
  97. let basicsQ2Ans = document.createElement('li');
  98. basicsQ2Ans.className = 'jp-FAQ-answer';
  99. basicsQ2Ans.textContent = 'Central to the project is the Jupyter Notebook, a web-based '
  100. + 'platform that allows users to combine live code, equations, narrative text, '
  101. + 'visualizations, interactive dashboards and other media. Together these building '
  102. + 'blocks make science and data reproducible across over 40 programming languages and'
  103. + 'combine to form what we call a computational narrative.';
  104. basicsQA.appendChild(basicsQ2);
  105. basicsQA.appendChild(basicsQ2Ans);
  106. let basicsQ3 = document.createElement('li');
  107. basicsQ3.className = 'jp-FAQ-question';
  108. basicsQ3.textContent = 'How stable is JupyterLab?';
  109. let basicsQ3Ans = document.createElement('li');
  110. basicsQ3Ans.className = 'jp-FAQ-answer';
  111. basicsQ3Ans.textContent = 'JupyterLab is currently in a alpha release and not ready '
  112. + 'for public use as new features and bug fixes are being added very frequently. '
  113. + 'We strongly recommend to backup your work before using JupyterLab. However, '
  114. + 'testing, development, and user feedback are greatly appreciated.';
  115. basicsQA.appendChild(basicsQ3);
  116. basicsQA.appendChild(basicsQ3Ans);
  117. let basicsQ4 = document.createElement('li');
  118. basicsQ4.className = 'jp-FAQ-question';
  119. basicsQ4.textContent = 'I’m confused with the interface. How do I navigate around JupyterLab?';
  120. let basicsQ4Ans = document.createElement('li');
  121. basicsQ4Ans.className = 'jp-FAQ-answer';
  122. basicsQ4Ans.textContent = 'Check out the JupyterLab tour ';
  123. basicsQA.appendChild(basicsQ4);
  124. basicsQA.appendChild(basicsQ4Ans);
  125. // Create a 'button' that opens the tour page.
  126. let tourButton = document.createElement('a');
  127. tourButton.className = 'jp-FAQ-a';
  128. let tourButtonText = document.createTextNode('here');
  129. tourButton.appendChild(tourButtonText);
  130. tourButton.addEventListener('click', () => {
  131. app.commands.execute('about-jupyterlab:show', void 0);
  132. });
  133. // Finish the rest of the answer.
  134. let basicsQ4AnsLeft = document.createTextNode('!');
  135. basicsQ4Ans.appendChild(tourButton);
  136. basicsQ4Ans.appendChild(basicsQ4AnsLeft);
  137. // Create Features section.
  138. let featuresHeading = document.createElement('h2');
  139. featuresHeading.className = 'jp-FAQ-h2';
  140. featuresHeading.textContent = 'FEATURES';
  141. faqContent.appendChild(featuresHeading);
  142. // Create unordered list of questions/answers under the Features section.
  143. let featuresQA = document.createElement('ul');
  144. featuresQA.className = 'jp-FAQ-ul';
  145. let featuresQ1 = document.createElement('li');
  146. featuresQ1.className = 'jp-FAQ-question';
  147. featuresQ1.textContent = 'How do I add more kernels/languages to JupyterLab?';
  148. let featuresQ1Ans = document.createElement('li');
  149. featuresQ1Ans.className = 'jp-FAQ-answer';
  150. featuresQ1Ans.textContent = 'To add more languages to the JupyterLab you must install '
  151. + 'a new kernel. Installing a kernel is usually fairly simple and can be done '
  152. + 'with a couple terminal commands. However the instructions for installing kernels '
  153. + 'is different for each language. For further instructions, click ';
  154. // Create a link to how to install more kernels.
  155. let kernelLink = document.createElement('a');
  156. kernelLink.className = 'jp-FAQ-a';
  157. let kernelLinkText = document.createTextNode('this');
  158. kernelLink.appendChild(kernelLinkText);
  159. kernelLink.href = 'https://jupyter.readthedocs.io/en/latest/install-kernel.html';
  160. kernelLink.target = '_blank';
  161. featuresQ1Ans.appendChild(kernelLink);
  162. let featuresQ1AnsLeft = document.createTextNode(' link');
  163. featuresQ1Ans.appendChild(featuresQ1AnsLeft);
  164. faqContent.appendChild(featuresQA);
  165. featuresQA.appendChild(featuresQ1);
  166. featuresQA.appendChild(featuresQ1Ans);
  167. let featuresQ2 = document.createElement('li');
  168. featuresQ2.className = 'jp-FAQ-question';
  169. featuresQ2.textContent = 'How can I share my notebooks?';
  170. let featuresQ2Ans = document.createElement('li');
  171. featuresQ2Ans.className = 'jp-FAQ-answer';
  172. featuresQ2Ans.textContent = 'You can either publish your notebooks on GitHub or use a '
  173. + 'free service such as ';
  174. // Create a link to NBViewer.
  175. let nbViewerLink = document.createElement('a');
  176. nbViewerLink.className = 'jp-FAQ-a';
  177. let nbViewerLinkText = document.createTextNode('nbviewer.org');
  178. nbViewerLink.appendChild(nbViewerLinkText);
  179. nbViewerLink.href = 'https://nbviewer.jupyter.org/';
  180. nbViewerLink.target = '_blank';
  181. featuresQ2Ans.appendChild(nbViewerLink);
  182. let featuresQ2AnsLeft = document.createTextNode(' to render your notebooks online.');
  183. featuresQ2Ans.appendChild(featuresQ2AnsLeft);
  184. featuresQA.appendChild(featuresQ2);
  185. featuresQA.appendChild(featuresQ2Ans);
  186. // Create Developer section.
  187. let developerHeading = document.createElement('h2');
  188. developerHeading.className = 'jp-FAQ-h2';
  189. developerHeading.textContent = 'DEVELOPER';
  190. faqContent.appendChild(developerHeading);
  191. // Create unordered list of questions/answers under the Developer section.
  192. let developerQA = document.createElement('ul');
  193. developerQA.className = 'jp-FAQ-ul';
  194. let developerQ1 = document.createElement('li');
  195. developerQ1.className = 'jp-FAQ-question';
  196. developerQ1.textContent = 'How do I report a bug?';
  197. let developerQ1Ans = document.createElement('li');
  198. developerQ1Ans.className = 'jp-FAQ-answer';
  199. developerQ1Ans.textContent = 'You can open an issue on our ';
  200. // Create a link to JupyterLab github issues.
  201. let issuesLink = document.createElement('a');
  202. issuesLink.className = 'jp-FAQ-a';
  203. let issuesLinkText = document.createTextNode('github repository');
  204. issuesLink.appendChild(issuesLinkText);
  205. issuesLink.href = 'https://github.com/jupyter/jupyterlab/issues';
  206. issuesLink.target = '_blank';
  207. developerQ1Ans.appendChild(issuesLink);
  208. let developerQ1AnsLeft = document.createTextNode('. Please check already opened issues '
  209. + 'before posting.');
  210. developerQ1Ans.appendChild(developerQ1AnsLeft);
  211. faqContent.appendChild(developerQA);
  212. developerQA.appendChild(developerQ1);
  213. developerQA.appendChild(developerQ1Ans);
  214. let developerQ2 = document.createElement('li');
  215. developerQ2.className = 'jp-FAQ-question';
  216. developerQ2.textContent = 'I have security concerns about JupyterLab.';
  217. let developerQ2Ans = document.createElement('li');
  218. developerQ2Ans.className = 'jp-FAQ-answer';
  219. developerQ2Ans.textContent = 'If you have any inquiries, concerns, or thought you found '
  220. + 'a security vulnerability, please write to us at ';
  221. // Create email address link for security concerns.
  222. let securityMailLink = document.createElement('a');
  223. securityMailLink.className = 'jp-FAQ-a';
  224. let securityMailLinkText = document.createTextNode('security@jupyter.org');
  225. securityMailLink.appendChild(securityMailLinkText);
  226. securityMailLink.href = 'mailto:security@jupyter.org';
  227. developerQ2Ans.appendChild(securityMailLink);
  228. // Finish the rest of the answer.
  229. let developerQ2AnsLeft = document.createTextNode('. We will do our best to respond to you promptly.');
  230. developerQ2Ans.appendChild(developerQ2AnsLeft);
  231. developerQA.appendChild(developerQ2);
  232. developerQA.appendChild(developerQ2Ans);
  233. let developerQ3 = document.createElement('li');
  234. developerQ3.className = 'jp-FAQ-question';
  235. developerQ3.textContent = 'How can I contribute?';
  236. let developerQ3Ans = document.createElement('li');
  237. developerQ3Ans.className = 'jp-FAQ-answer';
  238. developerQ3Ans.textContent = 'There are many ways to contribute to JupyterLab. '
  239. + 'Whether you are an experienced python programmer or a newcomer, any interested '
  240. + 'developers are welcome. You can learn about the JupyterLab codebase by going through our ';
  241. // Create a link to JupyterLab tutorial documentation.
  242. let tutorialLink = document.createElement('a');
  243. tutorialLink.className = 'jp-FAQ-a';
  244. let tutorialLinkText = document.createTextNode('tutorial walkthrough');
  245. tutorialLink.appendChild(tutorialLinkText);
  246. tutorialLink.href = 'https://jupyterlab-tutorial.readthedocs.io/en/latest/index.html';
  247. tutorialLink.target = '_blank';
  248. developerQ3Ans.appendChild(tutorialLink);
  249. // Finish the rest of the answer.
  250. let developerQ3AnsPart1 = document.createTextNode(' and ');
  251. developerQ3Ans.appendChild(developerQ3AnsPart1);
  252. let documentationLink = document.createElement('a');
  253. documentationLink.className = 'jp-FAQ-a';
  254. let documentationLinkText = document.createTextNode('documentation');
  255. documentationLink.appendChild(documentationLinkText);
  256. documentationLink.href = 'http://jupyter.org/jupyterlab/';
  257. documentationLink.target = '_blank';
  258. developerQ3Ans.appendChild(documentationLink);
  259. let developerQ3AnsPart2 = document.createTextNode('. Also, feel free to ask questions on our ');
  260. developerQ3Ans.appendChild(developerQ3AnsPart2);
  261. // Create a link to JupyterLab github repository.
  262. let githubLink = document.createElement('a');
  263. githubLink.className = 'jp-FAQ-a';
  264. let githubLinkText = document.createTextNode('github');
  265. githubLink.appendChild(githubLinkText);
  266. githubLink.href = 'https://github.com/jupyter/jupyterlab';
  267. githubLink.target = '_blank';
  268. developerQ3Ans.appendChild(githubLink);
  269. let developerQ3AnsPart3 = document.createTextNode(' or through any of our ');
  270. developerQ3Ans.appendChild(developerQ3AnsPart3);
  271. // Create a link to Jupyter community help resources.
  272. let communityLink = document.createElement('a');
  273. communityLink.className = 'jp-FAQ-a';
  274. let communityLinkText = document.createTextNode('community resources');
  275. communityLink.appendChild(communityLinkText);
  276. communityLink.href = 'http://jupyter.org/community.html';
  277. communityLink.target = '_blank';
  278. developerQ3Ans.appendChild(communityLink);
  279. let developerQ3AnsPart4 = document.createTextNode('.');
  280. developerQ3Ans.appendChild(developerQ3AnsPart4);
  281. developerQA.appendChild(developerQ3);
  282. developerQA.appendChild(developerQ3Ans);
  283. widget.node.style.overflowY = 'auto';
  284. app.commands.addCommand(commandId, {
  285. label: 'Frequently Asked Questions',
  286. execute: () => {
  287. if (!widget.isAttached) {
  288. app.shell.addToMainArea(widget);
  289. } else {
  290. app.shell.activateMain(widget.id);
  291. }
  292. }
  293. });
  294. palette.addItem({ command: commandId, category: 'Help' });
  295. }