widget.ts 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405
  1. // Copyright (c) Jupyter Development Team.
  2. // Distributed under the terms of the Modified BSD License.
  3. import {
  4. Message
  5. } from '@phosphor/messaging';
  6. import {
  7. h, VirtualNode
  8. } from '@phosphor/virtualdom';
  9. import {
  10. ICommandLinker, VDomModel, VDomWidget
  11. } from '@jupyterlab/apputils';
  12. /**
  13. * The class name added to the FAQ plugin.
  14. */
  15. const FAQ_CLASS = 'jp-FAQ';
  16. /**
  17. * The id name added to the header section element.
  18. */
  19. const HEADER_ID = 'faq-header';
  20. /**
  21. * The class name added to the title.
  22. */
  23. const TITLE_CLASS = 'jp-FAQ-title';
  24. /**
  25. * The class name added to h1 elements.
  26. */
  27. const HEADER_CLASS = 'jp-FAQ-h1';
  28. /**
  29. * The class name added to h2 elements.
  30. */
  31. const SUBHEADER_CLASS = 'jp-FAQ-h2';
  32. /**
  33. * The class name added for the question mark icon from default-theme.
  34. */
  35. const QUESTIONMARK_ICON_CLASS = 'jp-QuestionMark';
  36. /**
  37. * The class named added the question mark icon.
  38. */
  39. const QUESTIONMARK_CLASS = 'jp-FAQ-QuestionMark';
  40. /**
  41. * The class name added to faq content.
  42. */
  43. const CONTENT_CLASS = 'jp-FAQ-content';
  44. /**
  45. * The class name added to unordered list elements.
  46. */
  47. const FAQ_LIST_CLASS = 'jp-FAQ-ul';
  48. /**
  49. * The class name added to table of contents elements.
  50. */
  51. const TOC_CLASS = 'jp-FAQ-toc';
  52. /**
  53. * The class name added to questions.
  54. */
  55. const QUESTION_CLASS = 'jp-FAQ-question';
  56. /**
  57. * The class name added to answers.
  58. */
  59. const ANSWER_CLASS = 'jp-FAQ-answer';
  60. /**
  61. * The class name added to anchor elements.
  62. */
  63. const ANCHOR_CLASS = 'jp-FAQ-a';
  64. /**
  65. * Title of the FAQ plugin.
  66. */
  67. const TITLE = 'Frequently Asked Questions';
  68. /**
  69. * Contain subheadings for each section.
  70. */
  71. const SUBHEADINGS = ['THE BASICS', 'FEATURES', 'DEVELOPER'];
  72. /**
  73. * Contain questions for `the basics` section.
  74. */
  75. const BASIC_QUESTIONS = [
  76. 'What is JupyterLab?',
  77. 'What is a Jupyter Notebook?',
  78. 'How stable is JupyterLab?',
  79. `I'm confused with the interface. How do I navigate around JupyterLab?`
  80. ];
  81. /**
  82. * Contain questions for the `features` section.
  83. */
  84. const FEATURES_QUESTIONS = [
  85. 'How do I add more kernels/languages to JupyterLab?',
  86. 'How can I share my notebooks?'
  87. ];
  88. /**
  89. * Contain questions for the `developer` section.
  90. */
  91. const DEVELOPER_QUESTIONS = [
  92. 'How do I report a bug?',
  93. 'I have security concerns about JupyterLab.',
  94. 'How can I contribute?'
  95. ];
  96. /**
  97. * FaqModel holds data which the FaqWidget will render.
  98. */
  99. export
  100. class FaqModel extends VDomModel {
  101. /**
  102. * Title of the FAQ plugin.
  103. */
  104. readonly title = TITLE;
  105. /**
  106. * Contain subheadings for each section.
  107. */
  108. readonly subheadings = SUBHEADINGS;
  109. /**
  110. * Contain questions for `the basics` section.
  111. */
  112. readonly basicsQuestions = BASIC_QUESTIONS;
  113. /**
  114. * Contain questions for the `features` section.
  115. */
  116. readonly featuresQuestions = FEATURES_QUESTIONS;
  117. /**
  118. * Contain questions for the `developer` section.
  119. */
  120. readonly developerQuestions = DEVELOPER_QUESTIONS;
  121. }
  122. /**
  123. * A virtual-DOM-based widget for the FAQ plugin.
  124. */
  125. export
  126. class FaqWidget extends VDomWidget<FaqModel> {
  127. /**
  128. * Construct a new faq widget.
  129. */
  130. constructor(options: FaqWidget.IOptions) {
  131. super();
  132. this._linker = options.linker;
  133. this.addClass(FAQ_CLASS);
  134. }
  135. /**
  136. * Render the faq plugin to virtual DOM nodes.
  137. */
  138. protected render(): VirtualNode[] {
  139. let linker = this._linker;
  140. let subheadings = this.model.subheadings;
  141. let basicsQuestions = this.model.basicsQuestions;
  142. let featuresQuestions = this.model.featuresQuestions;
  143. let developerQuestions = this.model.developerQuestions;
  144. // Create Frequently Asked Questions Header Section.
  145. let faqHeader =
  146. h.section({ id: HEADER_ID },
  147. h.span({
  148. className: QUESTIONMARK_ICON_CLASS + ' ' + QUESTIONMARK_CLASS
  149. }),
  150. h.h1({ className: HEADER_CLASS },
  151. h.span({ className: TITLE_CLASS }, this.model.title)
  152. )
  153. );
  154. // Create a section element that holds Table of Contents.
  155. let questionList =
  156. h.section({ className: CONTENT_CLASS },
  157. h.h2({ className: SUBHEADER_CLASS }, subheadings[0]),
  158. h.ul({ className: FAQ_LIST_CLASS },
  159. h.li({ className: QUESTION_CLASS + ' ' + TOC_CLASS },
  160. h.a({ href: '#basicsQ1' }, basicsQuestions[0])
  161. ),
  162. h.li({ className: QUESTION_CLASS + ' ' + TOC_CLASS },
  163. h.a({ href: '#basicsQ2' }, basicsQuestions[1])
  164. ),
  165. h.li({ className: QUESTION_CLASS + ' ' + TOC_CLASS },
  166. h.a({ href: '#basicsQ3' }, basicsQuestions[2])
  167. ),
  168. h.li({ className: QUESTION_CLASS + ' ' + TOC_CLASS },
  169. h.a({ href: '#basicsQ4' }, basicsQuestions[3])
  170. )
  171. ),
  172. h.h2({ className: SUBHEADER_CLASS }, subheadings[1]),
  173. h.ul({ className: FAQ_LIST_CLASS },
  174. h.li({ className: QUESTION_CLASS + ' ' + TOC_CLASS },
  175. h.a({ href: '#featuresQ1' }, featuresQuestions[0])
  176. ),
  177. h.li({ className: QUESTION_CLASS + ' ' + TOC_CLASS },
  178. h.a({ href: '#featuresQ2' }, featuresQuestions[1])
  179. )
  180. ),
  181. h.h2({ className: SUBHEADER_CLASS }, subheadings[2]),
  182. h.ul({ className: FAQ_LIST_CLASS },
  183. h.li({ className: QUESTION_CLASS + ' ' + TOC_CLASS },
  184. h.a({ href: '#developerQ1' }, developerQuestions[0])
  185. ),
  186. h.li({ className: QUESTION_CLASS + ' ' + TOC_CLASS },
  187. h.a({ href: '#developerQ2' }, developerQuestions[1])
  188. ),
  189. h.li({ className: QUESTION_CLASS + ' ' + TOC_CLASS },
  190. h.a({ href: '#developerQ3' }, developerQuestions[2])
  191. )
  192. )
  193. );
  194. // Create a section element that all other FAQ Content will go under.
  195. let questionAnswerList =
  196. h.section({ className: CONTENT_CLASS },
  197. h.h2({ className: SUBHEADER_CLASS }, subheadings[0]),
  198. // Create list of questions/answers under the Basics section.
  199. h.ul({ className: FAQ_LIST_CLASS },
  200. h.li({ className: QUESTION_CLASS, id: 'basicsQ1' }, basicsQuestions[0]),
  201. h.li({ className: ANSWER_CLASS },
  202. `JupyterLab allows users to arrange multiple Jupyter notebooks,
  203. text editors, terminals, output areas, etc. on a single page with
  204. multiple panels and tabs into one application. The codebase and UI of
  205. JupyterLab is based on a flexible plugin system that makes it easy to
  206. extend with new components.`
  207. ),
  208. h.li({ className: QUESTION_CLASS, id: 'basicsQ2' }, basicsQuestions[1]),
  209. h.li({ className: ANSWER_CLASS },
  210. `Central to the project is the Jupyter Notebook, a web-based
  211. platform that allows users to combine live code, equations, narrative
  212. text, visualizations, interactive dashboards and other media. Together
  213. these building blocks make science and data reproducible across over
  214. 40 programming languages and combine to form what we call a
  215. computational narrative.`
  216. ),
  217. h.li({ className: QUESTION_CLASS, id: 'basicsQ3' }, basicsQuestions[2]),
  218. h.li({ className: ANSWER_CLASS },
  219. `JupyterLab is currently in an alpha release and not ready for public
  220. use as new features and bug fixes are being added very frequently. We
  221. strongly recommend to back up your work before using JupyterLab.
  222. However, testing, development, and user feedback are greatly
  223. appreciated.`
  224. ),
  225. h.li({ className: QUESTION_CLASS, id: 'basicsQ4' }, basicsQuestions[3]),
  226. h.li({ className: ANSWER_CLASS },
  227. 'Check out the JupyterLab tour ',
  228. h.a({
  229. className: ANCHOR_CLASS,
  230. dataset: linker.populateVNodeDataset('about-jupyterlab:open', null)
  231. }, 'here')
  232. )
  233. ),
  234. h.h2({ className: SUBHEADER_CLASS }, subheadings[1]),
  235. // Create list of questions/answers under the Features section.
  236. h.ul({ className: FAQ_LIST_CLASS },
  237. h.li({
  238. className: QUESTION_CLASS,
  239. id: 'featuresQ1'
  240. }, featuresQuestions[0]),
  241. h.li({ className: ANSWER_CLASS },
  242. `To add more languages to the JupyterLab you must install a new
  243. kernel. Installing a kernel is usually fairly simple and can be done
  244. with a couple terminal commands. However the instructions for
  245. installing kernels is different for each language. For further
  246. instructions, click`,
  247. h.a({
  248. className: ANCHOR_CLASS,
  249. href: 'https://jupyter.readthedocs.io/en/latest/install-kernel.html',
  250. target: '_blank'
  251. }, 'this'),
  252. ' link.'
  253. ),
  254. h.li({
  255. className: QUESTION_CLASS,
  256. id: 'featuresQ2'
  257. }, featuresQuestions[1]),
  258. h.li({ className: ANSWER_CLASS },
  259. `You can either publish your notebooks on GitHub or use a free service
  260. such as `,
  261. h.a({
  262. className: ANCHOR_CLASS,
  263. href: 'https://nbviewer.jupyter.org/',
  264. target: '_blank'
  265. }, 'nbviewer.org'),
  266. ' to render your notebooks online.'
  267. )
  268. ),
  269. h.h2({ className: SUBHEADER_CLASS }, subheadings[2]),
  270. // Create list of questions/answers under the Developer section.
  271. h.ul({ className: FAQ_LIST_CLASS },
  272. h.li({
  273. className: QUESTION_CLASS,
  274. id: 'developerQ1'
  275. }, developerQuestions[0]),
  276. h.li({ className: ANSWER_CLASS },
  277. 'You can open an issue on our ',
  278. h.a({
  279. className: ANCHOR_CLASS,
  280. href: 'https://github.com/jupyterlab/jupyterlab/issues',
  281. target: '_blank'
  282. }, 'GitHub repository'),
  283. '. Please check already opened issues before posting.'
  284. ),
  285. h.li({
  286. className: QUESTION_CLASS,
  287. id: 'developerQ2'
  288. }, developerQuestions[1]),
  289. h.li({ className: ANSWER_CLASS },
  290. `If you have any inquiries, concerns, or thought you found a security
  291. vulnerability, please write to use at `,
  292. h.a({
  293. className: ANCHOR_CLASS,
  294. href: 'mailto:security@jupyter.org'
  295. }, 'security@jupyter.org'),
  296. '. We will do our best to repond to you promptly.'
  297. ),
  298. h.li({
  299. className: QUESTION_CLASS,
  300. id: 'developerQ3'
  301. }, developerQuestions[2]),
  302. h.li({ className: ANSWER_CLASS },
  303. `There are many ways to contribute to JupyterLab. Whether you are an
  304. experienced Python programmer or a newcomer, any interested developers
  305. are welcome. You can learn about the JupyterLab codebase by going
  306. through our`,
  307. h.a({
  308. className: ANCHOR_CLASS,
  309. href: 'https://jupyterlab-tutorial.readthedocs.io/en/latest/index.html',
  310. target: '_blank'
  311. }, 'tutorial walkthrough' ),
  312. ' and ',
  313. h.a({
  314. className: ANCHOR_CLASS,
  315. href: 'https://jupyterlab.github.io/jupyterlab/',
  316. target: '_blank'
  317. }, 'documentation'),
  318. '. Also, feel free to ask questions on our ',
  319. h.a({
  320. className: ANCHOR_CLASS,
  321. href: 'https://github.com/jupyterlab/jupyterlab',
  322. target: '_blank'
  323. }, 'github'),
  324. ' or through any of our ',
  325. h.a({
  326. className: ANCHOR_CLASS,
  327. href: 'http://jupyter.org/community.html',
  328. target: '_blank'
  329. }, 'community resources'),
  330. '.'
  331. )
  332. )
  333. );
  334. return [faqHeader, questionList, questionAnswerList];
  335. }
  336. /**
  337. * Handle `'activate-request'` messages.
  338. */
  339. protected onActivateRequest(msg: Message): void {
  340. this.node.tabIndex = -1;
  341. this.node.focus();
  342. }
  343. /**
  344. * Handle `'close-request'` messages.
  345. */
  346. protected onCloseRequest(msg: Message): void {
  347. super.onCloseRequest(msg);
  348. this.dispose();
  349. }
  350. private _linker: ICommandLinker;
  351. }
  352. /**
  353. * A namespace for `FaqWidget` statics.
  354. */
  355. export
  356. namespace FaqWidget {
  357. /**
  358. * Instantiation options for the FAQ widget.
  359. */
  360. export
  361. interface IOptions {
  362. /**
  363. * A command linker instance.
  364. */
  365. linker: ICommandLinker;
  366. }
  367. }