├── .bowerrc ├── .gitignore ├── .travis.yml ├── AUTHORS ├── CHANGELOG.md ├── LICENSE.md ├── MANIFEST.in ├── Makefile ├── README.md ├── bower.json ├── docs ├── Makefile ├── environment.yml ├── make.bat └── source │ ├── _static │ ├── dashboard_rendering.graffle │ ├── dashboards_intro.png │ ├── grid_layout.png │ ├── layout_toolbar.png │ ├── metadata_grid_layout.png │ ├── metadata_report_layout.png │ ├── more_info.png │ ├── notebook.png │ ├── notebook_toolbar.png │ ├── preview.png │ ├── report_layout.png │ └── workflow.png │ ├── conf.py │ ├── development.md │ ├── getting-started.md │ ├── index.rst │ ├── maintenance.md │ ├── metadata.md │ ├── summary-changes.md │ ├── use-cases.md │ └── using.md ├── etc └── notebooks │ ├── README.md │ ├── declarativewidgets │ ├── community_sentiment_demo │ │ ├── community_sentiment_demo.ipynb │ │ └── widgets │ │ │ └── urth-timeline │ │ │ ├── bower.json │ │ │ └── urth-timeline.html │ ├── meetup_outreach_demo │ │ ├── meetup-outreach.ipynb │ │ └── widgets │ │ │ ├── dynamic-list │ │ │ ├── bower.json │ │ │ └── dynamic-list.html │ │ │ └── upcoming-meetups │ │ │ ├── bower.json │ │ │ └── upcoming-meetups.html │ ├── resizable_widgets_tutorial │ │ └── resizable_widgets.ipynb │ ├── sentiment_boilerplate_demo │ │ ├── sentiment_boilerplate_demo.ipynb │ │ └── widgets │ │ │ └── urth-timeline │ │ │ ├── bower.json │ │ │ └── urth-timeline.html │ ├── stream_demo │ │ └── meetup-streaming.ipynb │ └── taxi_demo │ │ ├── datasets │ │ ├── fares.csv │ │ ├── trips_1.csv │ │ ├── trips_2.csv │ │ └── trips_3.csv │ │ └── taxi_dashboard.ipynb │ ├── got_scotch_demo │ ├── datasets │ │ ├── features.dataframe │ │ ├── sims.dataframe │ │ └── whiskies.txt │ ├── scotch_analysis.ipynb │ ├── scotch_dashboard.ipynb │ └── scotch_dashboard_declarative.ipynb │ ├── plotting_demo.ipynb │ └── test │ ├── system-test │ └── Basic.ipynb │ ├── test_busy_indicator.ipynb │ ├── test_clear_output.ipynb │ ├── test_html_javascript.ipynb │ ├── test_layout.ipynb │ ├── test_layout_basic.ipynb │ ├── test_layout_declarativewidgets.ipynb │ ├── test_markdown.ipynb │ ├── test_no_layout.ipynb │ └── test_widget_overlap.ipynb ├── jupyter_dashboards ├── __init__.py ├── _version.py ├── extensionapp.py └── nbextension │ └── notebook │ ├── dashboard-common │ ├── dashboard-common.css │ ├── error-log.js │ ├── gridstack-custom.js │ └── gridstack-overrides.css │ ├── dashboard-view │ ├── dashboard-actions.css │ ├── dashboard-actions.js │ ├── dashboard-metadata-compatibility.js │ ├── dashboard-metadata.js │ ├── dashboard-view.css │ ├── dashboard-view.js │ ├── help.html │ ├── layout │ │ ├── grid │ │ │ ├── cell-controls.html │ │ │ ├── layout.css │ │ │ └── layout.js │ │ └── report │ │ │ ├── cell-controls.html │ │ │ ├── collapse-button.html │ │ │ ├── layout.css │ │ │ └── layout.js │ ├── notebook-util.js │ ├── object-util.js │ ├── polymer-support.js │ ├── sub-menu.html │ ├── template-loader.js │ ├── view-menu.html │ └── view-toolbar-buttons.html │ ├── link-css.js │ └── main.js ├── package.json ├── postcss-config.json ├── readthedocs.yml ├── requirements-demo.txt ├── requirements-doc.txt ├── requirements-test.txt ├── requirements.txt ├── scripts └── jupyter-dashboards ├── setup.py └── system-test ├── bin └── run-system-test.sh ├── dashboard-buttons-test.js ├── dashboard-menu-test.js └── utils ├── boilerplate.js └── dashboard.js /.bowerrc: -------------------------------------------------------------------------------- 1 | { 2 | "directory": "jupyter_dashboards/nbextension/notebook/bower_components", 3 | "interactive": false 4 | } 5 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | 5 | # C extensions 6 | *.so 7 | 8 | # Distribution / packaging 9 | .Python 10 | env/ 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | *.egg-info/ 23 | .installed.cfg 24 | *.egg 25 | 26 | # PyInstaller 27 | # Usually these files are written by a python script from a template 28 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 29 | *.manifest 30 | *.spec 31 | 32 | # Installer logs 33 | pip-log.txt 34 | pip-delete-this-directory.txt 35 | 36 | # Unit test / coverage reports 37 | htmlcov/ 38 | .tox/ 39 | .coverage 40 | .coverage.* 41 | .cache 42 | nosetests.xml 43 | coverage.xml 44 | *,cover 45 | 46 | # Translations 47 | *.mo 48 | *.pot 49 | 50 | # Django stuff: 51 | *.log 52 | 53 | # Sphinx documentation 54 | docs/_build/ 55 | 56 | # PyBuilder 57 | target/ 58 | 59 | # Project specific 60 | dist/ 61 | node_modules/ 62 | .ipynb_checkpoints/ 63 | bower_components/ 64 | __pycache__/ 65 | *.egg-info/ 66 | etc/notebooks/*_demo/.dashboard_cache 67 | etc/notebooks/*_demo/.ipynb_checkpoints 68 | etc/jupyter_notebook_config.py 69 | etc/ipython_notebook_config.py 70 | etc/notebook.json 71 | 72 | # System testing 73 | **/*/selenium.log 74 | **/*/selenium.jar 75 | **/*/selenium.pid 76 | 77 | # Mac stuff 78 | .DS_Store 79 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: python 2 | python: 3 | - 3.5 4 | 5 | addons: 6 | sauce_connect: 7 | no_ssl_bump_domains: all 8 | 9 | env: 10 | - TEST_SERVER=ondemand.saucelabs.com TEST_TYPE=remote 11 | 12 | before_install: 13 | - git clone https://github.com/ericdill/ci ~/scripts 14 | - . ~/scripts/install-miniconda.sh 15 | 16 | install: 17 | - make env 18 | 19 | script: 20 | # SauceLab creds are only available on merge 21 | - 'if [ "$TRAVIS_PULL_REQUEST" = "false" ]; then ./system-test/bin/run-system-test.sh; fi;' 22 | 23 | notifications: 24 | email: 25 | on_success: change 26 | on_failure: always 27 | 28 | branches: 29 | only: 30 | - master 31 | - fix-selenium 32 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | Nitin Dahyabhai (nitind) 2 | Drew Logsdon (dalogsdon) 3 | Peter Parente (parente) 4 | Javier Pedemonte (jhpedemonte) 5 | Corey Stubbs (Lull3rSkat3r) 6 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## 0.7.0 (2017-04-04) 4 | 5 | * Updated to support notebook 5.0 6 | * Fixed clipping at cell boundaries 7 | 8 | ## 0.6.1 (2016-08-18) 9 | 10 | * Include LICENSE.md in source package 11 | 12 | ## 0.6.0 (2016-06-17) 13 | 14 | * Switch to the [v1 dashboard layout specification](https://github.com/jupyter/dashboards/wiki/Dashboard-Metadata-and-Rendering) 15 | * Automatically upgrade existing notebook metadata to the v1 spec 16 | * Update example notebooks for compatibility with `jupyter_declarativewidgets` 0.6.0 17 | * Remove `urth` moniker in favor of `jupyter_dashboards` for CSS classes, notebook metadata, etc. 18 | * Fix gaps in grid when hiding cells 19 | 20 | ## 0.5.2 (2016-05-11) 21 | 22 | * Fix report layout reset when switching between dashboard layout and preview 23 | 24 | ## 0.5.1 (2016-05-11) 25 | 26 | * Hide errors from declarative widgets in dashboard layout and preview 27 | * Fix the state of the show code checkbox in layout view when switching layout types 28 | * Fix history window slider widgetin the community outreach demo 29 | * Fix missing imports in the declarative widgets scotch demo 30 | * Fix copy/pasted cells receive the same layout metadata 31 | * Fix lost cells in report layout after clear and refresh 32 | * Fix layout toolbar button default state 33 | 34 | ## 0.5.0 (2016-04-26) 35 | 36 | * Add report layout for simple top-to-bottom, full-width dashboards 37 | * Add buttons to move a cell to the top, bottom, or notebook order in layout mode 38 | * Make compatible with Jupyter Notebook 4.0.x to 4.2.x 39 | * Fix bokeh example race condition 40 | * Fix browser scrolling when dragging cells in layout view 41 | 42 | ## 0.4.2 (2016-02-18) 43 | 44 | * Fix code cell overflow in layout mode 45 | * Fix scroll bars that appear within cells of a certain size 46 | * Fix hidden cells from being cut-off in layout mode 47 | * Fix failure to load extension JS in certain situations 48 | * Fix meetup streaming demo filter box 49 | * Update to Gridstack 0.2.4 to remove a workaround 50 | 51 | ## 0.4.1 (2016-02-07) 52 | 53 | * Fix gridstack break with lodash>=4.0 54 | * Remove notebook 4.1 cell focus highlight in dashboard preview 55 | * Hide stderr and errors in dashboard preview, send them to the browser console 56 | 57 | ## 0.4.0 (2016-01-21) 58 | 59 | * Separate `pip install` from `jupyter dashboards [install | activate | deactivate]` 60 | * Match the Python package to the distribution name, `jupyter_dashboards` 61 | * Fix cell overlap when one cell has the minimum height 62 | * Prevent stderr and exception messages from displaying in dashboard modes 63 | * Update demo notebooks to stop using deprecated `UrthData.setItem` from declarative widgets. 64 | 65 | ## 0.3.0 (2015-12-30) 66 | 67 | * Make compatible with Jupyter Notebook 4.1.x 68 | * Remove all download and deployment related backend code in. Refer users to the separate `jupyter_cms` and `jupyter_dashboards_bundlers` packages for these features. 69 | * Keep compatible with Jupyter Notebook 4.0.x 70 | 71 | ## 0.2.2 (2015-12-15) 72 | 73 | * Revert to old jupyter\_notebook\_server.py config hack to remain compatible with jupyter\_declarativewidgets and jupyter\_cms (until they change too) 74 | 75 | ## 0.2.1 (2015-12-15) 76 | 77 | * Fix errors on install when profiles don't exist 78 | * Fix styling leaking out of dashboard mode 79 | 80 | ## 0.2.0 (2015-12-01) 81 | 82 | * Default to showing code instead of blank cells in layout mode 83 | * Add menu items for packed vs stacked cell layout 84 | * Make compatible with Jupyter Notebook 4.0.x 85 | * Make compatible with jupyter_declarativewidgets 0.2.x 86 | * System tests using Selenium locally, SauceLabs via Travis 87 | 88 | ## 0.1.1 (2015-12-02) 89 | 90 | * Backport of UX fixes from 0.2.0 91 | * Keep compatible with IPython Notebook 3.2.x 92 | * Keep compatible with declarative widgets 0.1.x 93 | 94 | ## 0.1.0 (2015-11-17) 95 | 96 | * First PyPI release 97 | * Compatible with IPython Notebook 3.2.x on Python 2.7 or Python 3.3+ 98 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | # Licensing terms 2 | 3 | This project is licensed under the terms of the Modified BSD License 4 | (also known as New or Revised or 3-Clause BSD), as follows: 5 | 6 | - Copyright (c) 2001-2015, IPython Development Team 7 | - Copyright (c) 2015-, Jupyter Development Team 8 | 9 | All rights reserved. 10 | 11 | Redistribution and use in source and binary forms, with or without 12 | modification, are permitted provided that the following conditions are met: 13 | 14 | Redistributions of source code must retain the above copyright notice, this 15 | list of conditions and the following disclaimer. 16 | 17 | Redistributions in binary form must reproduce the above copyright notice, this 18 | list of conditions and the following disclaimer in the documentation and/or 19 | other materials provided with the distribution. 20 | 21 | Neither the name of the Jupyter Development Team nor the names of its 22 | contributors may be used to endorse or promote products derived from this 23 | software without specific prior written permission. 24 | 25 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 26 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 27 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 28 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE 29 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 30 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 31 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 32 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 33 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 34 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 35 | 36 | ## About the Jupyter Development Team 37 | 38 | The Jupyter Development Team is the set of all contributors to the Jupyter project. 39 | This includes all of the Jupyter Subprojects, which are the different repositories 40 | under the [jupyter](https://github.com/jupyter/) GitHub organization. 41 | 42 | The core team that coordinates development on GitHub can be found here: 43 | https://github.com/jupyter/. 44 | 45 | ## Our copyright policy 46 | 47 | Jupyter uses a shared copyright model. Each contributor maintains copyright 48 | over their contributions to Jupyter. But, it is important to note that these 49 | contributions are typically only changes to the repositories. Thus, the Jupyter 50 | source code, in its entirety is not the copyright of any single person or 51 | institution. Instead, it is the collective copyright of the entire Jupyter 52 | Development Team. If individual contributors want to maintain a record of what 53 | changes/contributions they have specific copyright on, they should indicate 54 | their copyright in the commit message of the change, when they commit the 55 | change to one of the Jupyter repositories. 56 | 57 | With this in mind, the following banner should be used in any source code file 58 | to indicate the copyright and license terms: 59 | 60 | # Copyright (c) Jupyter Development Team. 61 | # Distributed under the terms of the Modified BSD License. 62 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | recursive-include jupyter_dashboards * 2 | include LICENSE.md 3 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # Copyright (c) Jupyter Development Team. 2 | # Distributed under the terms of the Modified BSD License. 3 | 4 | .PHONY: activate build clean docs env help notebook nuke release sdist test 5 | 6 | SA:=source activate 7 | ENV:=dashboards 8 | SHELL:=/bin/bash 9 | 10 | help: 11 | # http://marmelab.com/blog/2016/02/29/auto-documented-makefile.html 12 | @grep -E '^[a-zA-Z0-9_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' 13 | 14 | activate: ## eval $(make activate) 15 | @echo "$(SA) $(ENV)" 16 | 17 | clean: ## Make a clean source tree 18 | @-rm -rf dist 19 | @-rm -rf *.egg-info 20 | @-rm -rf __pycache__ */__pycache__ */*/__pycache__ 21 | @-find . -name '*.pyc' -exec rm -fv {} \; 22 | @-rm -rf node_modules 23 | @-rm -rf ./jupyter_dashboards/nbextension/notebook/bower_components 24 | 25 | docs: ## Make HTML documentation 26 | $(SA) $(ENV) && make -C docs html 27 | 28 | build: env 29 | env: ## Make a dev environment 30 | conda create -y -n $(ENV) -c conda-forge python=3 \ 31 | --file requirements.txt \ 32 | --file requirements-test.txt 33 | $(SA) $(ENV) && \ 34 | pip install -r requirements-doc.txt -r requirements-demo.txt && \ 35 | npm install && \ 36 | npm run bower && \ 37 | pip install -e . && \ 38 | jupyter dashboards quick-setup --sys-prefix && \ 39 | jupyter nbextension enable --py widgetsnbextension --sys-prefix 40 | #jupyter declarativewidgets quick-setup --sys-prefix 41 | 42 | js: ## Make JavaScript assets 43 | npm install 44 | npm run bower 45 | $(SA) $(ENV) && \ 46 | pip install -e . && \ 47 | jupyter dashboards quick-setup --sys-prefix 48 | 49 | notebook: ## Make a notebook server 50 | $(SA) $(ENV) && jupyter notebook --notebook-dir=./etc/notebooks 51 | 52 | nuke: clean ## Make clean + remove conda env 53 | -conda env remove -n $(ENV) -y 54 | 55 | release: js ## Make a release on PyPI 56 | $(SA) $(ENV) && python setup.py sdist register upload 57 | 58 | sdist: js ## Make a dist/*.tar.gz source distribution 59 | $(SA) $(ENV) && python setup.py sdist 60 | 61 | test: ## Make a local test run 62 | @./system-test/bin/run-system-test.sh 63 | 64 | test-saucelabs: 65 | @TEST_SERVER=ondemand.saucelabs.com TEST_TYPE=remote ./system-test/bin/run-system-test.sh 66 | 67 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # [RETIRED] Jupyter Dashboards - Layout Extension 2 | 3 | This project has been retired and replaced by incorporating the [Voilà ecosystem of dashboarding tools into Project Jupyter](https://github.com/voila-dashboards). See the [Jupyter blog](https://blog.jupyter.org/and-voil%C3%A0-f6a2c08a4a93) [posts](https://blog.jupyter.org/a-gallery-of-voil%C3%A0-examples-a2ce7ef99130?source=collection_home---6------10-----------------------) about Voilà and the [proposal to make Voilà part of Jupyter](https://github.com/jupyter/enhancement-proposals/blob/master/voila-incorporation/voila-incorporation.md) for more details. [voila-gridstack](https://github.com/voila-dashboards/voila-gridstack) is an on-going project to support layouts created by this deprecated extension using Voilà. 4 | 5 | --- 6 | 7 | [![Project Status: Inactive – The project has reached a stable, usable state but is no longer being actively developed; support/maintenance will be provided as time allows.](https://www.repostatus.org/badges/latest/inactive.svg)](https://www.repostatus.org/#inactive) 8 | [![PyPI version](https://badge.fury.io/py/jupyter_dashboards.svg)](https://badge.fury.io/py/jupyter_dashboards) [![Build Status](https://travis-ci.org/jupyter/dashboards.svg?branch=master)](https://travis-ci.org/jupyter/dashboards) [![Google Group](https://img.shields.io/badge/-Google%20Group-lightgrey.svg)](https://groups.google.com/forum/#!forum/jupyter) 9 | 10 | ## Overview 11 | 12 | The dashboards layout extension is an add-on for Jupyter Notebook. It lets you 13 | arrange your notebook outputs (text, plots, widgets, ...) in grid- or 14 | report-like layouts. It saves information about your layouts in your notebook 15 | document. Other people with the extension can open your notebook and view your 16 | layouts. 17 | 18 | ![Dashboard layout screenshot](docs/source/_static/dashboards_intro.png) 19 | 20 | For a sample of what's possible with the dashboard layout extension, have a look at the [demo dashboard-notebooks](etc/notebooks) in this repository. 21 | 22 | ## Installation 23 | 24 | Detailed installation instructions appear in the [Getting started 25 | page](http://jupyter-dashboards-layout.readthedocs.io/en/latest/getting-started.html) 26 | of the project docs. Here's a quickstart using pip or conda: 27 | 28 | ```bash 29 | # install using pip from pypi and then activate the extension 30 | pip install jupyter_dashboards 31 | jupyter dashboards quick-setup --sys-prefix 32 | 33 | # install using conda from conda-forge, no activation required 34 | conda install jupyter_dashboards -c conda-forge 35 | ``` 36 | 37 | ## Contributing 38 | 39 | The [Development 40 | page](http://jupyter-dashboards-layout.readthedocs.io/en/latest/development.html) 41 | includes information about setting up a dev environment and typical dev tasks. 42 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "dashboard-nbexts", 3 | "authors": [ 4 | "Jupyter Community" 5 | ], 6 | "main": "main.js", 7 | "moduleType": [ 8 | "amd" 9 | ], 10 | "ignore": [ 11 | "**/.*", 12 | "node_modules", 13 | "bower_components", 14 | "test", 15 | "tests" 16 | ], 17 | "dependencies": { 18 | "gridstack": "0.2.4", 19 | "requirejs": "~2.1.20", 20 | "requirejs-text": "~2.0.14" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # Makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line. 5 | SPHINXOPTS = 6 | SPHINXBUILD = sphinx-build 7 | PAPER = 8 | BUILDDIR = _build 9 | 10 | # User-friendly check for sphinx-build 11 | ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1) 12 | $(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don\'t have Sphinx installed, grab it from http://sphinx-doc.org/) 13 | endif 14 | 15 | # Internal variables. 16 | PAPEROPT_a4 = -D latex_paper_size=a4 17 | PAPEROPT_letter = -D latex_paper_size=letter 18 | ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source 19 | # the i18n builder cannot share the environment and doctrees with the others 20 | I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source 21 | 22 | .PHONY: help 23 | help: 24 | @echo "Please use \`make ' where is one of" 25 | @echo " html to make standalone HTML files" 26 | @echo " dirhtml to make HTML files named index.html in directories" 27 | @echo " singlehtml to make a single large HTML file" 28 | @echo " pickle to make pickle files" 29 | @echo " json to make JSON files" 30 | @echo " htmlhelp to make HTML files and a HTML help project" 31 | @echo " qthelp to make HTML files and a qthelp project" 32 | @echo " applehelp to make an Apple Help Book" 33 | @echo " devhelp to make HTML files and a Devhelp project" 34 | @echo " epub to make an epub" 35 | @echo " epub3 to make an epub3" 36 | @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" 37 | @echo " latexpdf to make LaTeX files and run them through pdflatex" 38 | @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx" 39 | @echo " text to make text files" 40 | @echo " man to make manual pages" 41 | @echo " texinfo to make Texinfo files" 42 | @echo " info to make Texinfo files and run them through makeinfo" 43 | @echo " gettext to make PO message catalogs" 44 | @echo " changes to make an overview of all changed/added/deprecated items" 45 | @echo " xml to make Docutils-native XML files" 46 | @echo " pseudoxml to make pseudoxml-XML files for display purposes" 47 | @echo " linkcheck to check all external links for integrity" 48 | @echo " doctest to run all doctests embedded in the documentation (if enabled)" 49 | @echo " coverage to run coverage check of the documentation (if enabled)" 50 | @echo " dummy to check syntax errors of document sources" 51 | 52 | .PHONY: clean 53 | clean: 54 | rm -rf $(BUILDDIR)/* 55 | 56 | .PHONY: html 57 | html: 58 | $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html 59 | @echo 60 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." 61 | 62 | .PHONY: dirhtml 63 | dirhtml: 64 | $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml 65 | @echo 66 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." 67 | 68 | .PHONY: singlehtml 69 | singlehtml: 70 | $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml 71 | @echo 72 | @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." 73 | 74 | .PHONY: pickle 75 | pickle: 76 | $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle 77 | @echo 78 | @echo "Build finished; now you can process the pickle files." 79 | 80 | .PHONY: json 81 | json: 82 | $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json 83 | @echo 84 | @echo "Build finished; now you can process the JSON files." 85 | 86 | .PHONY: htmlhelp 87 | htmlhelp: 88 | $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp 89 | @echo 90 | @echo "Build finished; now you can run HTML Help Workshop with the" \ 91 | ".hhp project file in $(BUILDDIR)/htmlhelp." 92 | 93 | .PHONY: qthelp 94 | qthelp: 95 | $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp 96 | @echo 97 | @echo "Build finished; now you can run "qcollectiongenerator" with the" \ 98 | ".qhcp project file in $(BUILDDIR)/qthelp, like this:" 99 | @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/Dashboards.qhcp" 100 | @echo "To view the help file:" 101 | @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/Dashboards.qhc" 102 | 103 | .PHONY: applehelp 104 | applehelp: 105 | $(SPHINXBUILD) -b applehelp $(ALLSPHINXOPTS) $(BUILDDIR)/applehelp 106 | @echo 107 | @echo "Build finished. The help book is in $(BUILDDIR)/applehelp." 108 | @echo "N.B. You won't be able to view it unless you put it in" \ 109 | "~/Library/Documentation/Help or install it in your application" \ 110 | "bundle." 111 | 112 | .PHONY: devhelp 113 | devhelp: 114 | $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp 115 | @echo 116 | @echo "Build finished." 117 | @echo "To view the help file:" 118 | @echo "# mkdir -p $$HOME/.local/share/devhelp/Dashboards" 119 | @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/Dashboards" 120 | @echo "# devhelp" 121 | 122 | .PHONY: epub 123 | epub: 124 | $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub 125 | @echo 126 | @echo "Build finished. The epub file is in $(BUILDDIR)/epub." 127 | 128 | .PHONY: epub3 129 | epub3: 130 | $(SPHINXBUILD) -b epub3 $(ALLSPHINXOPTS) $(BUILDDIR)/epub3 131 | @echo 132 | @echo "Build finished. The epub3 file is in $(BUILDDIR)/epub3." 133 | 134 | .PHONY: latex 135 | latex: 136 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 137 | @echo 138 | @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." 139 | @echo "Run \`make' in that directory to run these through (pdf)latex" \ 140 | "(use \`make latexpdf' here to do that automatically)." 141 | 142 | .PHONY: latexpdf 143 | latexpdf: 144 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 145 | @echo "Running LaTeX files through pdflatex..." 146 | $(MAKE) -C $(BUILDDIR)/latex all-pdf 147 | @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." 148 | 149 | .PHONY: latexpdfja 150 | latexpdfja: 151 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 152 | @echo "Running LaTeX files through platex and dvipdfmx..." 153 | $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja 154 | @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." 155 | 156 | .PHONY: text 157 | text: 158 | $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text 159 | @echo 160 | @echo "Build finished. The text files are in $(BUILDDIR)/text." 161 | 162 | .PHONY: man 163 | man: 164 | $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man 165 | @echo 166 | @echo "Build finished. The manual pages are in $(BUILDDIR)/man." 167 | 168 | .PHONY: texinfo 169 | texinfo: 170 | $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo 171 | @echo 172 | @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." 173 | @echo "Run \`make' in that directory to run these through makeinfo" \ 174 | "(use \`make info' here to do that automatically)." 175 | 176 | .PHONY: info 177 | info: 178 | $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo 179 | @echo "Running Texinfo files through makeinfo..." 180 | make -C $(BUILDDIR)/texinfo info 181 | @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." 182 | 183 | .PHONY: gettext 184 | gettext: 185 | $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale 186 | @echo 187 | @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." 188 | 189 | .PHONY: changes 190 | changes: 191 | $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes 192 | @echo 193 | @echo "The overview file is in $(BUILDDIR)/changes." 194 | 195 | .PHONY: linkcheck 196 | linkcheck: 197 | $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck 198 | @echo 199 | @echo "Link check complete; look for any errors in the above output " \ 200 | "or in $(BUILDDIR)/linkcheck/output.txt." 201 | 202 | .PHONY: doctest 203 | doctest: 204 | $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest 205 | @echo "Testing of doctests in the sources finished, look at the " \ 206 | "results in $(BUILDDIR)/doctest/output.txt." 207 | 208 | .PHONY: coverage 209 | coverage: 210 | $(SPHINXBUILD) -b coverage $(ALLSPHINXOPTS) $(BUILDDIR)/coverage 211 | @echo "Testing of coverage in the sources finished, look at the " \ 212 | "results in $(BUILDDIR)/coverage/python.txt." 213 | 214 | .PHONY: xml 215 | xml: 216 | $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml 217 | @echo 218 | @echo "Build finished. The XML files are in $(BUILDDIR)/xml." 219 | 220 | .PHONY: pseudoxml 221 | pseudoxml: 222 | $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml 223 | @echo 224 | @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." 225 | 226 | .PHONY: dummy 227 | dummy: 228 | $(SPHINXBUILD) -b dummy $(ALLSPHINXOPTS) $(BUILDDIR)/dummy 229 | @echo 230 | @echo "Build finished. Dummy builder generates no files." 231 | -------------------------------------------------------------------------------- /docs/environment.yml: -------------------------------------------------------------------------------- 1 | name: dashboard_docs 2 | dependencies: 3 | - python=3.5 4 | - sphinx_rtd_theme 5 | - sphinx 6 | - pip: 7 | - recommonmark 8 | 9 | -------------------------------------------------------------------------------- /docs/make.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | REM Command file for Sphinx documentation 4 | 5 | if "%SPHINXBUILD%" == "" ( 6 | set SPHINXBUILD=sphinx-build 7 | ) 8 | set BUILDDIR=_build 9 | set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% . 10 | set I18NSPHINXOPTS=%SPHINXOPTS% . 11 | if NOT "%PAPER%" == "" ( 12 | set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% 13 | set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS% 14 | ) 15 | 16 | if "%1" == "" goto help 17 | 18 | if "%1" == "help" ( 19 | :help 20 | echo.Please use `make ^` where ^ is one of 21 | echo. html to make standalone HTML files 22 | echo. dirhtml to make HTML files named index.html in directories 23 | echo. singlehtml to make a single large HTML file 24 | echo. pickle to make pickle files 25 | echo. json to make JSON files 26 | echo. htmlhelp to make HTML files and a HTML help project 27 | echo. qthelp to make HTML files and a qthelp project 28 | echo. devhelp to make HTML files and a Devhelp project 29 | echo. epub to make an epub 30 | echo. epub3 to make an epub3 31 | echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter 32 | echo. text to make text files 33 | echo. man to make manual pages 34 | echo. texinfo to make Texinfo files 35 | echo. gettext to make PO message catalogs 36 | echo. changes to make an overview over all changed/added/deprecated items 37 | echo. xml to make Docutils-native XML files 38 | echo. pseudoxml to make pseudoxml-XML files for display purposes 39 | echo. linkcheck to check all external links for integrity 40 | echo. doctest to run all doctests embedded in the documentation if enabled 41 | echo. coverage to run coverage check of the documentation if enabled 42 | echo. dummy to check syntax errors of document sources 43 | goto end 44 | ) 45 | 46 | if "%1" == "clean" ( 47 | for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i 48 | del /q /s %BUILDDIR%\* 49 | goto end 50 | ) 51 | 52 | 53 | REM Check if sphinx-build is available and fallback to Python version if any 54 | %SPHINXBUILD% 1>NUL 2>NUL 55 | if errorlevel 9009 goto sphinx_python 56 | goto sphinx_ok 57 | 58 | :sphinx_python 59 | 60 | set SPHINXBUILD=python -m sphinx.__init__ 61 | %SPHINXBUILD% 2> nul 62 | if errorlevel 9009 ( 63 | echo. 64 | echo.The 'sphinx-build' command was not found. Make sure you have Sphinx 65 | echo.installed, then set the SPHINXBUILD environment variable to point 66 | echo.to the full path of the 'sphinx-build' executable. Alternatively you 67 | echo.may add the Sphinx directory to PATH. 68 | echo. 69 | echo.If you don't have Sphinx installed, grab it from 70 | echo.http://sphinx-doc.org/ 71 | exit /b 1 72 | ) 73 | 74 | :sphinx_ok 75 | 76 | 77 | if "%1" == "html" ( 78 | %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html 79 | if errorlevel 1 exit /b 1 80 | echo. 81 | echo.Build finished. The HTML pages are in %BUILDDIR%/html. 82 | goto end 83 | ) 84 | 85 | if "%1" == "dirhtml" ( 86 | %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml 87 | if errorlevel 1 exit /b 1 88 | echo. 89 | echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml. 90 | goto end 91 | ) 92 | 93 | if "%1" == "singlehtml" ( 94 | %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml 95 | if errorlevel 1 exit /b 1 96 | echo. 97 | echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml. 98 | goto end 99 | ) 100 | 101 | if "%1" == "pickle" ( 102 | %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle 103 | if errorlevel 1 exit /b 1 104 | echo. 105 | echo.Build finished; now you can process the pickle files. 106 | goto end 107 | ) 108 | 109 | if "%1" == "json" ( 110 | %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json 111 | if errorlevel 1 exit /b 1 112 | echo. 113 | echo.Build finished; now you can process the JSON files. 114 | goto end 115 | ) 116 | 117 | if "%1" == "htmlhelp" ( 118 | %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp 119 | if errorlevel 1 exit /b 1 120 | echo. 121 | echo.Build finished; now you can run HTML Help Workshop with the ^ 122 | .hhp project file in %BUILDDIR%/htmlhelp. 123 | goto end 124 | ) 125 | 126 | if "%1" == "qthelp" ( 127 | %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp 128 | if errorlevel 1 exit /b 1 129 | echo. 130 | echo.Build finished; now you can run "qcollectiongenerator" with the ^ 131 | .qhcp project file in %BUILDDIR%/qthelp, like this: 132 | echo.^> qcollectiongenerator %BUILDDIR%\qthelp\Dashboards.qhcp 133 | echo.To view the help file: 134 | echo.^> assistant -collectionFile %BUILDDIR%\qthelp\Dashboards.ghc 135 | goto end 136 | ) 137 | 138 | if "%1" == "devhelp" ( 139 | %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp 140 | if errorlevel 1 exit /b 1 141 | echo. 142 | echo.Build finished. 143 | goto end 144 | ) 145 | 146 | if "%1" == "epub" ( 147 | %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub 148 | if errorlevel 1 exit /b 1 149 | echo. 150 | echo.Build finished. The epub file is in %BUILDDIR%/epub. 151 | goto end 152 | ) 153 | 154 | if "%1" == "epub3" ( 155 | %SPHINXBUILD% -b epub3 %ALLSPHINXOPTS% %BUILDDIR%/epub3 156 | if errorlevel 1 exit /b 1 157 | echo. 158 | echo.Build finished. The epub3 file is in %BUILDDIR%/epub3. 159 | goto end 160 | ) 161 | 162 | if "%1" == "latex" ( 163 | %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex 164 | if errorlevel 1 exit /b 1 165 | echo. 166 | echo.Build finished; the LaTeX files are in %BUILDDIR%/latex. 167 | goto end 168 | ) 169 | 170 | if "%1" == "latexpdf" ( 171 | %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex 172 | cd %BUILDDIR%/latex 173 | make all-pdf 174 | cd %~dp0 175 | echo. 176 | echo.Build finished; the PDF files are in %BUILDDIR%/latex. 177 | goto end 178 | ) 179 | 180 | if "%1" == "latexpdfja" ( 181 | %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex 182 | cd %BUILDDIR%/latex 183 | make all-pdf-ja 184 | cd %~dp0 185 | echo. 186 | echo.Build finished; the PDF files are in %BUILDDIR%/latex. 187 | goto end 188 | ) 189 | 190 | if "%1" == "text" ( 191 | %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text 192 | if errorlevel 1 exit /b 1 193 | echo. 194 | echo.Build finished. The text files are in %BUILDDIR%/text. 195 | goto end 196 | ) 197 | 198 | if "%1" == "man" ( 199 | %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man 200 | if errorlevel 1 exit /b 1 201 | echo. 202 | echo.Build finished. The manual pages are in %BUILDDIR%/man. 203 | goto end 204 | ) 205 | 206 | if "%1" == "texinfo" ( 207 | %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo 208 | if errorlevel 1 exit /b 1 209 | echo. 210 | echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo. 211 | goto end 212 | ) 213 | 214 | if "%1" == "gettext" ( 215 | %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale 216 | if errorlevel 1 exit /b 1 217 | echo. 218 | echo.Build finished. The message catalogs are in %BUILDDIR%/locale. 219 | goto end 220 | ) 221 | 222 | if "%1" == "changes" ( 223 | %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes 224 | if errorlevel 1 exit /b 1 225 | echo. 226 | echo.The overview file is in %BUILDDIR%/changes. 227 | goto end 228 | ) 229 | 230 | if "%1" == "linkcheck" ( 231 | %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck 232 | if errorlevel 1 exit /b 1 233 | echo. 234 | echo.Link check complete; look for any errors in the above output ^ 235 | or in %BUILDDIR%/linkcheck/output.txt. 236 | goto end 237 | ) 238 | 239 | if "%1" == "doctest" ( 240 | %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest 241 | if errorlevel 1 exit /b 1 242 | echo. 243 | echo.Testing of doctests in the sources finished, look at the ^ 244 | results in %BUILDDIR%/doctest/output.txt. 245 | goto end 246 | ) 247 | 248 | if "%1" == "coverage" ( 249 | %SPHINXBUILD% -b coverage %ALLSPHINXOPTS% %BUILDDIR%/coverage 250 | if errorlevel 1 exit /b 1 251 | echo. 252 | echo.Testing of coverage in the sources finished, look at the ^ 253 | results in %BUILDDIR%/coverage/python.txt. 254 | goto end 255 | ) 256 | 257 | if "%1" == "xml" ( 258 | %SPHINXBUILD% -b xml %ALLSPHINXOPTS% %BUILDDIR%/xml 259 | if errorlevel 1 exit /b 1 260 | echo. 261 | echo.Build finished. The XML files are in %BUILDDIR%/xml. 262 | goto end 263 | ) 264 | 265 | if "%1" == "pseudoxml" ( 266 | %SPHINXBUILD% -b pseudoxml %ALLSPHINXOPTS% %BUILDDIR%/pseudoxml 267 | if errorlevel 1 exit /b 1 268 | echo. 269 | echo.Build finished. The pseudo-XML files are in %BUILDDIR%/pseudoxml. 270 | goto end 271 | ) 272 | 273 | if "%1" == "dummy" ( 274 | %SPHINXBUILD% -b dummy %ALLSPHINXOPTS% %BUILDDIR%/dummy 275 | if errorlevel 1 exit /b 1 276 | echo. 277 | echo.Build finished. Dummy builder generates no files. 278 | goto end 279 | ) 280 | 281 | :end 282 | -------------------------------------------------------------------------------- /docs/source/_static/dashboard_rendering.graffle: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jupyter/dashboards/d5393ccd0081b2f67c2140257917c75cb8174da8/docs/source/_static/dashboard_rendering.graffle -------------------------------------------------------------------------------- /docs/source/_static/dashboards_intro.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jupyter/dashboards/d5393ccd0081b2f67c2140257917c75cb8174da8/docs/source/_static/dashboards_intro.png -------------------------------------------------------------------------------- /docs/source/_static/grid_layout.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jupyter/dashboards/d5393ccd0081b2f67c2140257917c75cb8174da8/docs/source/_static/grid_layout.png -------------------------------------------------------------------------------- /docs/source/_static/layout_toolbar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jupyter/dashboards/d5393ccd0081b2f67c2140257917c75cb8174da8/docs/source/_static/layout_toolbar.png -------------------------------------------------------------------------------- /docs/source/_static/metadata_grid_layout.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jupyter/dashboards/d5393ccd0081b2f67c2140257917c75cb8174da8/docs/source/_static/metadata_grid_layout.png -------------------------------------------------------------------------------- /docs/source/_static/metadata_report_layout.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jupyter/dashboards/d5393ccd0081b2f67c2140257917c75cb8174da8/docs/source/_static/metadata_report_layout.png -------------------------------------------------------------------------------- /docs/source/_static/more_info.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jupyter/dashboards/d5393ccd0081b2f67c2140257917c75cb8174da8/docs/source/_static/more_info.png -------------------------------------------------------------------------------- /docs/source/_static/notebook.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jupyter/dashboards/d5393ccd0081b2f67c2140257917c75cb8174da8/docs/source/_static/notebook.png -------------------------------------------------------------------------------- /docs/source/_static/notebook_toolbar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jupyter/dashboards/d5393ccd0081b2f67c2140257917c75cb8174da8/docs/source/_static/notebook_toolbar.png -------------------------------------------------------------------------------- /docs/source/_static/preview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jupyter/dashboards/d5393ccd0081b2f67c2140257917c75cb8174da8/docs/source/_static/preview.png -------------------------------------------------------------------------------- /docs/source/_static/report_layout.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jupyter/dashboards/d5393ccd0081b2f67c2140257917c75cb8174da8/docs/source/_static/report_layout.png -------------------------------------------------------------------------------- /docs/source/_static/workflow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jupyter/dashboards/d5393ccd0081b2f67c2140257917c75cb8174da8/docs/source/_static/workflow.png -------------------------------------------------------------------------------- /docs/source/development.md: -------------------------------------------------------------------------------- 1 | # Developer tasks 2 | 3 | This document includes instructions development environment for the dashboards 4 | layout extension. It also includes common steps in the developer workflow such 5 | as running tests, building docs, etc. 6 | 7 | Install [conda](https://conda.io/miniconda.html) on your system. 8 | Then clone this repository in a local directory. 9 | 10 | ```bash 11 | # make a directory under ~ to put source 12 | mkdir -p ~/projects 13 | cd !$ 14 | 15 | # clone this repo 16 | git clone https://github.com/jupyter/dashboards.git 17 | ``` 18 | 19 | Create a conda environment with the necessary dev and test dependencies. 20 | 21 | ```bash 22 | cd dashboards 23 | make env 24 | ``` 25 | 26 | Install the necessary JS dependencies. Re-run this command any time your 27 | `bower.json` or `package.json` changes. 28 | 29 | ```bash 30 | make js 31 | ``` 32 | 33 | Run a notebook server with the dashboard extension enabled. 34 | 35 | ```bash 36 | make notebook 37 | ``` 38 | 39 | Travis runs a small set of UI smoke tests using Selenium on Sauce Labs on every 40 | merge to the git master branch. You can run these tests locally if you install 41 | Selenium. 42 | 43 | ```bash 44 | # install selenium first, e.g., on OSX 45 | brew install selenium-server-standalone 46 | # run the smoke tests 47 | make test 48 | ``` 49 | 50 | ReadTheDocs builds the project documentation on every merge to git master. 51 | You can build the documentation locally as well. 52 | 53 | ```bash 54 | make docs 55 | ``` 56 | 57 | Run `make help` to get a full list of development tasks. 58 | -------------------------------------------------------------------------------- /docs/source/getting-started.md: -------------------------------------------------------------------------------- 1 | # Getting started 2 | 3 | This document describes some of the basics of installing and enabling the 4 | dashboards layout extension. 5 | 6 | ## Prerequisites 7 | 8 | * Jupyter Notebook >=4.2 running on Python 3.x or Python 2.7.x 9 | * Edge, Chrome, Firefox, or Safari 10 | 11 | ## Installing and Enabling 12 | 13 | The following steps install the extension package using `pip` and enable the 14 | extension in the active Python environment. 15 | 16 | ```bash 17 | pip install jupyter_dashboards 18 | jupyter dashboards quick-setup --sys-prefix 19 | ``` 20 | 21 | Run `jupyter dashboards quick-setup --help` for other options. Note that the 22 | second command is a shortcut for the following: 23 | 24 | ```bash 25 | jupyter nbextension install --py jupyter_dashboards --sys-prefix 26 | jupyter nbextension enable --py jupyter_dashboards --sys-prefix 27 | ``` 28 | 29 | Alternatively, the following command both installs and enables the package 30 | using `conda`. 31 | 32 | ```bash 33 | conda install jupyter_dashboards -c conda-forge 34 | ``` 35 | 36 | ## Disabling and Uninstalling 37 | 38 | The following steps deactivate the extension in the active Python environment 39 | and uninstall the package using `pip`. 40 | 41 | ```bash 42 | jupyter dashboards quick-remove --sys-prefix 43 | pip uninstall jupyter_dashboards 44 | ``` 45 | 46 | Note that the first command is a shortcut for the following: 47 | 48 | ```bash 49 | jupyter nbextension disable --py jupyter_dashboards --sys-prefix 50 | jupyter nbextension uninstall --py jupyter_dashboards --sys-prefix 51 | ``` 52 | 53 | The following command deactivates and uninstalls the package if it was 54 | installed using `conda`. 55 | 56 | ```bash 57 | conda remove jupyter_dashboards 58 | ``` 59 | 60 | ## Legacy Notes 61 | 62 | If you installed the dashboard extension against Jupyter notebook 4.0 or 4.1, 63 | you may need to manually remove this line from your 64 | `jupyter_notebook_config.py` file when uninstalling or upgrading: 65 | 66 | ```python 67 | # [YOUR_JUPYTER_CONFIG_PATH]/jupyter_notebook_config.py 68 | c.NotebookApp.server_extensions.append('urth.dashboard.nbexts') 69 | ``` 70 | -------------------------------------------------------------------------------- /docs/source/index.rst: -------------------------------------------------------------------------------- 1 | Jupyter Dashboards Layout Extension 2 | =================================== 3 | 4 | The dashboards layout extension is an add-on for Jupyter Notebook. It lets you arrange your notebook outputs (text, plots, widgets, ...) in grid- or report-like layouts. It saves information about your layouts in your notebook document. Other people with the extension can open your notebook and view your layouts. 5 | 6 | .. image:: _static/dashboards_intro.png 7 | :alt: Dashboard layout screenshot 8 | 9 | For a sample of what's possible with the dashboard layout extension, have a look at the `demo dashboard-notebooks in the project repository `__. 10 | 11 | .. toctree:: 12 | :maxdepth: 2 13 | :caption: User Documentation 14 | 15 | getting-started 16 | using 17 | use-cases 18 | 19 | .. toctree:: 20 | :maxdepth: 2 21 | :caption: Contributor Documentation 22 | 23 | development 24 | maintenance 25 | metadata 26 | 27 | .. toctree:: 28 | :maxdepth: 2 29 | :caption: About Dashboards Layout 30 | 31 | summary-changes 32 | 33 | .. toctree:: 34 | :maxdepth: 2 35 | :caption: Questions? Suggestions? 36 | 37 | Jupyter mailing list 38 | Jupyter website 39 | Stack Overflow - Jupyter 40 | Stack Overflow - Jupyter-notebook 41 | jupyter/help 42 | 43 | Indices and tables 44 | ================== 45 | 46 | * :ref:`genindex` 47 | * :ref:`modindex` 48 | * :ref:`search` 49 | -------------------------------------------------------------------------------- /docs/source/maintenance.md: -------------------------------------------------------------------------------- 1 | # Maintainer tasks 2 | 3 | This document includes instructions for typical maintainer tasks. 4 | 5 | ## Build a package 6 | 7 | To build a source tarball in `dist/`, run the following: 8 | 9 | ```bash 10 | make sdist 11 | ``` 12 | 13 | ## Make a release 14 | 15 | To start a new major/minor branch for its first release (e.g., 0.3.0): 16 | 17 | ```bash 18 | git checkout master 19 | git pull origin master 20 | git checkout -b 0.3.x 21 | 22 | git checkout master 23 | 24 | # edit _version.py to bump to next major/minor (e.g., 0.4.0.dev) 25 | # then ... 26 | 27 | git add . 28 | git commit -m 'Bump to 0.4.0.dev' 29 | git push origin master 30 | ``` 31 | 32 | To make a patch release on a major/minor branch (e.g., 0.3.0): 33 | 34 | ```bash 35 | # cherry-pick commits into the branch from master 36 | # if there's multiple comments on master, do this ... 37 | git checkout master 38 | git checkout -b tmp-backport-0.3.x 39 | git rebase -i 0.3.x 40 | # delete any version bumps or other commits you don't want 41 | # in the stable release branch from master 42 | git checkout 0.3.x 43 | git merge tmp-backport-0.3.x 44 | git branch -D tmp-backport-0.3.x 45 | 46 | # if there's only one or two commits, just use cherry-pick 47 | # then ... 48 | git checkout -b 0.3.x 49 | 50 | # edit _version.py to remove the trailing 'dev' token 51 | # then ... 52 | 53 | git add . 54 | git commit -m 'Release 0.3.0' 55 | git tag 0.3.0 56 | 57 | # do the release 58 | make release 59 | 60 | # edit _version.py to bump to 0.3.1.dev 61 | # then ... 62 | 63 | git add . 64 | git commit -m 'Bump to 0.3.1.dev' 65 | 66 | git push origin 0.3.x 67 | git push origin 0.3.0 68 | ``` 69 | -------------------------------------------------------------------------------- /docs/source/summary-changes.md: -------------------------------------------------------------------------------- 1 | # Summary of changes 2 | 3 | See `git log` for a more detailed summary of changes. 4 | 5 | ## 0.7 6 | 7 | ### 0.7.0 (2017-04-04) 8 | 9 | * Updated to support notebook 5.0 10 | * Fixed clipping at cell boundaries 11 | 12 | ## 0.6 13 | 14 | ### 0.6.0 (2016-06-17) 15 | 16 | * Switch to the [v1 dashboard layout specification](https://github.com/jupyter/dashboards/wiki/Dashboard-Metadata-and-Rendering) 17 | * Automatically upgrade existing notebook metadata to the v1 spec 18 | * Update example notebooks for compatibility with `jupyter_declarativewidgets` 0.6.0 19 | * Remove `urth` moniker in favor of `jupyter_dashboards` for CSS classes, notebook metadata, etc. 20 | * Fix gaps in grid when hiding cells 21 | 22 | ## 0.5 23 | 24 | ### 0.5.2 (2016-05-11) 25 | 26 | * Fix report layout reset when switching between dashboard layout and preview 27 | 28 | ### 0.5.1 (2016-05-11) 29 | 30 | * Hide errors from declarative widgets in dashboard layout and preview 31 | * Fix the state of the show code checkbox in layout view when switching layout types 32 | * Fix history window slider widgetin the community outreach demo 33 | * Fix missing imports in the declarative widgets scotch demo 34 | * Fix copy/pasted cells receive the same layout metadata 35 | * Fix lost cells in report layout after clear and refresh 36 | * Fix layout toolbar button default state 37 | 38 | ### 0.5.0 (2016-04-26) 39 | 40 | * Add report layout for simple top-to-bottom, full-width dashboards 41 | * Add buttons to move a cell to the top, bottom, or notebook order in layout mode 42 | * Make compatible with Jupyter Notebook 4.0.x to 4.2.x 43 | * Fix bokeh example race condition 44 | * Fix browser scrolling when dragging cells in layout view 45 | 46 | ## 0.4 47 | 48 | ### 0.4.2 (2016-02-18) 49 | 50 | * Fix code cell overflow in layout mode 51 | * Fix scroll bars that appear within cells of a certain size 52 | * Fix hidden cells from being cut-off in layout mode 53 | * Fix failure to load extension JS in certain situations 54 | * Fix meetup streaming demo filter box 55 | * Update to Gridstack 0.2.4 to remove a workaround 56 | 57 | ### 0.4.1 (2016-02-07) 58 | 59 | * Fix gridstack break with lodash>=4.0 60 | * Remove notebook 4.1 cell focus highlight in dashboard preview 61 | * Hide stderr and errors in dashboard preview, send them to the browser console 62 | 63 | ### 0.4.0 (2016-01-21) 64 | 65 | * Separate `pip install` from `jupyter dashboards [install | activate | deactivate]` 66 | * Match the Python package to the distribution name, `jupyter_dashboards` 67 | * Fix cell overlap when one cell has the minimum height 68 | * Prevent stderr and exception messages from displaying in dashboard modes 69 | * Update demo notebooks to stop using deprecated `UrthData.setItem` from declarative widgets. 70 | 71 | ## 0.3 72 | 73 | ### 0.3.0 (2015-12-30) 74 | 75 | * Make compatible with Jupyter Notebook 4.1.x 76 | * Remove all download and deployment related backend code in. Refer users to the separate `jupyter_cms` and `jupyter_dashboards_bundlers` packages for these features. 77 | * Keep compatible with Jupyter Notebook 4.0.x 78 | 79 | ## 0.2 80 | 81 | ### 0.2.2 (2015-12-15) 82 | 83 | * Revert to old jupyter\_notebook\_server.py config hack to remain compatible with jupyter\_declarativewidgets and jupyter\_cms (until they change too) 84 | 85 | ### 0.2.1 (2015-12-15) 86 | 87 | * Fix errors on install when profiles don't exist 88 | * Fix styling leaking out of dashboard mode 89 | 90 | ### 0.2.0 (2015-12-01) 91 | 92 | * Default to showing code instead of blank cells in layout mode 93 | * Add menu items for packed vs stacked cell layout 94 | * Make compatible with Jupyter Notebook 4.0.x 95 | * Make compatible with jupyter_declarativewidgets 0.2.x 96 | * System tests using Selenium locally, SauceLabs via Travis 97 | 98 | ## 0.1 99 | 100 | ### 0.1.1 (2015-12-02) 101 | 102 | * Backport of UX fixes from 0.2.0 103 | * Keep compatible with IPython Notebook 3.2.x 104 | * Keep compatible with declarative widgets 0.1.x 105 | 106 | ### 0.1.0 (2015-11-17) 107 | 108 | * First PyPI release 109 | * Compatible with IPython Notebook 3.2.x on Python 2.7 or Python 3.3+ 110 | -------------------------------------------------------------------------------- /docs/source/use-cases.md: -------------------------------------------------------------------------------- 1 | ## Understanding the use case 2 | 3 | The dashboard layout extension is part of a larger Jupyter Dashboards 4 | effort 5 | meant to address the following problem: 6 | 7 | > Alice is a Jupyter Notebook user. Alice prototypes data access, 8 | > modeling, plotting, interactivity, etc. in a notebook. Now Alice 9 | > needs to deliver a dynamic dashboard for non-notebook users. Today, 10 | > Alice must step outside Jupyter Notebook and build a separate web 11 | > application. Alice cannot directly transform her notebook into a 12 | > secure, standalone dashboard application. 13 | 14 | The solution implemented by the Dashboards effort is the following: 15 | 16 | 1. Alice authors a notebook document using Jupyter Notebook. She adds 17 | visualizations and interactive widgets. 18 | 2. Alice arranges her notebook cells in a grid- or report-like dashboard 19 | layout. 20 | 3. Alice one-click deploys her notebook and associated assets to a Jupyter 21 | Dashboards server. 22 | 4. Bob visits the dashboards server and interacts with Alice's 23 | notebook-turned-dashboard application. 24 | 5. Alice updates her notebook with new features and redeploys it to the 25 | dashboards server. 26 | 27 | ![Jupyter dashboards workflow](_static/workflow.png) 28 | 29 | The ecosystem of widget and visualization libraries for Jupyter 30 | Notebook covers step (1). The dashboard layout extension handles step 31 | (2). The other incubating projects in the Jupyter Dashboards effort, 32 | namely the [dashboard 33 | bundlers](https://github.com/jupyter-incubator/dashboards_bundlers) 34 | and [dashboard 35 | server](https://github.com/jupyter-incubator/dashboards_server) 36 | attempt to handle the remaining steps (3) through (5). 37 | -------------------------------------------------------------------------------- /docs/source/using.md: -------------------------------------------------------------------------------- 1 | # Creating dashboard layouts 2 | 3 | This page provides a brief walkthrough of using the dashboard extension. The 4 | extension provides additional, built-in help about all of the dashboard 5 | features. The steps below include instructions on how to access the help. 6 | 7 | Create a new Jupyter notebook document in a language of your choice. Insert 8 | markdown and code into the notebook. Run the cells to generate text, plots, 9 | widgets, etc. 10 | 11 | ![Screenshot of a notebook](_static/notebook.png) 12 | 13 | Select either *Grid Layout* or *Report Layout* in the *Dashboard View* toolbar. 14 | Alternatively, use the options in the *View -> Dashboard Layout* menu. 15 | 16 | ![Screenshot of the dashboard toolbar with layout mode dropdown open](_static/layout_toolbar.png) 17 | 18 | In grid layout, drag handles to resize and move cells in the grid. Click the 19 | buttons to add or remove cells in the layout. Use the *Cell -> Dashboard* menu 20 | items for batch operations.
21 | 22 | ![Screenshot of grid layout authoring](_static/grid_layout.png) 23 | 24 | In report layout, click buttons to show or hide cells.
25 | 26 | ![Screenshot of report layout authoring](_static/report_layout.png) 27 | 28 | Click *More Info* at the top of the layout view for help with additional 29 | features.
30 | 31 | ![Screenshot of more info help](_static/more_info.png) 32 | 33 | Click the *Dashboard Preview* button in the toolbar to view and interact with 34 | the cells without the authoring tools. Alternatively, click the *Dashboard 35 | Preview* menu item in the *View* menu.
36 | 37 | ![Screenshot of dashboard preview](_static/preview.png) 38 | 39 | Click the *Notebook View* button in the toolbar to return to the notebook 40 | editor. Alternatively, click the *Notebook* menu item in the *View* menu. 41 |
42 | 43 | ![Screenshot of notebook view toolbar button](_static/notebook_toolbar.png) 44 | -------------------------------------------------------------------------------- /etc/notebooks/README.md: -------------------------------------------------------------------------------- 1 | # Jupyter Dashboards Demos 2 | 3 | The [dashboards layout extension](https://github.com/jupyter/dashboards) is an 4 | add-on for Jupyter Notebook. It lets you arrange your notebook outputs (text, 5 | plots, widgets, ...) in grid- or report-like layouts. It saves information 6 | about your layouts in your notebook document. Other people with the extension 7 | can open your notebook and view your layouts. 8 | 9 | The git repository for the project contains a handful of notebooks that you can 10 | run and modify to learn how the dashboards extension works. After installing 11 | the extension and learning the basics by reading the 12 | [documentation](http://jupyter-dashboards-layout.readthedocs.io/en/latest/index.html), 13 | do the following to get a copy of the example notebooks to run yourself. 14 | 15 | ``` 16 | # Get a copy of the project source and example notebooks 17 | git clone https://github.com/jupyter/dashboards.git 18 | 19 | # Activate the virtualenv or conda environment containing your 20 | # install of jupyter notebook and the extension. Then install 21 | # the demo requirements. 22 | pip install -r dashboards/requirements-demo.txt 23 | 24 | # Run the notebook server. 25 | jupyter notebook --notebook-dir=./dashboards/etc/notebooks/ 26 | ``` 27 | 28 | The following demos are kept up-to-date as issues with dependencies are found and fixed. 29 | 30 | 1. [Got Scotch?](got_scotch_demo/scotch_dashboard.ipynb) - show similarities 31 | between scotch varieties 32 | 2. [Plotting demo](plotting_demo.ipynb) - shows how matplotlib, bokeh, and plotly work in a dashboard layout 33 | -------------------------------------------------------------------------------- /etc/notebooks/declarativewidgets/community_sentiment_demo/widgets/urth-timeline/bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "urth-timeline", 3 | "version": "0.0.0", 4 | "description": "A timeline.", 5 | "authors": [ 6 | "IBM" 7 | ], 8 | "license": "MIT", 9 | "ignore": [ 10 | "**/.*", 11 | "node_modules", 12 | "bower_components", 13 | "test", 14 | "tests" 15 | ], 16 | "dependencies" : { 17 | "polymer": "Polymer/polymer#^1.0.0", 18 | "paper-radio-button": "PolymerElements/paper-radio-button#^1.0.0", 19 | "paper-radio-group": "PolymerElements/paper-radio-group#^1.0.0", 20 | "paper-checkbox": "PolymerElements/paper-checkbox#^1.0.0", 21 | "paper-item": "PolymerElements/paper-item#^1.0.0", 22 | "iron-icons": "PolymerElements/iron-icons#^1.0.0" 23 | }, 24 | "main" : "urth-timeline.html", 25 | "private" : true 26 | } 27 | -------------------------------------------------------------------------------- /etc/notebooks/declarativewidgets/meetup_outreach_demo/widgets/dynamic-list/bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "dynamic-list", 3 | "version": "0.0.1", 4 | "description": "A dynamic list", 5 | "authors": [ 6 | "IBM" 7 | ], 8 | "license": "MIT", 9 | "ignore": [ 10 | "**/.*", 11 | "node_modules", 12 | "bower_components" 13 | ], 14 | "dependencies" : { 15 | "polymer": "Polymer/polymer#^1.0.0", 16 | "iron-icons": "PolymerElements/iron-list#^1.0.0", 17 | "paper-radio-button": "PolymerElements/paper-material#^1.0.0", 18 | "paper-radio-group": "PolymerElements/paper-toggle-button#^1.0.0" 19 | }, 20 | "main" : "dynamic-list.html", 21 | "private" : true 22 | } 23 | -------------------------------------------------------------------------------- /etc/notebooks/declarativewidgets/meetup_outreach_demo/widgets/upcoming-meetups/bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "upcoming-meetups", 3 | "version": "0.0.1", 4 | "description": "A list of future meetups", 5 | "authors": [ 6 | "IBM" 7 | ], 8 | "license": "MIT", 9 | "ignore": [ 10 | "**/.*", 11 | "node_modules", 12 | "bower_components" 13 | ], 14 | "dependencies" : { 15 | "polymer": "Polymer/polymer#^1.0.0", 16 | "iron-icons": "PolymerElements/iron-list#^1.0.0", 17 | "iron-icons": "PolymerElements/iron-resizable-behavior#^1.0.0", 18 | "paper-radio-button": "PolymerElements/paper-material#^1.0.0" 19 | }, 20 | "main" : "upcoming-meetups.html", 21 | "private" : true 22 | } 23 | -------------------------------------------------------------------------------- /etc/notebooks/declarativewidgets/meetup_outreach_demo/widgets/upcoming-meetups/upcoming-meetups.html: -------------------------------------------------------------------------------- 1 | 2 | 107 | 108 | 178 | 179 | -------------------------------------------------------------------------------- /etc/notebooks/declarativewidgets/resizable_widgets_tutorial/resizable_widgets.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": { 6 | "extensions": { 7 | "jupyter_dashboards": { 8 | "version": 1, 9 | "views": { 10 | "grid_default": { 11 | "col": 0, 12 | "height": 6, 13 | "hidden": false, 14 | "row": 0, 15 | "width": 12 16 | }, 17 | "report_default": { 18 | "hidden": false 19 | } 20 | } 21 | } 22 | } 23 | }, 24 | "source": [ 25 | "# Resizable Widget Tutorial\n", 26 | "\n", 27 | "This tutorial demonstrates how to implement a resizable Polymer element for use with the [Dynamic Dashboard](https://github.com/jupyter/dashboards) extension. By using [`iron-resizable-behavior`](https://elements.polymer-project.org/elements/iron-resizable-behavior?active=Polymer.IronResizableBehavior), your widget can be informed when it is resized, allowing you to act accordingly. This is mainly applicable to [Declarative Widgets](https://github.com/jupyter-incubator/declarativewidgets) as a declarative widget is a Polymer element.\n", 28 | "\n", 29 | "A Notebook cell can be resized in one of two ways: (1) by resizing the window or (2) by resizing the cell when in the Dashboard layout view (`View > Layout Dashboard`). Any cell output content is responsible for sizing itself. By listening to the `iron-resize` event, your widget can be notified of both of these resize actions.\n", 30 | "\n", 31 | "The important parts are as follows:\n", 32 | "\n", 33 | "1. Add the `iron-resizable-behavior` to your list of `behaviors`. This will add the capabilities from that behavior to your widget.\n", 34 | "2. Add a listener for the `iron-resize` event, which is fired when your element is resized (i.e. a user is resizing the cells in the Dashboard view).\n", 35 | "3. Implement a callback function which can act when your widget is resized.\n", 36 | "\n", 37 | "In the example widget below, when the cell is resized, the widget adjusts its height to match its width." 38 | ] 39 | }, 40 | { 41 | "cell_type": "markdown", 42 | "metadata": { 43 | "extensions": { 44 | "jupyter_dashboards": { 45 | "version": 1, 46 | "views": { 47 | "grid_default": { 48 | "col": 7, 49 | "height": 4, 50 | "hidden": true, 51 | "row": 6, 52 | "width": 4 53 | }, 54 | "report_default": {} 55 | } 56 | } 57 | } 58 | }, 59 | "source": [ 60 | "
\n", 61 | "Note: Requires Declarative Widgets v0.6.0+.\n", 62 | "
" 63 | ] 64 | }, 65 | { 66 | "cell_type": "code", 67 | "execution_count": null, 68 | "metadata": { 69 | "collapsed": false, 70 | "extensions": { 71 | "jupyter_dashboards": { 72 | "version": 1, 73 | "views": { 74 | "grid_default": { 75 | "hidden": true 76 | }, 77 | "report_default": {} 78 | } 79 | } 80 | } 81 | }, 82 | "outputs": [], 83 | "source": [ 84 | "import declarativewidgets as widgets\n", 85 | "\n", 86 | "widgets.init()" 87 | ] 88 | }, 89 | { 90 | "cell_type": "code", 91 | "execution_count": null, 92 | "metadata": { 93 | "collapsed": false, 94 | "extensions": { 95 | "jupyter_dashboards": { 96 | "version": 1, 97 | "views": { 98 | "grid_default": { 99 | "hidden": true 100 | }, 101 | "report_default": { 102 | "hidden": false 103 | } 104 | } 105 | } 106 | } 107 | }, 108 | "outputs": [], 109 | "source": [ 110 | "%%html\n", 111 | "\n", 113 | "\n", 114 | "\n", 115 | " \n", 122 | "\n", 123 | " \n", 128 | "\n", 129 | " \n", 167 | "" 168 | ] 169 | }, 170 | { 171 | "cell_type": "code", 172 | "execution_count": null, 173 | "metadata": { 174 | "collapsed": false, 175 | "extensions": { 176 | "jupyter_dashboards": { 177 | "version": 1, 178 | "views": { 179 | "grid_default": { 180 | "col": 0, 181 | "height": 23, 182 | "hidden": false, 183 | "row": 6, 184 | "width": 7 185 | }, 186 | "report_default": { 187 | "hidden": false 188 | } 189 | } 190 | } 191 | } 192 | }, 193 | "outputs": [], 194 | "source": [ 195 | "%%html\n", 196 | "" 197 | ] 198 | } 199 | ], 200 | "metadata": { 201 | "extensions": { 202 | "jupyter_dashboards": { 203 | "activeView": "grid_default", 204 | "version": 1, 205 | "views": { 206 | "grid_default": { 207 | "cellMargin": 10, 208 | "defaultCellHeight": 20, 209 | "maxColumns": 12, 210 | "name": "grid", 211 | "type": "grid" 212 | }, 213 | "report_default": { 214 | "name": "report", 215 | "type": "report" 216 | } 217 | } 218 | } 219 | }, 220 | "kernelspec": { 221 | "display_name": "Python 3", 222 | "language": "python", 223 | "name": "python3" 224 | }, 225 | "language_info": { 226 | "codemirror_mode": { 227 | "name": "ipython", 228 | "version": 3 229 | }, 230 | "file_extension": ".py", 231 | "mimetype": "text/x-python", 232 | "name": "python", 233 | "nbconvert_exporter": "python", 234 | "pygments_lexer": "ipython3", 235 | "version": "3.5.1" 236 | }, 237 | "widgets": { 238 | "state": { 239 | "A639A7C001574EBC854DDE0497144BB7": { 240 | "views": [] 241 | } 242 | }, 243 | "version": "1.1.2" 244 | } 245 | }, 246 | "nbformat": 4, 247 | "nbformat_minor": 0 248 | } 249 | -------------------------------------------------------------------------------- /etc/notebooks/declarativewidgets/sentiment_boilerplate_demo/widgets/urth-timeline/bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "urth-timeline", 3 | "version": "0.0.0", 4 | "description": "A timeline.", 5 | "authors": [ 6 | "IBM" 7 | ], 8 | "license": "MIT", 9 | "ignore": [ 10 | "**/.*", 11 | "node_modules", 12 | "bower_components", 13 | "test", 14 | "tests" 15 | ], 16 | "dependencies" : { 17 | "polymer": "Polymer/polymer#^1.0.0", 18 | "paper-radio-button": "PolymerElements/paper-radio-button#^1.0.0", 19 | "paper-radio-group": "PolymerElements/paper-radio-group#^1.0.0", 20 | "paper-checkbox": "PolymerElements/paper-checkbox#^1.0.0", 21 | "paper-item": "PolymerElements/paper-item#^1.0.0", 22 | "iron-icons": "PolymerElements/iron-icons#^1.0.0" 23 | }, 24 | "main" : "urth-timeline.html", 25 | "private" : true 26 | } 27 | -------------------------------------------------------------------------------- /etc/notebooks/got_scotch_demo/datasets/features.dataframe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jupyter/dashboards/d5393ccd0081b2f67c2140257917c75cb8174da8/etc/notebooks/got_scotch_demo/datasets/features.dataframe -------------------------------------------------------------------------------- /etc/notebooks/got_scotch_demo/datasets/sims.dataframe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jupyter/dashboards/d5393ccd0081b2f67c2140257917c75cb8174da8/etc/notebooks/got_scotch_demo/datasets/sims.dataframe -------------------------------------------------------------------------------- /etc/notebooks/got_scotch_demo/datasets/whiskies.txt: -------------------------------------------------------------------------------- 1 | RowID,Distillery,Body,Sweetness,Smoky,Medicinal,Tobacco,Honey,Spicy,Winey,Nutty,Malty,Fruity,Floral,Postcode, Latitude, Longitude 2 | 01,Aberfeldy,2,2,2,0,0,2,1,2,2,2,2,2, PH15 2EB, 286580,749680 3 | 02,Aberlour,3,3,1,0,0,4,3,2,2,3,3,2, AB38 9PJ, 326340,842570 4 | 03,AnCnoc,1,3,2,0,0,2,0,0,2,2,3,2, AB5 5LI, 352960,839320 5 | 04,Ardbeg,4,1,4,4,0,0,2,0,1,2,1,0, PA42 7EB, 141560,646220 6 | 05,Ardmore,2,2,2,0,0,1,1,1,2,3,1,1, AB54 4NH, 355350,829140 7 | 06,ArranIsleOf,2,3,1,1,0,1,1,1,0,1,1,2, KA27 8HJ, 194050,649950 8 | 07,Auchentoshan,0,2,0,0,0,1,1,0,2,2,3,3, G81 4SJ, 247670,672610 9 | 08,Auchroisk,2,3,1,0,0,2,1,2,2,2,2,1, AB55 3XS, 340754,848623 10 | 09,Aultmore,2,2,1,0,0,1,0,0,2,2,2,2, AB55 3QY, 340754,848623 11 | 10,Balblair,2,3,2,1,0,0,2,0,2,1,2,1, IV19 1LB, 270820,885770 12 | 11,Balmenach,4,3,2,0,0,2,1,3,3,0,1,2, PH26 3PF, 307750,827170 13 | 12,Belvenie,3,2,1,0,0,3,2,1,0,2,2,2, AB55 4DH, 332680,840840 14 | 13,BenNevis,4,2,2,0,0,2,2,0,2,2,2,2, PH33 6TJ, 212600,775710 15 | 14,Benriach,2,2,1,0,0,2,2,0,0,2,3,2, IV30 8SJ, 323450,858380 16 | 15,Benrinnes,3,2,2,0,0,3,1,1,2,3,2,2, AB38 9NN, 325800,839920 17 | 16,Benromach,2,2,2,0,0,2,2,1,2,2,2,2, IV36 3EB, 303330,859350 18 | 17,Bladnoch,1,2,1,0,0,0,1,1,0,2,2,3, DG8 9AB, 242260,554260 19 | 18,BlairAthol,2,2,2,0,0,1,2,2,2,2,2,2, PH16 5LY, 294860,757580 20 | 19,Bowmore,2,2,3,1,0,2,2,1,1,1,1,2, PA43 7GS, 131330,659720 21 | 20,Bruichladdich,1,1,2,2,0,2,2,1,2,2,2,2, PA49 7UN, 126680,661400 22 | 21,Bunnahabhain,1,2,1,1,0,1,1,1,1,2,2,3, PA46 7RR, 142210,673170 23 | 22,Caol Ila,3,1,4,2,1,0,2,0,2,1,1,1, PA46 7RL, 142920,670040 24 | 23,Cardhu,1,3,1,0,0,1,1,0,2,2,2,2, AB38 7RY, 318790,843090 25 | 24,Clynelish,3,2,3,3,1,0,2,0,1,1,2,0, KW9 6LB, 290250,904230 26 | 25,Craigallechie,2,2,2,0,1,2,2,1,2,2,1,4, AB38 9ST, 328920,844920 27 | 26,Craigganmore,2,3,2,1,0,0,1,0,2,2,2,2, AB37 9AB, 316600,836370 28 | 27,Dailuaine,4,2,2,0,0,1,2,2,2,2,2,1, AB38 7RE, 323520,841010 29 | 28,Dalmore,3,2,2,1,0,1,2,2,1,2,3,1, IV17 0UT, 266610,868730 30 | 29,Dalwhinnie,2,2,2,0,0,2,1,0,1,2,2,2, PH19 1AB, 263670,785270 31 | 30,Deanston,2,2,1,0,0,2,1,1,1,3,2,1, FK16 6AG, 271570,701570 32 | 31,Dufftown,2,3,1,1,0,0,0,0,1,2,2,2, AB55 4BR, 332360,839200 33 | 32,Edradour,2,3,1,0,0,2,1,1,4,2,2,2, PH16 5JP, 295960,757940 34 | 33,GlenDeveronMacduff,2,3,1,1,1,1,1,2,0,2,0,1, AB4 3JT, 372120,860400 35 | 34,GlenElgin,2,3,1,0,0,2,1,1,1,1,2,3, IV30 3SL, 322640,861040 36 | 35,GlenGarioch,2,1,3,0,0,0,3,1,0,2,2,2, AB51 0ES, 381020,827590 37 | 36,GlenGrant,1,2,0,0,0,1,0,1,2,1,2,1, AB38 7BS, 327610,849570 38 | 37,GlenKeith,2,3,1,0,0,1,2,1,2,1,2,1, AB55 3BU, 340754,848623 39 | 38,GlenMoray,1,2,1,0,0,1,2,1,2,2,2,4, IV30 1YE, 319820,862320 40 | 39,GlenOrd,3,2,1,0,0,1,2,1,1,2,2,2, IV6 7UJ, 251810,850860 41 | 40,GlenScotia,2,2,2,2,0,1,0,1,2,2,1,1, PA28 6DS, 172090,621010 42 | 41,GlenSpey,1,3,1,0,0,0,1,1,1,2,0,2, AB38 7AU, 327760,849140 43 | 42,Glenallachie,1,3,1,0,0,1,1,0,1,2,2,2, AB38 9LR, 326490,841240 44 | 43,Glendronach,4,2,2,0,0,2,1,4,2,2,2,0, AB54 6DA, 361200,844930 45 | 44,Glendullan,3,2,1,0,0,2,1,2,1,2,3,2, AB55 4DJ, 333000,840300 46 | 45,Glenfarclas,2,4,1,0,0,1,2,3,2,3,2,2, AB37 9BD, 320950,838160 47 | 46,Glenfiddich,1,3,1,0,0,0,0,0,0,2,2,2, AB55 4DH, 332680,840840 48 | 47,Glengoyne,1,2,0,0,0,1,1,1,2,2,3,2, G63 9LB, 252810,682750 49 | 48,Glenkinchie,1,2,1,0,0,1,2,0,0,2,2,2, EH34 5ET, 344380,666690 50 | 49,Glenlivet,2,3,1,0,0,2,2,2,1,2,2,3, AB37 9DB, 319560,828780 51 | 50,Glenlossie,1,2,1,0,0,1,2,0,1,2,2,2, IV30 3SS, 322640,861040 52 | 51,Glenmorangie,2,2,1,1,0,1,2,0,2,1,2,2, IV19 1PZ, 276750,883450 53 | 52,Glenrothes,2,3,1,0,0,1,1,2,1,2,2,0, AB38 7AA, 327650,849170 54 | 53,Glenturret,2,3,1,0,0,2,2,2,2,2,1,2, PH7 4HA, 285630,723580 55 | 54,Highland Park,2,2,3,1,0,2,1,1,1,2,1,1, KW15 1SU, 345340,1009260 56 | 55,Inchgower,1,3,1,1,0,2,2,0,1,2,1,2, AB56 5AB, 342610,863970 57 | 56,Isle of Jura,2,1,2,2,0,1,1,0,2,1,1,1, PA60 7XT, 152660,667040 58 | 57,Knochando,2,3,1,0,0,2,2,1,2,1,2,2, AB38 7RT, 319470,841570 59 | 58,Lagavulin,4,1,4,4,1,0,1,2,1,1,1,0, PA42 7DZ, 140430,645730 60 | 59,Laphroig,4,2,4,4,1,0,0,1,1,1,0,0, PA42 7DU, 138680,645160 61 | 60,Linkwood,2,3,1,0,0,1,1,2,0,1,3,2, IV30 3RD, 322640,861040 62 | 61,Loch Lomond,1,1,1,1,0,1,1,0,1,2,1,2, G83 0TL, 239370,680920 63 | 62,Longmorn,3,2,1,0,0,1,1,1,3,3,2,3, IV30 3SJ, 322640,861040 64 | 63,Macallan,4,3,1,0,0,2,1,4,2,2,3,1, AB38 9RX, 327710,844480 65 | 64,Mannochmore,2,1,1,0,0,1,1,1,2,1,2,2, IV30 3SS, 322640,861040 66 | 65,Miltonduff,2,4,1,0,0,1,0,0,2,1,1,2, IV30 3TQ, 322640,861040 67 | 66,Mortlach,3,2,2,0,0,2,3,3,2,1,2,2, AB55 4AQ, 332950,839850 68 | 67,Oban,2,2,2,2,0,0,2,0,2,2,2,0, PA34 5NH, 185940,730190 69 | 68,OldFettercairn,1,2,2,0,1,2,2,1,2,3,1,1, AB30 1YE, 370860,772900 70 | 69,OldPulteney,2,1,2,2,1,0,1,1,2,2,2,2, KW1 5BA, 336730,950130 71 | 70,RoyalBrackla,2,3,2,1,1,1,2,1,0,2,3,2, IV12 5QY, 286040,851320 72 | 71,RoyalLochnagar,3,2,2,0,0,2,2,2,2,2,3,1, AB35 5TB, 326140,794370 73 | 72,Scapa,2,2,1,1,0,2,1,1,2,2,2,2, KW15 1SE, 342850,1008930 74 | 73,Speyburn,2,4,1,0,0,2,1,0,0,2,1,2, AB38 7AG, 326930,851430 75 | 74,Speyside,2,2,1,0,0,1,0,1,2,2,2,2, PH21 1NS, 278740,800600 76 | 75,Springbank,2,2,2,2,0,2,2,1,2,1,0,1, PA28 6EJ, 172280,620910 77 | 76,Strathisla,2,2,1,0,0,2,2,2,3,3,3,2, AB55 3BS, 340754,848623 78 | 77,Strathmill,2,3,1,0,0,0,2,0,2,1,3,2, AB55 5DQ,342650,850500 79 | 78,Talisker,4,2,3,3,0,1,3,0,1,2,2,0, IV47 8SR, 137950,831770 80 | 79,Tamdhu,1,2,1,0,0,2,0,1,1,2,2,2, AB38 7RP, 319210,841760 81 | 80,Tamnavulin,1,3,2,0,0,0,2,0,2,1,2,3, AB37 9JA, 321180,826110 82 | 81,Teaninich,2,2,2,1,0,0,2,0,0,0,2,2, IV17 0XB, 265360,869120 83 | 82,Tobermory,1,1,1,0,0,1,0,0,1,2,2,2, PA75 6NR, 150450,755070 84 | 83,Tomatin,2,3,2,0,0,2,2,1,1,2,0,1, IV13 7YT, 279120,829630 85 | 84,Tomintoul,0,3,1,0,0,2,2,1,1,2,1,2, AB37 9AQ, 315100,825560 86 | 85,Tormore,2,2,1,0,0,1,0,1,2,1,0,0, PH26 3LR, 315180,834960 87 | 86,Tullibardine,2,3,0,0,1,0,2,1,1,2,2,1, PH4 1QG, 289690,708850 88 | -------------------------------------------------------------------------------- /etc/notebooks/test/system-test/Basic.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": { 6 | "extensions": { 7 | "jupyter_dashboards": { 8 | "version": 1, 9 | "views": { 10 | "grid_default": { 11 | "col": 0, 12 | "height": 4, 13 | "hidden": false, 14 | "row": 0, 15 | "width": 4 16 | }, 17 | "report_default": { 18 | "hidden": false 19 | } 20 | } 21 | } 22 | } 23 | }, 24 | "source": [ 25 | "# Markdown Cell\n", 26 | "This test will look for the header above in layout view and dashboard view." 27 | ] 28 | } 29 | ], 30 | "metadata": { 31 | "extensions": { 32 | "jupyter_dashboards": { 33 | "activeView": "grid_default", 34 | "version": 1, 35 | "views": { 36 | "grid_default": { 37 | "cellMargin": 10, 38 | "defaultCellHeight": 20, 39 | "maxColumns": 12, 40 | "name": "grid", 41 | "type": "grid" 42 | }, 43 | "report_default": { 44 | "name": "report", 45 | "type": "report" 46 | } 47 | } 48 | } 49 | }, 50 | "kernelspec": { 51 | "display_name": "Python 3", 52 | "language": "python", 53 | "name": "python3" 54 | }, 55 | "language_info": { 56 | "codemirror_mode": { 57 | "name": "ipython", 58 | "version": 3 59 | }, 60 | "file_extension": ".py", 61 | "mimetype": "text/x-python", 62 | "name": "python", 63 | "nbconvert_exporter": "python", 64 | "pygments_lexer": "ipython3", 65 | "version": "3.6.2" 66 | }, 67 | "widgets": { 68 | "state": {}, 69 | "version": "1.1.2" 70 | } 71 | }, 72 | "nbformat": 4, 73 | "nbformat_minor": 1 74 | } 75 | -------------------------------------------------------------------------------- /etc/notebooks/test/test_clear_output.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": { 6 | "extensions": { 7 | "jupyter_dashboards": { 8 | "version": 1, 9 | "views": { 10 | "grid_default": { 11 | "col": 0, 12 | "height": 2, 13 | "hidden": false, 14 | "row": 0, 15 | "width": 4 16 | }, 17 | "report_default": { 18 | "hidden": false 19 | } 20 | } 21 | } 22 | } 23 | }, 24 | "source": [ 25 | "# Test clear_display" 26 | ] 27 | }, 28 | { 29 | "cell_type": "code", 30 | "execution_count": null, 31 | "metadata": { 32 | "extensions": { 33 | "jupyter_dashboards": { 34 | "version": 1, 35 | "views": { 36 | "grid_default": { 37 | "hidden": true 38 | }, 39 | "report_default": { 40 | "hidden": false 41 | } 42 | } 43 | } 44 | } 45 | }, 46 | "outputs": [], 47 | "source": [ 48 | "%matplotlib inline" 49 | ] 50 | }, 51 | { 52 | "cell_type": "code", 53 | "execution_count": null, 54 | "metadata": { 55 | "extensions": { 56 | "jupyter_dashboards": { 57 | "version": 1, 58 | "views": { 59 | "grid_default": { 60 | "hidden": true 61 | }, 62 | "report_default": { 63 | "hidden": false 64 | } 65 | } 66 | } 67 | } 68 | }, 69 | "outputs": [], 70 | "source": [ 71 | "import matplotlib.pyplot as plt\n", 72 | "import numpy as np\n", 73 | "\n", 74 | "from ipywidgets import interact\n", 75 | "from ipykernel.pylab.backend_inline import flush_figures" 76 | ] 77 | }, 78 | { 79 | "cell_type": "code", 80 | "execution_count": null, 81 | "metadata": { 82 | "extensions": { 83 | "jupyter_dashboards": { 84 | "version": 1, 85 | "views": { 86 | "grid_default": { 87 | "col": 0, 88 | "height": 12, 89 | "hidden": false, 90 | "row": 2, 91 | "width": 5 92 | }, 93 | "report_default": { 94 | "hidden": false 95 | } 96 | } 97 | } 98 | } 99 | }, 100 | "outputs": [], 101 | "source": [ 102 | "@interact(points=['-', '10', '20', '30'])\n", 103 | "def render(points=None):\n", 104 | " if points == '-': return\n", 105 | " points = int(points)\n", 106 | " fig, ax = plt.subplots()\n", 107 | " x = np.random.randn(points)\n", 108 | " y = np.random.randn(points)\n", 109 | " ax.scatter(x, y)\n", 110 | " flush_figures()" 111 | ] 112 | } 113 | ], 114 | "metadata": { 115 | "extensions": { 116 | "jupyter_dashboards": { 117 | "activeView": "grid_default", 118 | "version": 1, 119 | "views": { 120 | "grid_default": { 121 | "cellMargin": 10, 122 | "defaultCellHeight": 20, 123 | "maxColumns": 12, 124 | "max_cols": 4, 125 | "max_rows": 17, 126 | "name": "grid", 127 | "type": "grid" 128 | }, 129 | "report_default": { 130 | "name": "report", 131 | "type": "report" 132 | } 133 | } 134 | } 135 | }, 136 | "kernelspec": { 137 | "display_name": "Python 3", 138 | "language": "python", 139 | "name": "python3" 140 | }, 141 | "language_info": { 142 | "codemirror_mode": { 143 | "name": "ipython", 144 | "version": 3 145 | }, 146 | "file_extension": ".py", 147 | "mimetype": "text/x-python", 148 | "name": "python", 149 | "nbconvert_exporter": "python", 150 | "pygments_lexer": "ipython3", 151 | "version": "3.6.2" 152 | }, 153 | "widgets": { 154 | "state": {}, 155 | "version": "1.1.2" 156 | } 157 | }, 158 | "nbformat": 4, 159 | "nbformat_minor": 1 160 | } 161 | -------------------------------------------------------------------------------- /etc/notebooks/test/test_html_javascript.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": { 6 | "extensions": { 7 | "jupyter_dashboards": { 8 | "version": 1, 9 | "views": { 10 | "grid_default": { 11 | "col": 0, 12 | "height": 4, 13 | "hidden": false, 14 | "row": 0, 15 | "width": 12 16 | }, 17 | "report_default": { 18 | "hidden": false 19 | } 20 | } 21 | } 22 | } 23 | }, 24 | "source": [ 25 | "## %%html and %%javascript magics test case\n", 26 | "\n", 27 | "This cell's background should turn red and the heading above should turn blue." 28 | ] 29 | }, 30 | { 31 | "cell_type": "code", 32 | "execution_count": null, 33 | "metadata": { 34 | "extensions": { 35 | "jupyter_dashboards": { 36 | "version": 1, 37 | "views": { 38 | "grid_default": { 39 | "hidden": true 40 | }, 41 | "report_default": { 42 | "hidden": false 43 | } 44 | } 45 | } 46 | } 47 | }, 48 | "outputs": [], 49 | "source": [ 50 | "%%html\n", 51 | "" 56 | ] 57 | }, 58 | { 59 | "cell_type": "code", 60 | "execution_count": null, 61 | "metadata": { 62 | "extensions": { 63 | "jupyter_dashboards": { 64 | "version": 1, 65 | "views": { 66 | "grid_default": { 67 | "hidden": true 68 | }, 69 | "report_default": { 70 | "hidden": false 71 | } 72 | } 73 | } 74 | } 75 | }, 76 | "outputs": [], 77 | "source": [ 78 | "%%javascript\n", 79 | "require([\"widgets/js/widget\", \"widgets/js/manager\"], function(widget, manager){ \n", 80 | " console.log('IT WORKS!
');\n", 81 | "});" 82 | ] 83 | }, 84 | { 85 | "cell_type": "code", 86 | "execution_count": null, 87 | "metadata": { 88 | "extensions": { 89 | "jupyter_dashboards": { 90 | "version": 1, 91 | "views": { 92 | "grid_default": { 93 | "hidden": true 94 | }, 95 | "report_default": { 96 | "hidden": false 97 | } 98 | } 99 | } 100 | } 101 | }, 102 | "outputs": [], 103 | "source": [ 104 | "%%javascript\n", 105 | "var cells = document.getElementsByClassName('rendered_html')\n", 106 | "cells[0].style.backgroundColor = 'red';" 107 | ] 108 | } 109 | ], 110 | "metadata": { 111 | "celltoolbar": "Section", 112 | "extensions": { 113 | "jupyter_dashboards": { 114 | "activeView": "grid_default", 115 | "version": 1, 116 | "views": { 117 | "grid_default": { 118 | "cellMargin": 10, 119 | "defaultCellHeight": 20, 120 | "maxColumns": 12, 121 | "name": "grid", 122 | "type": "grid" 123 | }, 124 | "report_default": { 125 | "name": "report", 126 | "type": "report" 127 | } 128 | } 129 | } 130 | }, 131 | "kernelspec": { 132 | "display_name": "Python 3", 133 | "language": "python", 134 | "name": "python3" 135 | }, 136 | "language_info": { 137 | "codemirror_mode": { 138 | "name": "ipython", 139 | "version": 3 140 | }, 141 | "file_extension": ".py", 142 | "mimetype": "text/x-python", 143 | "name": "python", 144 | "nbconvert_exporter": "python", 145 | "pygments_lexer": "ipython3", 146 | "version": "3.6.2" 147 | }, 148 | "widgets": { 149 | "state": {}, 150 | "version": "1.1.2" 151 | } 152 | }, 153 | "nbformat": 4, 154 | "nbformat_minor": 1 155 | } 156 | -------------------------------------------------------------------------------- /etc/notebooks/test/test_layout.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": { 6 | "extensions": { 7 | "jupyter_dashboards": { 8 | "version": 1, 9 | "views": { 10 | "grid_default": { 11 | "col": 0, 12 | "height": 6, 13 | "hidden": false, 14 | "row": 0, 15 | "width": 12 16 | }, 17 | "report_default": { 18 | "hidden": false 19 | } 20 | } 21 | } 22 | } 23 | }, 24 | "source": [ 25 | "# Dashboard Layout Test\n", 26 | "\n", 27 | "The purpose of this notebook is to ensure the layout of notebook sections is similar between the authoring environment and deployed dashboards. This notebook creates has a heading section at the top containing this text, followed by a two by two grid. The top left of the grid contains a bit of markdown text. The top right contains an interactive plot. The bottom left contains a set of IPython widgets. And the bottom right contains more text.\n", 28 | "\n", 29 | "**Goal**: Appearance should be similar between View → Dashboard View in Jupyter and when deployed as a standalone dashboard app." 30 | ] 31 | }, 32 | { 33 | "cell_type": "code", 34 | "execution_count": null, 35 | "metadata": { 36 | "extensions": { 37 | "jupyter_dashboards": { 38 | "version": 1, 39 | "views": { 40 | "grid_default": { 41 | "hidden": true 42 | }, 43 | "report_default": { 44 | "hidden": false 45 | } 46 | } 47 | } 48 | } 49 | }, 50 | "outputs": [], 51 | "source": [ 52 | "%matplotlib notebook" 53 | ] 54 | }, 55 | { 56 | "cell_type": "markdown", 57 | "metadata": { 58 | "extensions": { 59 | "jupyter_dashboards": { 60 | "version": 1, 61 | "views": { 62 | "grid_default": { 63 | "col": 0, 64 | "height": 12, 65 | "hidden": false, 66 | "row": 6, 67 | "width": 6 68 | }, 69 | "report_default": { 70 | "hidden": false 71 | } 72 | } 73 | } 74 | } 75 | }, 76 | "source": [ 77 | "## Plot Test →\n", 78 | "\n", 79 | "The scatter plot to the right shows 100 (x,y) coordinates." 80 | ] 81 | }, 82 | { 83 | "cell_type": "code", 84 | "execution_count": null, 85 | "metadata": { 86 | "extensions": { 87 | "jupyter_dashboards": { 88 | "version": 1, 89 | "views": { 90 | "grid_default": { 91 | "hidden": true 92 | }, 93 | "report_default": { 94 | "hidden": false 95 | } 96 | } 97 | } 98 | } 99 | }, 100 | "outputs": [], 101 | "source": [ 102 | "%%html\n", 103 | "" 112 | ] 113 | }, 114 | { 115 | "cell_type": "code", 116 | "execution_count": null, 117 | "metadata": { 118 | "extensions": { 119 | "jupyter_dashboards": { 120 | "version": 1, 121 | "views": { 122 | "grid_default": { 123 | "hidden": true 124 | }, 125 | "report_default": { 126 | "hidden": false 127 | } 128 | } 129 | } 130 | } 131 | }, 132 | "outputs": [], 133 | "source": [ 134 | "import matplotlib.pyplot as plt\n", 135 | "import numpy" 136 | ] 137 | }, 138 | { 139 | "cell_type": "code", 140 | "execution_count": null, 141 | "metadata": { 142 | "collapsed": true, 143 | "extensions": { 144 | "jupyter_dashboards": { 145 | "version": 1, 146 | "views": { 147 | "grid_default": { 148 | "hidden": true 149 | }, 150 | "report_default": { 151 | "hidden": false 152 | } 153 | } 154 | } 155 | } 156 | }, 157 | "outputs": [], 158 | "source": [ 159 | "x = numpy.random.beta(1, 0.8, 100)\n", 160 | "y = numpy.random.beta(0.1, 0.5, 100)\n" 161 | ] 162 | }, 163 | { 164 | "cell_type": "code", 165 | "execution_count": null, 166 | "metadata": { 167 | "extensions": { 168 | "jupyter_dashboards": { 169 | "version": 1, 170 | "views": { 171 | "grid_default": { 172 | "col": 6, 173 | "height": 12, 174 | "hidden": false, 175 | "row": 6, 176 | "width": 6 177 | }, 178 | "report_default": { 179 | "hidden": false 180 | } 181 | } 182 | } 183 | } 184 | }, 185 | "outputs": [], 186 | "source": [ 187 | "fig, ax = plt.subplots(figsize=(5,3.5))\n", 188 | "ax.scatter(x, y)\n", 189 | "plt.tight_layout()" 190 | ] 191 | }, 192 | { 193 | "cell_type": "code", 194 | "execution_count": null, 195 | "metadata": { 196 | "extensions": { 197 | "jupyter_dashboards": { 198 | "version": 1, 199 | "views": { 200 | "grid_default": { 201 | "hidden": true 202 | }, 203 | "report_default": { 204 | "hidden": false 205 | } 206 | } 207 | } 208 | } 209 | }, 210 | "outputs": [], 211 | "source": [ 212 | "from ipywidgets import *\n", 213 | "from IPython.display import display" 214 | ] 215 | }, 216 | { 217 | "cell_type": "code", 218 | "execution_count": null, 219 | "metadata": { 220 | "extensions": { 221 | "jupyter_dashboards": { 222 | "version": 1, 223 | "views": { 224 | "grid_default": { 225 | "col": 0, 226 | "height": 4, 227 | "hidden": false, 228 | "row": 18, 229 | "width": 6 230 | }, 231 | "report_default": { 232 | "hidden": false 233 | } 234 | } 235 | } 236 | } 237 | }, 238 | "outputs": [], 239 | "source": [ 240 | "w = IntSlider()\n", 241 | "display(w)" 242 | ] 243 | }, 244 | { 245 | "cell_type": "markdown", 246 | "metadata": { 247 | "extensions": { 248 | "jupyter_dashboards": { 249 | "version": 1, 250 | "views": { 251 | "grid_default": { 252 | "col": 6, 253 | "height": 4, 254 | "hidden": false, 255 | "row": 18, 256 | "width": 6 257 | }, 258 | "report_default": { 259 | "hidden": false 260 | } 261 | } 262 | } 263 | } 264 | }, 265 | "source": [ 266 | "## ← Widgets Test\n", 267 | "\n", 268 | "The widget to the left should update as you interact with it." 269 | ] 270 | } 271 | ], 272 | "metadata": { 273 | "celltoolbar": "Section", 274 | "extensions": { 275 | "jupyter_dashboards": { 276 | "activeView": "grid_default", 277 | "version": 1, 278 | "views": { 279 | "grid_default": { 280 | "cellMargin": 10, 281 | "defaultCellHeight": 20, 282 | "maxColumns": 12, 283 | "name": "grid", 284 | "type": "grid" 285 | }, 286 | "report_default": { 287 | "name": "report", 288 | "type": "report" 289 | } 290 | } 291 | } 292 | }, 293 | "kernelspec": { 294 | "display_name": "Python 3", 295 | "language": "python", 296 | "name": "python3" 297 | }, 298 | "language_info": { 299 | "codemirror_mode": { 300 | "name": "ipython", 301 | "version": 3 302 | }, 303 | "file_extension": ".py", 304 | "mimetype": "text/x-python", 305 | "name": "python", 306 | "nbconvert_exporter": "python", 307 | "pygments_lexer": "ipython3", 308 | "version": "3.6.2" 309 | }, 310 | "widgets": { 311 | "state": {}, 312 | "version": "1.1.2" 313 | } 314 | }, 315 | "nbformat": 4, 316 | "nbformat_minor": 1 317 | } 318 | -------------------------------------------------------------------------------- /etc/notebooks/test/test_layout_basic.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": { 6 | "extensions": { 7 | "jupyter_dashboards": { 8 | "version": 1, 9 | "views": { 10 | "grid_default": { 11 | "col": 3, 12 | "height": 4, 13 | "hidden": false, 14 | "row": 0, 15 | "width": 6 16 | }, 17 | "report_default": { 18 | "hidden": false 19 | } 20 | } 21 | } 22 | } 23 | }, 24 | "source": [ 25 | "# Basic Dashboard Layout Test" 26 | ] 27 | }, 28 | { 29 | "cell_type": "code", 30 | "execution_count": null, 31 | "metadata": { 32 | "collapsed": true, 33 | "extensions": { 34 | "jupyter_dashboards": { 35 | "version": 1, 36 | "views": { 37 | "grid_default": { 38 | "hidden": true 39 | }, 40 | "report_default": { 41 | "hidden": false 42 | } 43 | } 44 | } 45 | } 46 | }, 47 | "outputs": [], 48 | "source": [ 49 | "from IPython.display import Image" 50 | ] 51 | }, 52 | { 53 | "cell_type": "markdown", 54 | "metadata": { 55 | "extensions": { 56 | "jupyter_dashboards": { 57 | "version": 1, 58 | "views": { 59 | "grid_default": { 60 | "col": 1, 61 | "height": 15, 62 | "hidden": false, 63 | "row": 4, 64 | "width": 5 65 | }, 66 | "report_default": { 67 | "hidden": false 68 | } 69 | } 70 | } 71 | } 72 | }, 73 | "source": [ 74 | "Pull a static image inline into the notebook." 75 | ] 76 | }, 77 | { 78 | "cell_type": "code", 79 | "execution_count": null, 80 | "metadata": { 81 | "extensions": { 82 | "jupyter_dashboards": { 83 | "version": 1, 84 | "views": { 85 | "grid_default": { 86 | "col": 6, 87 | "height": 15, 88 | "hidden": false, 89 | "row": 4, 90 | "width": 5 91 | }, 92 | "report_default": { 93 | "hidden": false 94 | } 95 | } 96 | } 97 | } 98 | }, 99 | "outputs": [], 100 | "source": [ 101 | "Image('http://blog.jupyter.org/content/images/2015/02/jupyter-sq-text.png')" 102 | ] 103 | }, 104 | { 105 | "cell_type": "code", 106 | "execution_count": null, 107 | "metadata": { 108 | "extensions": { 109 | "jupyter_dashboards": { 110 | "version": 1, 111 | "views": { 112 | "grid_default": { 113 | "hidden": true 114 | }, 115 | "report_default": { 116 | "hidden": false 117 | } 118 | } 119 | } 120 | } 121 | }, 122 | "outputs": [], 123 | "source": [ 124 | "from IPython.display import display\n", 125 | "from ipywidgets import FloatText, FloatSlider, FloatProgress\n", 126 | "from traitlets import link" 127 | ] 128 | }, 129 | { 130 | "cell_type": "code", 131 | "execution_count": null, 132 | "metadata": { 133 | "extensions": { 134 | "jupyter_dashboards": { 135 | "version": 1, 136 | "views": { 137 | "grid_default": { 138 | "col": 1, 139 | "height": 5, 140 | "hidden": false, 141 | "row": 19, 142 | "width": 5 143 | }, 144 | "report_default": { 145 | "hidden": false 146 | } 147 | } 148 | } 149 | } 150 | }, 151 | "outputs": [], 152 | "source": [ 153 | "a = FloatText()\n", 154 | "b = FloatSlider()\n", 155 | "c = FloatProgress()\n", 156 | "display(a,b,c)\n", 157 | "\n", 158 | "link1 = link((a, 'value'), (b, 'value'))\n", 159 | "link2 = link((a, 'value'), (c, 'value'))" 160 | ] 161 | }, 162 | { 163 | "cell_type": "markdown", 164 | "metadata": { 165 | "extensions": { 166 | "jupyter_dashboards": { 167 | "version": 1, 168 | "views": { 169 | "grid_default": { 170 | "col": 6, 171 | "height": 4, 172 | "hidden": false, 173 | "row": 19, 174 | "width": 5 175 | }, 176 | "report_default": { 177 | "hidden": false 178 | } 179 | } 180 | } 181 | } 182 | }, 183 | "source": [ 184 | "## ← Widgets Test\n", 185 | "\n", 186 | "The widgets to the left should update as you interact with any of them." 187 | ] 188 | } 189 | ], 190 | "metadata": { 191 | "celltoolbar": "Section", 192 | "extensions": { 193 | "jupyter_dashboards": { 194 | "activeView": "grid_default", 195 | "version": 1, 196 | "views": { 197 | "grid_default": { 198 | "cellMargin": 10, 199 | "defaultCellHeight": 20, 200 | "maxColumns": 12, 201 | "name": "grid", 202 | "type": "grid" 203 | }, 204 | "report_default": { 205 | "name": "report", 206 | "type": "report" 207 | } 208 | } 209 | } 210 | }, 211 | "kernelspec": { 212 | "display_name": "Python 3", 213 | "language": "python", 214 | "name": "python3" 215 | }, 216 | "language_info": { 217 | "codemirror_mode": { 218 | "name": "ipython", 219 | "version": 3 220 | }, 221 | "file_extension": ".py", 222 | "mimetype": "text/x-python", 223 | "name": "python", 224 | "nbconvert_exporter": "python", 225 | "pygments_lexer": "ipython3", 226 | "version": "3.6.2" 227 | }, 228 | "widgets": { 229 | "state": {}, 230 | "version": "1.1.2" 231 | } 232 | }, 233 | "nbformat": 4, 234 | "nbformat_minor": 1 235 | } 236 | -------------------------------------------------------------------------------- /etc/notebooks/test/test_layout_declarativewidgets.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": { 6 | "extensions": { 7 | "jupyter_dashboards": { 8 | "version": 1, 9 | "views": { 10 | "grid_default": { 11 | "col": 0, 12 | "height": 3, 13 | "hidden": false, 14 | "row": 0, 15 | "width": 12 16 | }, 17 | "report_default": { 18 | "hidden": false 19 | } 20 | } 21 | } 22 | } 23 | }, 24 | "source": [ 25 | "# Declarative Widgets in a Dashboard Layout Test" 26 | ] 27 | }, 28 | { 29 | "cell_type": "code", 30 | "execution_count": null, 31 | "metadata": { 32 | "collapsed": false, 33 | "extensions": { 34 | "jupyter_dashboards": { 35 | "version": 1, 36 | "views": { 37 | "grid_default": { 38 | "hidden": true 39 | }, 40 | "report_default": {} 41 | } 42 | } 43 | } 44 | }, 45 | "outputs": [], 46 | "source": [ 47 | "import declarativewidgets as widgets\n", 48 | "\n", 49 | "widgets.init()" 50 | ] 51 | }, 52 | { 53 | "cell_type": "markdown", 54 | "metadata": { 55 | "extensions": { 56 | "jupyter_dashboards": { 57 | "version": 1, 58 | "views": { 59 | "grid_default": { 60 | "col": 0, 61 | "height": 4, 62 | "hidden": false, 63 | "row": 3, 64 | "width": 3 65 | }, 66 | "report_default": { 67 | "hidden": false 68 | } 69 | } 70 | } 71 | } 72 | }, 73 | "source": [ 74 | "Here is a `paper-input` widget from the Polymer catalog." 75 | ] 76 | }, 77 | { 78 | "cell_type": "code", 79 | "execution_count": null, 80 | "metadata": { 81 | "collapsed": false, 82 | "extensions": { 83 | "jupyter_dashboards": { 84 | "version": 1, 85 | "views": { 86 | "grid_default": { 87 | "col": 3, 88 | "height": 4, 89 | "hidden": false, 90 | "row": 3, 91 | "width": 9 92 | }, 93 | "report_default": { 94 | "hidden": false 95 | } 96 | } 97 | } 98 | } 99 | }, 100 | "outputs": [], 101 | "source": [ 102 | "%%html\n", 103 | "\n", 105 | "\n", 106 | "" 107 | ] 108 | }, 109 | { 110 | "cell_type": "markdown", 111 | "metadata": { 112 | "extensions": { 113 | "jupyter_dashboards": { 114 | "version": 1, 115 | "views": { 116 | "grid_default": { 117 | "col": 0, 118 | "height": 4, 119 | "hidden": false, 120 | "row": 7, 121 | "width": 3 122 | }, 123 | "report_default": { 124 | "hidden": false 125 | } 126 | } 127 | } 128 | } 129 | }, 130 | "source": [ 131 | "And here is a `paper-dropdown-menu` widget from the Polymer catalog." 132 | ] 133 | }, 134 | { 135 | "cell_type": "code", 136 | "execution_count": null, 137 | "metadata": { 138 | "collapsed": false, 139 | "extensions": { 140 | "jupyter_dashboards": { 141 | "version": 1, 142 | "views": { 143 | "grid_default": { 144 | "col": 3, 145 | "height": 4, 146 | "hidden": false, 147 | "row": 7, 148 | "width": 4 149 | }, 150 | "report_default": { 151 | "hidden": false 152 | } 153 | } 154 | } 155 | } 156 | }, 157 | "outputs": [], 158 | "source": [ 159 | "%%html\n", 160 | "\n", 162 | "\n", 164 | "\n", 165 | "\n", 166 | " \n", 167 | " A \n", 168 | " B \n", 169 | " C \n", 170 | " \n", 171 | "" 172 | ] 173 | } 174 | ], 175 | "metadata": { 176 | "celltoolbar": "Section", 177 | "extensions": { 178 | "jupyter_dashboards": { 179 | "activeView": "grid_default", 180 | "version": 1, 181 | "views": { 182 | "grid_default": { 183 | "cellMargin": 10, 184 | "defaultCellHeight": 20, 185 | "maxColumns": 12, 186 | "name": "grid", 187 | "type": "grid" 188 | }, 189 | "report_default": { 190 | "name": "report", 191 | "type": "report" 192 | } 193 | } 194 | } 195 | }, 196 | "kernelspec": { 197 | "display_name": "Python 3", 198 | "language": "python", 199 | "name": "python3" 200 | }, 201 | "language_info": { 202 | "codemirror_mode": { 203 | "name": "ipython", 204 | "version": 3 205 | }, 206 | "file_extension": ".py", 207 | "mimetype": "text/x-python", 208 | "name": "python", 209 | "nbconvert_exporter": "python", 210 | "pygments_lexer": "ipython3", 211 | "version": "3.5.1" 212 | }, 213 | "widgets": { 214 | "state": { 215 | "3DD167D680C24D5B974608DDB5E98E87": { 216 | "views": [] 217 | } 218 | }, 219 | "version": "1.1.2" 220 | } 221 | }, 222 | "nbformat": 4, 223 | "nbformat_minor": 0 224 | } 225 | -------------------------------------------------------------------------------- /etc/notebooks/test/test_markdown.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": { 6 | "extensions": { 7 | "jupyter_dashboards": { 8 | "version": 1, 9 | "views": { 10 | "grid_default": { 11 | "col": 0, 12 | "height": 4, 13 | "hidden": false, 14 | "row": 0, 15 | "width": 5 16 | }, 17 | "report_default": { 18 | "hidden": false 19 | } 20 | } 21 | } 22 | } 23 | }, 24 | "source": [ 25 | "# Test Markdown Conversion" 26 | ] 27 | }, 28 | { 29 | "cell_type": "markdown", 30 | "metadata": { 31 | "extensions": { 32 | "jupyter_dashboards": { 33 | "version": 1, 34 | "views": { 35 | "grid_default": { 36 | "col": 9, 37 | "height": 4, 38 | "hidden": false, 39 | "row": 0, 40 | "width": 2 41 | }, 42 | "report_default": { 43 | "hidden": false 44 | } 45 | } 46 | } 47 | } 48 | }, 49 | "source": [ 50 | "I am a markdown cell with no HTML wrapping my **content** which includes [a link in markdown](http://ibm.com)" 51 | ] 52 | }, 53 | { 54 | "cell_type": "markdown", 55 | "metadata": { 56 | "extensions": { 57 | "jupyter_dashboards": { 58 | "version": 1, 59 | "views": { 60 | "grid_default": { 61 | "col": 7, 62 | "height": 4, 63 | "hidden": false, 64 | "row": 0, 65 | "width": 2 66 | }, 67 | "report_default": { 68 | "hidden": false 69 | } 70 | } 71 | } 72 | } 73 | }, 74 | "source": [ 75 | "I am a markdown cell with HTML <small> wrapping my **content** which includes [a link in markdown](http://ibm.com)" 76 | ] 77 | }, 78 | { 79 | "cell_type": "code", 80 | "execution_count": null, 81 | "metadata": { 82 | "extensions": { 83 | "jupyter_dashboards": { 84 | "version": 1, 85 | "views": { 86 | "grid_default": { 87 | "col": 5, 88 | "height": 4, 89 | "hidden": false, 90 | "row": 0, 91 | "width": 2 92 | }, 93 | "report_default": { 94 | "hidden": false 95 | } 96 | } 97 | } 98 | } 99 | }, 100 | "outputs": [], 101 | "source": [ 102 | "%%html\n", 103 | "I am a code %%html cell with <small> wrapping my content which includes a link in HTML" 104 | ] 105 | } 106 | ], 107 | "metadata": { 108 | "celltoolbar": "Section", 109 | "extensions": { 110 | "jupyter_dashboards": { 111 | "activeView": "grid_default", 112 | "version": 1, 113 | "views": { 114 | "grid_default": { 115 | "cellMargin": 10, 116 | "defaultCellHeight": 20, 117 | "maxColumns": 12, 118 | "name": "grid", 119 | "type": "grid" 120 | }, 121 | "report_default": { 122 | "name": "report", 123 | "type": "report" 124 | } 125 | } 126 | } 127 | }, 128 | "kernelspec": { 129 | "display_name": "Python 3", 130 | "language": "python", 131 | "name": "python3" 132 | }, 133 | "language_info": { 134 | "codemirror_mode": { 135 | "name": "ipython", 136 | "version": 3 137 | }, 138 | "file_extension": ".py", 139 | "mimetype": "text/x-python", 140 | "name": "python", 141 | "nbconvert_exporter": "python", 142 | "pygments_lexer": "ipython3", 143 | "version": "3.6.2" 144 | }, 145 | "widgets": { 146 | "state": {}, 147 | "version": "1.1.2" 148 | } 149 | }, 150 | "nbformat": 4, 151 | "nbformat_minor": 1 152 | } 153 | -------------------------------------------------------------------------------- /etc/notebooks/test/test_no_layout.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "## No Layout Metadata\n", 8 | "\n", 9 | "This notebook has no layout metadata in it." 10 | ] 11 | }, 12 | { 13 | "cell_type": "code", 14 | "execution_count": null, 15 | "metadata": { 16 | "collapsed": true 17 | }, 18 | "outputs": [], 19 | "source": [ 20 | "%matplotlib inline" 21 | ] 22 | }, 23 | { 24 | "cell_type": "code", 25 | "execution_count": null, 26 | "metadata": { 27 | "collapsed": true 28 | }, 29 | "outputs": [], 30 | "source": [ 31 | "import seaborn as sns" 32 | ] 33 | }, 34 | { 35 | "cell_type": "code", 36 | "execution_count": null, 37 | "metadata": { 38 | "collapsed": true 39 | }, 40 | "outputs": [], 41 | "source": [ 42 | "tips = sns.load_dataset('tips')" 43 | ] 44 | }, 45 | { 46 | "cell_type": "code", 47 | "execution_count": null, 48 | "metadata": {}, 49 | "outputs": [], 50 | "source": [ 51 | "sns.stripplot(x=\"day\", y=\"total_bill\", hue=\"time\", data=tips)" 52 | ] 53 | } 54 | ], 55 | "metadata": { 56 | "kernelspec": { 57 | "display_name": "Python 3", 58 | "language": "python", 59 | "name": "python3" 60 | }, 61 | "language_info": { 62 | "codemirror_mode": { 63 | "name": "ipython", 64 | "version": 3 65 | }, 66 | "file_extension": ".py", 67 | "mimetype": "text/x-python", 68 | "name": "python", 69 | "nbconvert_exporter": "python", 70 | "pygments_lexer": "ipython3", 71 | "version": "3.6.2" 72 | }, 73 | "widgets": { 74 | "state": {}, 75 | "version": "1.1.2" 76 | } 77 | }, 78 | "nbformat": 4, 79 | "nbformat_minor": 1 80 | } 81 | -------------------------------------------------------------------------------- /etc/notebooks/test/test_widget_overlap.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": { 6 | "extensions": { 7 | "jupyter_dashboards": { 8 | "version": 1, 9 | "views": { 10 | "grid_default": { 11 | "col": 0, 12 | "height": 3, 13 | "hidden": false, 14 | "row": 0, 15 | "width": 12 16 | }, 17 | "report_default": { 18 | "hidden": false 19 | } 20 | } 21 | } 22 | } 23 | }, 24 | "source": [ 25 | "# Test widget overlap\n", 26 | "\n", 27 | "Make sure that the dropdown appears on top of the table both in notebook mode and dashboard mode." 28 | ] 29 | }, 30 | { 31 | "cell_type": "code", 32 | "execution_count": null, 33 | "metadata": { 34 | "extensions": { 35 | "jupyter_dashboards": { 36 | "version": 1, 37 | "views": { 38 | "grid_default": { 39 | "hidden": true 40 | }, 41 | "report_default": { 42 | "hidden": false 43 | } 44 | } 45 | } 46 | } 47 | }, 48 | "outputs": [], 49 | "source": [ 50 | "from ipywidgets import interact\n", 51 | "from IPython.display import display\n", 52 | "import pandas as pd\n", 53 | "import numpy as np" 54 | ] 55 | }, 56 | { 57 | "cell_type": "code", 58 | "execution_count": null, 59 | "metadata": { 60 | "extensions": { 61 | "jupyter_dashboards": { 62 | "version": 1, 63 | "views": { 64 | "grid_default": { 65 | "col": 0, 66 | "height": 18, 67 | "hidden": false, 68 | "row": 3, 69 | "width": 12 70 | }, 71 | "report_default": { 72 | "hidden": false 73 | } 74 | } 75 | } 76 | } 77 | }, 78 | "outputs": [], 79 | "source": [ 80 | "@interact(count=['5','10','15'])\n", 81 | "def render(count):\n", 82 | " count = int(count)\n", 83 | " data = np.random.randn(count, count)\n", 84 | " display(pd.DataFrame(data))" 85 | ] 86 | } 87 | ], 88 | "metadata": { 89 | "extensions": { 90 | "jupyter_dashboards": { 91 | "activeView": "grid_default", 92 | "version": 1, 93 | "views": { 94 | "grid_default": { 95 | "cellMargin": 10, 96 | "defaultCellHeight": 20, 97 | "maxColumns": 12, 98 | "name": "grid", 99 | "type": "grid" 100 | }, 101 | "report_default": { 102 | "name": "report", 103 | "type": "report" 104 | } 105 | } 106 | } 107 | }, 108 | "kernelspec": { 109 | "display_name": "Python 3", 110 | "language": "python", 111 | "name": "python3" 112 | }, 113 | "language_info": { 114 | "codemirror_mode": { 115 | "name": "ipython", 116 | "version": 3 117 | }, 118 | "file_extension": ".py", 119 | "mimetype": "text/x-python", 120 | "name": "python", 121 | "nbconvert_exporter": "python", 122 | "pygments_lexer": "ipython3", 123 | "version": "3.6.2" 124 | }, 125 | "widgets": { 126 | "state": {}, 127 | "version": "1.1.2" 128 | } 129 | }, 130 | "nbformat": 4, 131 | "nbformat_minor": 1 132 | } 133 | -------------------------------------------------------------------------------- /jupyter_dashboards/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Jupyter Development Team. 2 | # Distributed under the terms of the Modified BSD License. 3 | 4 | 5 | def _jupyter_nbextension_paths(): 6 | '''API for JS extension installation on notebook>=4.2''' 7 | return [{ 8 | 'section': 'notebook', 9 | 'src': 'nbextension', 10 | 'dest': 'jupyter_dashboards', 11 | 'require': 'jupyter_dashboards/notebook/main' 12 | }] 13 | -------------------------------------------------------------------------------- /jupyter_dashboards/_version.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Jupyter Development Team. 2 | # Distributed under the terms of the Modified BSD License. 3 | 4 | version_info = (0, 8, 0, 'dev') 5 | __version__ = '.'.join(map(str, version_info)) 6 | -------------------------------------------------------------------------------- /jupyter_dashboards/extensionapp.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Jupyter Development Team. 2 | # Distributed under the terms of the Modified BSD License. 3 | import os.path 4 | import sys 5 | 6 | from ._version import __version__ 7 | 8 | from notebook.nbextensions import (InstallNBExtensionApp, EnableNBExtensionApp, 9 | DisableNBExtensionApp, flags, aliases) 10 | 11 | try: 12 | from notebook.extensions import BaseExtensionApp 13 | _new_extensions = True 14 | except ImportError: 15 | try: 16 | from notebook.nbextensions import BaseNBExtensionApp 17 | BaseExtensionApp = BaseNBExtensionApp 18 | _new_extensions = True 19 | except ImportError: 20 | BaseExtensionApp = object 21 | _new_extensions = False 22 | 23 | from traitlets import Unicode 24 | from traitlets.config.application import catch_config_error 25 | from traitlets.config.application import Application 26 | 27 | # Make copies to reuse flags and aliases 28 | INSTALL_FLAGS = {} 29 | INSTALL_FLAGS.update(flags) 30 | 31 | INSTALL_ALIASES = {} 32 | INSTALL_ALIASES.update(aliases) 33 | del INSTALL_ALIASES['destination'] 34 | 35 | 36 | class ExtensionInstallApp(InstallNBExtensionApp): 37 | '''Subclass that installs this particular extension.''' 38 | name = u'jupyter-dashboards-extension-install' 39 | description = u'Install the jupyter_dashboards extension' 40 | 41 | flags = INSTALL_FLAGS 42 | aliases = INSTALL_ALIASES 43 | 44 | examples = """ 45 | jupyter dashboards install 46 | jupyter dashboards install --user 47 | jupyter dashboards install --prefix=/path/to/prefix 48 | jupyter dashboards install --nbextensions=/path/to/nbextensions 49 | """ 50 | 51 | destination = Unicode('') 52 | 53 | def _classes_default(self): 54 | return [ExtensionInstallApp, InstallNBExtensionApp] 55 | 56 | def start(self): 57 | here = os.path.abspath(os.path.join(os.path.dirname(__file__))) 58 | 59 | self.log.info("Installing jupyter_dashboards JS notebook extensions") 60 | self.extra_args = [os.path.join(here, 'nbextension')] 61 | self.destination = 'jupyter_dashboards' 62 | self.install_extensions() 63 | self.log.info('Done.') 64 | 65 | 66 | class ExtensionActivateApp(EnableNBExtensionApp): 67 | '''Subclass that activates this particular extension.''' 68 | name = u'jupyter-dashboards-extension-activate' 69 | description = u'Activate the jupyter_dashboards extension' 70 | 71 | flags = {} 72 | aliases = {} 73 | 74 | examples = """ 75 | jupyter dashboards activate 76 | """ 77 | 78 | def _classes_default(self): 79 | return [ExtensionActivateApp, EnableNBExtensionApp] 80 | 81 | def start(self): 82 | self.log.info("Activating jupyter_dashboards JS notebook extensions") 83 | self.section = "notebook" 84 | self.enable_nbextension("jupyter_dashboards/notebook/main") 85 | self.log.info("Done.") 86 | 87 | 88 | class ExtensionDeactivateApp(DisableNBExtensionApp): 89 | '''Subclass that deactivates this particular extension.''' 90 | name = u'jupyter-dashboards-extension-deactivate' 91 | description = u'Deactivate the jupyter_dashboards extension' 92 | 93 | flags = {} 94 | aliases = {} 95 | 96 | examples = """ 97 | jupyter dashboards deactivate 98 | """ 99 | 100 | def _classes_default(self): 101 | return [ExtensionDeactivateApp, DisableNBExtensionApp] 102 | 103 | def start(self): 104 | self.log.info("Deactivating jupyter_dashboards JS notebook extensions") 105 | self.section = "notebook" 106 | self.disable_nbextension("jupyter_dashboards/notebook/main") 107 | self.log.info("Done.") 108 | 109 | 110 | class ExtensionQuickSetupApp(BaseExtensionApp): 111 | """Installs and enables all parts of this extension""" 112 | name = "jupyter dashboards quick-setup" 113 | version = __version__ 114 | description = "Installs and enables all features of the jupyter_dashboards extension" 115 | 116 | def start(self): 117 | self.argv.extend(['--py', 'jupyter_dashboards']) 118 | 119 | from notebook import nbextensions 120 | install = nbextensions.InstallNBExtensionApp() 121 | install.initialize(self.argv) 122 | install.start() 123 | enable = nbextensions.EnableNBExtensionApp() 124 | enable.initialize(self.argv) 125 | enable.start() 126 | 127 | 128 | class ExtensionQuickRemovalApp(BaseExtensionApp): 129 | """Disables and uninstalls all parts of this extension""" 130 | name = "jupyter dashboards quick-remove" 131 | version = __version__ 132 | description = "Disables and removes all features of the jupyter_dashboards extension" 133 | 134 | def start(self): 135 | self.argv.extend(['--py', 'jupyter_dashboards']) 136 | 137 | from notebook import nbextensions 138 | enable = nbextensions.DisableNBExtensionApp() 139 | enable.initialize(self.argv) 140 | enable.start() 141 | install = nbextensions.UninstallNBExtensionApp() 142 | install.initialize(self.argv) 143 | install.start() 144 | 145 | 146 | class ExtensionApp(Application): 147 | '''CLI for extension management.''' 148 | name = u'jupyter_dashboards extension' 149 | description = u'Utilities for managing the jupyter_dashboards extension' 150 | examples = "" 151 | 152 | subcommands = {} 153 | if _new_extensions: 154 | subcommands.update({ 155 | "quick-setup": ( 156 | ExtensionQuickSetupApp, 157 | "Install and enable everything in the package (notebook>=4.2)" 158 | ), 159 | "quick-remove": ( 160 | ExtensionQuickRemovalApp, 161 | "Disable and uninstall everything in the package (notebook>=4.2)" 162 | ) 163 | }) 164 | else: 165 | subcommands.update(dict( 166 | install=( 167 | ExtensionInstallApp, 168 | "Install the extension." 169 | ), 170 | activate=( 171 | ExtensionActivateApp, 172 | "Activate the extension." 173 | ), 174 | deactivate=( 175 | ExtensionDeactivateApp, 176 | "Deactivate the extension." 177 | ) 178 | )) 179 | 180 | def _classes_default(self): 181 | classes = super(ExtensionApp, self)._classes_default() 182 | 183 | # include all the apps that have configurable options 184 | for appname, (app, help) in self.subcommands.items(): 185 | if len(app.class_traits(config=True)) > 0: 186 | classes.append(app) 187 | 188 | @catch_config_error 189 | def initialize(self, argv=None): 190 | super(ExtensionApp, self).initialize(argv) 191 | 192 | def start(self): 193 | # check: is there a subapp given? 194 | if self.subapp is None: 195 | self.print_help() 196 | sys.exit(1) 197 | 198 | # This starts subapps 199 | super(ExtensionApp, self).start() 200 | 201 | 202 | def main(): 203 | ExtensionApp.launch_instance() 204 | -------------------------------------------------------------------------------- /jupyter_dashboards/nbextension/notebook/dashboard-common/dashboard-common.css: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) Jupyter Development Team. 3 | * Distributed under the terms of the Modified BSD License. 4 | */ 5 | 6 | .jupyter-dashboard .container div.output_wrapper { 7 | z-index: auto; /* override `z-index:1` set by Notebook */ 8 | } 9 | 10 | .jupyter-dashboard .container div.output_subarea { 11 | max-width: 100%; /* override Notebook CSS so it takes up full width */ 12 | overflow: hidden; /* hide overflowing contents */ 13 | } 14 | 15 | /* disable display of paragraph anchor text*/ 16 | .jupyter-dashboard .container h1 .anchor-link, 17 | .jupyter-dashboard .container h2 .anchor-link, 18 | .jupyter-dashboard .container h3 .anchor-link, 19 | .jupyter-dashboard .container h4 .anchor-link, 20 | .jupyter-dashboard .container h5 .anchor-link, 21 | .jupyter-dashboard .container h6 .anchor-link { 22 | display: none; 23 | } 24 | -------------------------------------------------------------------------------- /jupyter_dashboards/nbextension/notebook/dashboard-common/error-log.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) Jupyter Development Team. 3 | * Distributed under the terms of the Modified BSD License. 4 | */ 5 | 6 | /** 7 | * Registers an error handler which prints errors to the JS console. 8 | */ 9 | define([ 10 | 'require', 11 | 'jquery' 12 | ], function( 13 | require, 14 | $ 15 | ) { 16 | 'use strict'; 17 | var enabled = false; 18 | return { 19 | /** 20 | * Show IOPub errors in the JS console. 21 | * @param {object} IPython "global" IPython singleton 22 | */ 23 | enable: function(IPython) { 24 | if (!enabled) { 25 | var errorHandler = IPython.notebook.kernel.get_iopub_handler('error'); // save old handler 26 | IPython.notebook.kernel.register_iopub_handler('error', function(msg) { 27 | errorHandler(msg); // call old handler 28 | 29 | var data; 30 | try { 31 | data = msg.content.traceback.join('\n'); 32 | } catch(e) { 33 | console.error('A kernel error occured without a traceback'); 34 | return; 35 | } 36 | try { 37 | // Try to pretty-print the error if IPython.utils are available 38 | // print error to console (following code as seen in Notebook's OutputArea.append_text) 39 | data = IPython.utils.fixConsole(data); 40 | data = IPython.utils.fixCarriageReturn(data); 41 | data = IPython.utils.autoLinkUrls(data); 42 | // `data` is HTML, print out text-only 43 | console.error($('
').append(data).text()); 44 | } catch(e) { 45 | // Otherwise print what we can: the raw data 46 | console.error(data); 47 | } 48 | }); 49 | enabled = true; 50 | } 51 | } 52 | }; 53 | }); 54 | -------------------------------------------------------------------------------- /jupyter_dashboards/nbextension/notebook/dashboard-common/gridstack-custom.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) Jupyter Development Team. 3 | * Distributed under the terms of the Modified BSD License. 4 | */ 5 | 6 | /** 7 | * Overrides some Gridstack functions 8 | */ 9 | define(['jquery', 'Gridstack'], function($, Gridstack) { 10 | 11 | var GridstackCustom = function() { 12 | Gridstack.apply(this, arguments); 13 | }; 14 | 15 | GridstackCustom.prototype = Object.create(Gridstack.prototype); 16 | GridstackCustom.prototype.constructor = GridstackCustom; 17 | 18 | GridstackCustom.prototype.__destroy = Gridstack.prototype.destroy; 19 | GridstackCustom.prototype.destroy = function(detach_node) { 20 | detach_node = typeof detach_node === 'undefined' ? true : detach_node; 21 | 22 | if (!detach_node) { 23 | // Gridstack.destroy() removes the container from the DOM. Hack around it to make it 24 | // a no-op if `detach_node` is false. 25 | var $container = this.container; 26 | var oldRemove = $.fn.remove; 27 | $.fn.remove = function() { 28 | if (!this.is($container)) { 29 | return oldRemove.apply(this, arguments); 30 | } 31 | return this; 32 | }; 33 | } 34 | 35 | this.__destroy(); 36 | 37 | if (!detach_node) { 38 | $.fn.remove = oldRemove; 39 | } 40 | }; 41 | 42 | /** 43 | * Generates cell styles which depend on margin (which is a layout option). 44 | * @param {Object[]} rules - list of style rules 45 | * @param {string} rules[].selector - CSS style selector 46 | * @param {string} rules[].rules - CSS style rules for given selector 47 | */ 48 | GridstackCustom.prototype.generateStylesheet = function(rules) { 49 | var Utils = Gridstack.Utils; 50 | 51 | // init new style 52 | this._styles_id_2 = 'gridstack-style-' + (Math.random() * 100000).toFixed(); 53 | this._styles_2 = Utils.create_stylesheet(this._styles_id_2); 54 | var style = this._styles_2; 55 | 56 | rules.forEach(function(item, i) { 57 | Utils.insert_css_rule(style, 58 | item.selector, 59 | item.rules, 60 | i 61 | ); 62 | }); 63 | }; 64 | 65 | GridstackCustom.prototype.removeStylesheet = function() { 66 | if (this._styles_id_2) { 67 | Gridstack.Utils.remove_stylesheet(this._styles_id_2); 68 | } 69 | }; 70 | 71 | window.GridStackUI = GridstackCustom; 72 | window.GridStackUI.Utils = Gridstack.Utils; 73 | 74 | // Override jQuery function to use our custom class 75 | $.fn.gridstack = function(opts) { 76 | return this.each(function() { 77 | if (!$(this).data('gridstack')) { 78 | $(this).data('gridstack', new GridstackCustom(this, opts)); 79 | } 80 | }); 81 | }; 82 | 83 | return GridstackCustom; 84 | 85 | }); 86 | -------------------------------------------------------------------------------- /jupyter_dashboards/nbextension/notebook/dashboard-common/gridstack-overrides.css: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) Jupyter Development Team. 3 | * Distributed under the terms of the Modified BSD License. 4 | */ 5 | 6 | /**************************************************** 7 | * Override Gridstack width properties so that we * 8 | * can show a margin between horizontal cells. * 9 | ****************************************************/ 10 | .grid-stack > .grid-stack-item { 11 | min-width: 0; 12 | } 13 | -------------------------------------------------------------------------------- /jupyter_dashboards/nbextension/notebook/dashboard-view/dashboard-actions.css: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) Jupyter Development Team. 3 | * Distributed under the terms of the Modified BSD License. 4 | */ 5 | 6 | .jupyter-dashboard-menu-item { 7 | position: relative; 8 | } 9 | .jupyter-dashboard-menu-item.selected::before { 10 | font-family: FontAwesome; 11 | content: '\f00c'; 12 | position: absolute; 13 | left: 4px; 14 | top: 3px; 15 | } 16 | 17 | .jupyter-dashboard-toolbar-buttons { 18 | display: -webkit-inline-flex; 19 | display: -ms-inline-flexbox; 20 | display: inline-flex; 21 | -webkit-align-items: center; 22 | -ms-flex-align: center; 23 | align-items: center; 24 | } 25 | #maintoolbar .jupyter-dashboard-toolbar-buttons .navbar-text { 26 | margin: 0 5px; 27 | } 28 | 29 | /* Dashboard authoring button with embedded layout dropdown */ 30 | #jupyter-dashboard-view-toolbar-buttons > button:first-of-type { 31 | border-top-left-radius: 2px; 32 | border-bottom-left-radius: 2px; 33 | } 34 | #jupyter-dashboard-view-toolbar-buttons > .dashboard-authoring-btn-container { 35 | display: -webkit-inline-flex; 36 | display: -ms-inline-flexbox; 37 | display: inline-flex; 38 | border-width: 0; 39 | padding: 0; 40 | } 41 | #jupyter-dashboard-view-toolbar-buttons > .dashboard-authoring-btn-container .dashboard-authoring-btn, 42 | #jupyter-dashboard-view-toolbar-buttons > .dashboard-authoring-btn-container .db-embedded-dropdown-toggle { 43 | border-radius: 0; 44 | border-color: inherit; 45 | } 46 | #jupyter-dashboard-view-toolbar-buttons > .dashboard-authoring-btn-container .dashboard-authoring-btn { 47 | border-right: none; 48 | background-color: transparent; 49 | } 50 | #jupyter-dashboard-view-toolbar-buttons > .dashboard-authoring-btn-container .db-embedded-dropdown-toggle { 51 | border-left: none; 52 | background-color: transparent; 53 | } 54 | #jupyter-dashboard-view-toolbar-buttons .dashboard-layout-menu-item { 55 | display: -webkit-flex; 56 | display: -ms-flexbox; 57 | display: flex; 58 | } 59 | #jupyter-dashboard-view-toolbar-buttons .dashboard-layout-menu-item a { 60 | flex-grow: 1; 61 | padding-left: 10px; 62 | } 63 | #jupyter-dashboard-view-toolbar-buttons .dashboard-layout-menu-item a i { 64 | margin-right: 8px; 65 | } 66 | -------------------------------------------------------------------------------- /jupyter_dashboards/nbextension/notebook/dashboard-view/dashboard-actions.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) Jupyter Development Team. 3 | * Distributed under the terms of the Modified BSD License. 4 | */ 5 | /** 6 | * This module handles dashboard view menu and toolbar creation and actions. 7 | */ 8 | define([ 9 | 'jquery', 10 | 'base/js/namespace', 11 | './dashboard-metadata', 12 | 'template!./view-toolbar-buttons.html', 13 | 'template!./sub-menu.html', 14 | 'template!./view-menu.html' 15 | ], function( 16 | $, 17 | IPython, 18 | Metadata, 19 | $viewToolbarBtnsTemplate, 20 | $subMenuTemplate, 21 | $viewMenuTemplate 22 | ) { 23 | 'use strict'; 24 | 25 | // These states are used in html templates as data-dashboard-state 26 | // DASHBOARD_AUTH_* states are saved in notebook metadata as layout 27 | var STATE = Object.freeze({ 28 | NOTEBOOK: 'notebook', 29 | DASHBOARD_AUTH_GRID: 'grid', 30 | DASHBOARD_AUTH_REPORT: 'report', 31 | DASHBOARD_PREVIEW: 'preview' 32 | }); 33 | var currentState = STATE.NOTEBOOK; 34 | var toolbarBtnsSelector = '#jupyter-dashboard-view-toolbar-buttons'; 35 | var isHeaderVisible = true, isToolbarVisible = true; 36 | var opts, scrollToBottom; 37 | 38 | function enterDashboardMode(newState) { 39 | opts.enterDbModeCallback(newState); 40 | // disable scroll to bottom of notebook 41 | scrollToBottom = IPython.Notebook.prototype.scroll_to_bottom; 42 | IPython.Notebook.prototype.scroll_to_bottom = function() {}; 43 | } 44 | 45 | function exitDashboardMode() { 46 | opts.exitDbModeCallback(); 47 | // restore scrolling behavior 48 | IPython.Notebook.prototype.scroll_to_bottom = scrollToBottom; 49 | scrollToBottom = null; 50 | } 51 | 52 | function getFaIconClass(el) { 53 | return $(el).attr('class').split(' ').filter(function(value) { 54 | return /^fa-/.test(value); 55 | })[0]; 56 | } 57 | 58 | function updateAuthoringButtonState(state) { 59 | if (state && 60 | state !== STATE.NOTEBOOK && 61 | state !== STATE.DASHBOARD_PREVIEW) { 62 | var $btns = $(toolbarBtnsSelector); 63 | var icon = getFaIconClass($btns.find( 64 | '.dashboard-layout-menu-item[data-dashboard-state="' + state + '"] i')); 65 | $btns.find('.dashboard-authoring-btn') 66 | .attr('data-dashboard-state', state) 67 | .find('.dashboard-authoring-icon') 68 | .removeClass(function() { 69 | return getFaIconClass(this); 70 | }) 71 | .addClass(icon); 72 | } 73 | } 74 | 75 | function updateAuthoringOptions(state) { 76 | // update the layout button to reflect the current notebook layout mode 77 | updateAuthoringButtonState(state); 78 | 79 | // enable the correct button group and menu state items 80 | var activeBtn = $(toolbarBtnsSelector + ' button:not(.dropdown-toggle)[data-dashboard-state="' + state + '"]'); 81 | if (activeBtn.is('.dashboard-authoring-btn')) { 82 | activeBtn = activeBtn.parent(); 83 | } 84 | activeBtn.addClass('active').siblings().removeClass('active'); 85 | $('#view_menu [data-dashboard-state]').each(function() { 86 | $(this).toggleClass('selected', state === $(this).attr('data-dashboard-state')); 87 | }); 88 | 89 | // disable show/hide menu items when in preview state 90 | $('.dashboard-submenu-item').toggleClass('disabled', state === STATE.NOTEBOOK || state === STATE.DASHBOARD_PREVIEW); 91 | $('#jupyter-dashboard-show-all').toggleClass('disabled', state === STATE.NOTEBOOK || state === STATE.DASHBOARD_PREVIEW || state === STATE.DASHBOARD_AUTH_REPORT); 92 | } 93 | 94 | function setDashboardState(newState) { 95 | if (newState !== currentState) { 96 | if (newState === STATE.NOTEBOOK) { 97 | exitDashboardMode(); 98 | } else { 99 | enterDashboardMode(newState); 100 | } 101 | updateUIState(newState); 102 | currentState = newState; 103 | } 104 | } 105 | 106 | function setHeaderVisibility(doShow) { 107 | // if hiding, save current state 108 | if (!doShow) { 109 | isHeaderVisible = $('#header-container').is(':visible'); 110 | isToolbarVisible = $('div#maintoolbar').is(':visible'); 111 | } 112 | // hide or revert back to previous state 113 | $('#header-container, .header-bar').toggle(doShow && isHeaderVisible); 114 | $('div#maintoolbar').toggle(doShow && isToolbarVisible); 115 | IPython.notebook.events.trigger('resize-header.Page'); 116 | } 117 | 118 | function setStateFromQueryString() { 119 | // set 'Dashboard View' state if 'dashboard' query parameter is set 120 | var idx = window.location.search.slice(1).split(/[&=]/).indexOf('dashboard'); 121 | if (idx !== -1) { 122 | setDashboardState(STATE.DASHBOARD_PREVIEW); 123 | } 124 | } 125 | 126 | function updateUIState(state) { 127 | var isDashboardPreview = state === STATE.DASHBOARD_PREVIEW; 128 | updateUrlState(isDashboardPreview); 129 | setHeaderVisibility(!isDashboardPreview); 130 | updateAuthoringOptions(state); 131 | 132 | // set view-only class if previewing the dashboard 133 | $('body').toggleClass('view-only', state === STATE.DASHBOARD_PREVIEW); 134 | 135 | // disable code editing when in a dashboard view 136 | $('.CodeMirror').each(function() { 137 | this.CodeMirror.setOption('readOnly', state === STATE.NOTEBOOK ? false : 'nocursor'); 138 | }); 139 | } 140 | 141 | function updateUrlState(inDashboardViewMode) { 142 | var l = window.location, s = l.search.slice(1); 143 | if (inDashboardViewMode) { 144 | if (s.split(/[&=]/).indexOf('dashboard') === -1) { 145 | s += (s.length ? '&' : '') + 'dashboard'; 146 | } 147 | } else { 148 | var params = s.split('&'); 149 | var idx = params.indexOf('dashboard'); 150 | if (idx !== -1) { 151 | params.splice(idx, 1); 152 | } 153 | s = params.join('&'); 154 | } 155 | var url = l.protocol + '//' + l.host + l.pathname + (s.length ? '?' + s : ''); 156 | window.history.replaceState(null, null, url); 157 | } 158 | 159 | /*************************************/ 160 | var DashboardActions = function(args) { 161 | opts = { 162 | enterDbModeCallback: args.enterDashboardMode, 163 | exitDbModeCallback: args.exitDashboardMode, 164 | showAllCallback: args.showAll, 165 | showAllStackedCallback: args.showAllStacked, 166 | hideAllCallback: args.hideAll 167 | }; 168 | setStateFromQueryString(); 169 | }; 170 | 171 | Object.defineProperty(DashboardActions, 'STATE', { 172 | value: STATE, 173 | writable: false 174 | }); 175 | 176 | DashboardActions.prototype.addMenuItems = function() { 177 | // Add view menu items and hook up click handlers to set state 178 | $('#view_menu').append('
  • ', $viewMenuTemplate.clone()) 179 | .find('[data-dashboard-state]') 180 | .click(function() { 181 | var $el = $(this); 182 | var state = $el.attr('data-dashboard-state'); 183 | if ($el.parents('#jupyter-dashboard-layout-menu').length) { 184 | Metadata.activeView = state; 185 | } 186 | setDashboardState(state); 187 | }) 188 | .filter(function() { 189 | return $(this).attr('data-dashboard-state') === currentState; 190 | }).addClass('selected'); // initial selected view menu item 191 | 192 | // Cell menu items to show/hide cells 193 | $('#cell_menu').append('
  • ', $subMenuTemplate.clone()); 194 | $('#jupyter-dashboard-show-all').click(opts.showAllCallback); 195 | $('#jupyter-dashboard-show-all-stacked').click(opts.showAllStackedCallback); 196 | $('#jupyter-dashboard-hide-all').click(opts.hideAllCallback); 197 | }; 198 | 199 | DashboardActions.prototype.addToolbarItems = function() { 200 | // add toolbar buttons from template and add click handlers 201 | $(IPython.toolbar.selector).append($viewToolbarBtnsTemplate.clone()); 202 | $(toolbarBtnsSelector + ' [data-dashboard-state]').click(function() { 203 | setDashboardState($(this).attr('data-dashboard-state')); 204 | }); 205 | // update the authoring element based on current state 206 | updateAuthoringOptions(currentState); 207 | // also set the initial layout button default to whatever layout the 208 | // notebook currently has 209 | updateAuthoringButtonState(Metadata.activeView); 210 | }; 211 | 212 | DashboardActions.prototype.switchToNotebook = function() { 213 | setDashboardState(STATE.NOTEBOOK); 214 | }; 215 | 216 | return DashboardActions; 217 | }); 218 | -------------------------------------------------------------------------------- /jupyter_dashboards/nbextension/notebook/dashboard-view/dashboard-metadata-compatibility.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) Jupyter Development Team. 3 | * Distributed under the terms of the Modified BSD License. 4 | */ 5 | /** 6 | * This module provides an API to manage compatibility between 7 | * Jupyter Dashboards extension metadata. 8 | * 9 | * Jupyter Dashboard metadata structure: 10 | * https://github.com/jupyter/dashboards/wiki/Dashboard-Metadata-and-Rendering 11 | */ 12 | define([ 13 | 'jquery', 14 | 'base/js/namespace', 15 | './object-util' 16 | ], function( 17 | $, 18 | IPython, 19 | ObjectUtil 20 | ) { 21 | 'use strict'; 22 | 23 | var GRID_DEFAULT = 'grid_default'; 24 | var REPORT_DEFAULT = 'report_default'; 25 | 26 | // Mapping of view type to view id (from dashboard-metadata.js) 27 | // This will change when multiple views of the same type are supported. 28 | var VIEW_TO_ID = { 29 | grid: GRID_DEFAULT, 30 | report: REPORT_DEFAULT 31 | }; 32 | 33 | return { 34 | /** 35 | * Converts version 0.x metadata structure to version 1. 36 | * Versions 0.x and 1 currently do not overlap. 37 | * This must be run AFTER the version 1 metadata is initialized in 38 | * `dashboard-metadata.js`. 39 | */ 40 | convert: function() { 41 | var metadata = IPython.notebook.metadata; 42 | var jupyter_dashboards = metadata.extensions.jupyter_dashboards; 43 | 44 | // 0.x metadata resides under "urth" 45 | var oldNotebookMetadata = IPython.notebook.metadata.urth; 46 | if (!oldNotebookMetadata) { return; } 47 | 48 | // notebook-level metadata 49 | if (oldNotebookMetadata.dashboard) { 50 | // set active view 51 | if (oldNotebookMetadata.dashboard.layout) { 52 | jupyter_dashboards.activeView = 53 | VIEW_TO_ID[oldNotebookMetadata.dashboard.layout]; 54 | } else { 55 | jupyter_dashboards.activeView = GRID_DEFAULT; 56 | } 57 | 58 | // copy dashboard properties 59 | Object.keys(oldNotebookMetadata.dashboard).filter(function(key) { 60 | return key !== 'layout'; 61 | }).forEach(function(key) { 62 | jupyter_dashboards.views[jupyter_dashboards.activeView][key] = 63 | oldNotebookMetadata.dashboard[key]; 64 | }); 65 | } 66 | 67 | // cell-level metadata 68 | IPython.notebook.get_cells().forEach(function(cell) { 69 | if (ObjectUtil.has(cell, 'metadata.urth.dashboard')) { 70 | var cellMetadata = cell.metadata; 71 | var cellDashboard = cellMetadata.extensions.jupyter_dashboards; 72 | 73 | // copy hidden state 74 | Object.keys(cellDashboard.views).forEach(function(view) { 75 | cellDashboard.views[view].hidden = false; 76 | }); 77 | if (jupyter_dashboards.activeView === GRID_DEFAULT && 78 | Object.keys(cellMetadata.urth.dashboard).length === 0) { 79 | // special case: empty grid cells were implicitly hidden 80 | cellDashboard.views[jupyter_dashboards.activeView].hidden = true; 81 | } else { 82 | cellDashboard.views[jupyter_dashboards.activeView].hidden = 83 | !!cellMetadata.urth.dashboard.hidden; 84 | } 85 | 86 | // copy layout properties 87 | if (cellMetadata.urth.dashboard.layout) { 88 | var cellLayout = cellMetadata.urth.dashboard.layout; 89 | 90 | // only grid layout has properties 91 | // so copy all layout properties into default grid view 92 | Object.keys(cellLayout).forEach(function(key) { 93 | cellDashboard.views[GRID_DEFAULT][key] = cellLayout[key]; 94 | }); 95 | } 96 | 97 | // clear old metadata 98 | delete cellMetadata.urth; 99 | } 100 | }); 101 | 102 | // clear old metadata 103 | delete IPython.notebook.metadata.urth; 104 | } 105 | }; 106 | }); 107 | -------------------------------------------------------------------------------- /jupyter_dashboards/nbextension/notebook/dashboard-view/dashboard-view.css: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) Jupyter Development Team. 3 | * Distributed under the terms of the Modified BSD License. 4 | */ 5 | 6 | /* hide extraneous cell parts when in dashboard view */ 7 | .jupyter-dashboard .celltoolbar, 8 | .jupyter-dashboard .container .cell .prompt, 9 | .jupyter-dashboard .container .cell .output_stderr, 10 | .jupyter-dashboard .container .cell .output_error { 11 | display: none !important; /* Necessary to override inline style set by notebook */ 12 | } 13 | 14 | /* Dashboard cell */ 15 | .jupyter-dashboard .cell { 16 | position: relative; 17 | } 18 | .jupyter-dashboard .cell, 19 | .jupyter-dashboard .cell.selected { 20 | background: transparent; 21 | border: none; 22 | padding: 0; 23 | } 24 | .jupyter-dashboard .cell.selected:before { 25 | background: transparent; 26 | } 27 | 28 | /* Show cell code in the background of each cell */ 29 | .jupyter-dashboard:not(.view-only) .cell > .input { 30 | position: absolute; 31 | top: 0; 32 | left: 0; 33 | height: 100%; 34 | padding: 0.5em 1em; 35 | overflow: hidden; 36 | opacity: 0; 37 | transition: opacity 0.3s; 38 | } 39 | .jupyter-dashboard:not(.view-only) #notebook-container:not(.hide-code):hover .cell > .input { 40 | opacity: 0.3; 41 | } 42 | .jupyter-dashboard:not(.view-only) #notebook-container:not(.hide-code) .cell > .input div.input_area { 43 | border: none; 44 | background: none; 45 | } 46 | 47 | /* Dashboard cell controls */ 48 | .jupyter-dashboard .cell .cell-control-container { 49 | display: flex; 50 | position: absolute; 51 | color: #b2b2b2; 52 | visibility: hidden; 53 | 54 | background-color: #fff; 55 | border: 1px solid #eee; 56 | 57 | /* widgets overlap, so pull forward */ 58 | z-index: 100; 59 | } 60 | .jupyter-dashboard:not(.view-only) .cell:hover .cell-control-container { 61 | visibility: visible; 62 | } 63 | .jupyter-dashboard .cell .cell-control-container.cell-control-nw { 64 | border-top: none; 65 | border-left: none; 66 | top: 0; 67 | left: 0; 68 | } 69 | .jupyter-dashboard .cell .cell-control-container.cell-control-ne { 70 | border-top: none; 71 | border-right: none; 72 | top: 0; 73 | right: 0; 74 | } 75 | .jupyter-dashboard .cell .cell-control-container.cell-control-se { 76 | border-bottom: none; 77 | border-right: none; 78 | bottom: 0; 79 | right: 0; 80 | } 81 | .jupyter-dashboard .cell .cell-control { 82 | padding: 5px; 83 | width: 25px; 84 | height: 25px; 85 | text-align: center; 86 | cursor: pointer; 87 | } 88 | .jupyter-dashboard .cell .cell-control:hover { 89 | color: #306c9e; 90 | } 91 | .jupyter-dashboard .cell .cell-control.hide-btn:hover { 92 | color: red; 93 | } 94 | 95 | /* Hidden Cells */ 96 | .jupyter-dashboard #dashboard-hidden-header { 97 | height: 150px; 98 | padding: 15px; 99 | } 100 | .jupyter-dashboard #dashboard-hidden-header .header { 101 | display: -webkit-flex; 102 | display: -ms-flexbox; 103 | display: flex; 104 | -webkit-align-items: center; 105 | -ms-flex-align: center; 106 | align-items: center; 107 | margin: 2em 0; 108 | padding-top: 50px; 109 | } 110 | .jupyter-dashboard #dashboard-hidden-header .header .title { 111 | margin: 0 1em 0 0; 112 | } 113 | .jupyter-dashboard #dashboard-hidden-header .header .btn:not(.btn-info) { 114 | background-color: transparent; 115 | border: 1px solid black; 116 | } 117 | 118 | /* Dashboard preview */ 119 | .jupyter-dashboard.view-only #dashboard-hidden-header { 120 | display: none; 121 | } 122 | .jupyter-dashboard.view-only .cell > .input { 123 | display: none !important; /* Necessary to override inline style set by notebook */ 124 | } 125 | 126 | /* Edit cell animation */ 127 | .cell.edit-select { 128 | -webkit-animation: shadow-fade 2s linear 250ms; 129 | animation: shadow-fade 2s linear 250ms; 130 | } 131 | @-webkit-keyframes shadow-fade { 132 | 0% { box-shadow: 0 0 10px 2px #5bc0de; } 133 | 100% { box-shadow: 0 0 10px 2px transparent; } 134 | } 135 | @keyframes shadow-fade { 136 | 0% { box-shadow: 0 0 10px 2px #5bc0de; } 137 | 100% { box-shadow: 0 0 10px 2px transparent; } 138 | } 139 | 140 | /* Declarative widgets specific styles */ 141 | .jupyter-dashboard .cell .urth-widget-error { 142 | display: none; 143 | } 144 | -------------------------------------------------------------------------------- /jupyter_dashboards/nbextension/notebook/dashboard-view/dashboard-view.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) Jupyter Development Team. 3 | * Distributed under the terms of the Modified BSD License. 4 | */ 5 | /* global console, requirejs */ 6 | 7 | /** 8 | * This module extends the notebook to allow dashboard creation and viewing. 9 | */ 10 | define([ 11 | 'jquery', 12 | 'require', 13 | './polymer-support', 14 | '../link-css' 15 | ], function( 16 | $, 17 | require, 18 | PolymerSupport, 19 | linkCSS 20 | ) { 21 | 'use strict'; 22 | 23 | // use global require.js to setup the paths for our dependencies 24 | requirejs.config({ 25 | packages: [ 26 | { name: 'dashboard-common', location: require.toUrl('../dashboard-common').split('?')[0] } 27 | ], 28 | paths: { 29 | Gridstack: require.toUrl('../bower_components/gridstack/dist/gridstack.min').split('?')[0], 30 | lodash: require.toUrl('../bower_components/lodash/lodash').split('?')[0], 31 | text: require.toUrl('../bower_components/requirejs-text/text').split('?')[0], 32 | template: require.toUrl('./template-loader').split('?')[0] 33 | // jquery-ui is already loaded by Notebook, as 'jqueryui' in 4.0.x and 'jquery-ui' in 4.1.x 34 | }, 35 | map: { 36 | // Gridstack uses jquery-ui 1.11 (supports AMD) while notebook uses 1.10 (non-amd). 37 | // Map Gridstack to the old non-AMD jquery-ui used by notebook. 38 | // We can't just use the 'jqueryui' that is mapped back to 'jquery-ui' in notebook 4.1.x+ 39 | // because requirejs does not recursively apply maps and instead chooses the most 40 | // specific rule. Here, that would be whatever we set for Gridstack vs whatever notebook 41 | // set for '*'. 42 | Gridstack: { 43 | 'jquery-ui/core': require.specified('jquery-ui') ? 'jquery-ui' : 'jqueryui', 44 | 'jquery-ui/mouse': require.specified('jquery-ui') ? 'jquery-ui' : 'jqueryui', 45 | 'jquery-ui/widget': require.specified('jquery-ui') ? 'jquery-ui' : 'jqueryui', 46 | 'jquery-ui/resizable': require.specified('jquery-ui') ? 'jquery-ui' : 'jqueryui', 47 | 'jquery-ui/draggable': require.specified('jquery-ui') ? 'jquery-ui' : 'jqueryui' 48 | } 49 | } 50 | }); 51 | 52 | linkCSS('./dashboard-view/dashboard-actions.css'); 53 | linkCSS('./dashboard-common/dashboard-common.css'); 54 | linkCSS('./dashboard-view/dashboard-view.css'); 55 | 56 | var dashboard; 57 | var $helpArea; 58 | function getLayout(dbActions, module, opts) { 59 | return { 60 | module: module, 61 | opts: $.extend({ 62 | $container: $('#notebook-container'), 63 | scrollContainer: $('#site').get(0), 64 | exit: function() { 65 | dbActions.switchToNotebook(); 66 | } 67 | }, opts) 68 | }; 69 | } 70 | 71 | PolymerSupport.init(); 72 | 73 | // dashboard-actions depends on requirejs text plugin 74 | require([ 75 | 'base/js/namespace', 76 | './dashboard-actions', 77 | './dashboard-metadata', 78 | './dashboard-metadata-compatibility' 79 | ], function( 80 | Jupyter, 81 | DashboardActions, 82 | Metadata, 83 | Compatibility 84 | ) { 85 | var dashboardClass = 'jupyter-dashboard'; 86 | if (Jupyter.notebook.metadata.hasOwnProperty('urth')) { 87 | // convert old metadata spec to new version 88 | Metadata.initialize(); 89 | Compatibility.convert(); 90 | } 91 | var dbActions = new DashboardActions({ 92 | enterDashboardMode: function(actionState) { 93 | $('body').addClass(dashboardClass); 94 | require([ 95 | './layout/grid/layout', 96 | './layout/report/layout', 97 | 'template!./help.html' 98 | ], function( 99 | GridLayout, 100 | ReportLayout, 101 | $helpTemplate 102 | ) { 103 | var LAYOUT = {}; 104 | LAYOUT[Metadata.DASHBOARD_VIEW.GRID] = getLayout(dbActions, GridLayout, { 105 | onResize: PolymerSupport.onResize 106 | }); 107 | LAYOUT[Metadata.DASHBOARD_VIEW.REPORT] = getLayout(dbActions, ReportLayout); 108 | 109 | if (actionState !== DashboardActions.STATE.NOTEBOOK && 110 | !Metadata.activeView) { 111 | // set to grid by default if layout not set 112 | Metadata.activeView = Metadata.DASHBOARD_VIEW.GRID; 113 | } 114 | LAYOUT[DashboardActions.STATE.DASHBOARD_PREVIEW] = LAYOUT[Metadata.activeView]; 115 | var layout = LAYOUT[actionState]; 116 | 117 | if (dashboard) { 118 | // destroy the previous view 119 | dashboard.destroy(); 120 | } 121 | // create help area 122 | if ($helpArea) { 123 | // remove if it exists since layout-specific help text will be inserted 124 | // note: we assume this cleans up all descendant event handlers (according to 125 | // the jquery source and various online doc) 126 | $helpArea.remove(); 127 | } 128 | $helpArea = $helpTemplate.clone().prependTo($('#notebook_panel')); 129 | var layoutHelpText = layout.module.helpText; 130 | if (layoutHelpText) { 131 | // insert layout-specific help text 132 | if (layoutHelpText.snippet) { 133 | $helpArea.find('.help-snippet-text').text(layoutHelpText.snippet); 134 | } 135 | var layoutHelpDetails = layoutHelpText.details; 136 | if (layoutHelpDetails) { 137 | var $firstDetail = $helpArea.find('.help-details-list').children().first(); 138 | Object.keys(layoutHelpDetails).forEach(function(key, i) { 139 | $firstDetail.before($('
  • ').append(layoutHelpDetails[key])); 140 | }); 141 | } 142 | } 143 | 144 | // instantiate the dashboard 145 | dashboard = layout.module.create(layout.opts); 146 | dashboard.setInteractive({ 147 | enable: actionState !== 'preview', 148 | complete: function() { 149 | PolymerSupport.notifyResizeAll(); 150 | } 151 | }); 152 | // Metadata.activeView gets set by the layout module 153 | $('body').attr('data-dashboard-layout', Metadata.activeView); 154 | }); 155 | }, 156 | exitDashboardMode: function() { 157 | $('body').removeClass(dashboardClass) 158 | .attr('data-dashboard-layout', ''); 159 | dashboard.destroy(); 160 | dashboard = null; 161 | PolymerSupport.notifyResizeAll(); 162 | $helpArea.remove(); 163 | }, 164 | showAll: function() { 165 | dashboard.showAllCells(); 166 | }, 167 | showAllStacked: function() { 168 | // ok if width is undefined, only grid layout takes an argument 169 | dashboard.showAllCells({ width : dashboard.numCols }); 170 | }, 171 | hideAll: function() { 172 | dashboard.hideAllCells(); 173 | } 174 | }); 175 | dbActions.addMenuItems(); 176 | dbActions.addToolbarItems(); 177 | }); 178 | }); 179 | -------------------------------------------------------------------------------- /jupyter_dashboards/nbextension/notebook/dashboard-view/help.html: -------------------------------------------------------------------------------- 1 | 3 | 37 |
    38 |
    39 | Dashboard authoring: create your dashboard. 40 | more info 41 | 42 |
    43 |
    44 |
      45 |
    • Hide cell: Click to hide a cell from the dashboard view.
    • 46 |
    • Show cell: Click to return a hidden cell to the dashboard view.
    • 47 |
    • Hide/Show all: Select the options under Cell > Dashboard to hide or show all cells.
    • 48 |
    • Edit cell: Click to jump to the Notebook and edit the code.
    • 49 |
    50 |
    51 |
    52 | 68 | -------------------------------------------------------------------------------- /jupyter_dashboards/nbextension/notebook/dashboard-view/layout/grid/cell-controls.html: -------------------------------------------------------------------------------- 1 | 3 |
    4 | 5 | 6 |
    7 |
    8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 |
    ; 34 | -------------------------------------------------------------------------------- /jupyter_dashboards/nbextension/notebook/dashboard-view/layout/grid/layout.css: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) Jupyter Development Team. 3 | * Distributed under the terms of the Modified BSD License. 4 | */ 5 | 6 | /* Gridstack container */ 7 | .jupyter-dashboard .grid-stack#notebook-container { 8 | padding-left: 0; 9 | padding-right: 0; 10 | transition: background-color 0.75s, 11 | box-shadow 0.75s, 12 | height 0.3s; 13 | } 14 | .jupyter-dashboard:not(.view-only) .grid-stack#notebook-container:hover { 15 | background-color: transparent; 16 | box-shadow: none; 17 | } 18 | .grid-stack#notebook-container .grid-stack-placeholder { 19 | transition-duration: 0.25s; 20 | } 21 | .grid-stack#notebook-container .grid-stack-placeholder > .placeholder-content { 22 | border: 2px dashed #5bc0de; 23 | background-color: transparent; 24 | 25 | /* 26 | computed by gridstack-custom: 27 | 28 | left: (margin/2)px; 29 | right: (margin/2)px; 30 | */ 31 | } 32 | 33 | /* Gridstack cells */ 34 | .grid-stack .dashboard-item-background, 35 | .grid-stack .dashboard-item-border { 36 | position: absolute; 37 | background-color: white; 38 | top: 0; 39 | bottom: 0; 40 | z-index: -1; 41 | transition: box-shadow 0.75s; 42 | 43 | /* 44 | computed by gridstack-custom: 45 | 46 | left: (margin/2)px; 47 | right: (margin/2)px; 48 | */ 49 | } 50 | .grid-stack .dashboard-item-border { 51 | background-color: transparent; 52 | color: transparent; 53 | z-index: 10; 54 | pointer-events: none; /* "pass through" mouse events */ 55 | transition: background-color 0.2s, 56 | color 0.2s, 57 | box-shadow 0.75s; 58 | } 59 | .grid-stack .cell:not(.grid-stack-item) .dashboard-item-background, 60 | .grid-stack .cell:not(.grid-stack-item) .dashboard-item-border { 61 | left: 0; 62 | right: 0; 63 | } 64 | .grid-stack:hover .grid-stack-item .dashboard-item-border, 65 | .grid-stack .cell:not(.grid-stack-item) { 66 | box-shadow: 0 1px 5px 1px rgba(87,87,87,0.2); 67 | } 68 | .jupyter-dashboard .grid-stack .ui-draggable-dragging.cell, 69 | .jupyter-dashboard .grid-stack .ui-resizable-resizing.cell { 70 | opacity: 0.75; 71 | } 72 | .grid-stack .cell > :not(.dashboard-item-background):not(.dashboard-item-border):not(.ui-resizable-handle) { 73 | /* 74 | computed by gridstack-custom: 75 | 76 | margin-left: (margin/2)px; 77 | margin-right: (margin/2)px; 78 | */ 79 | } 80 | 81 | /* Dashboard cell controls: drag */ 82 | .jupyter-dashboard .grid-stack .cell .drag-handle:hover { 83 | color: #306c9e; 84 | cursor: move; /* for old IE */ 85 | cursor: -webkit-grab; 86 | cursor: grab; 87 | } 88 | body.dragging, 89 | body.dragging.jupyter-dashboard .grid-stack .ui-draggable-dragging.cell:hover .drag-handle:hover { 90 | cursor: -webkit-grabbing !important; 91 | cursor: grabbing !important; 92 | } 93 | 94 | /* drag/drop cell overlay*/ 95 | .jupyter-dashboard.all_cell_drag:not(.view-only) .grid-stack .grid-stack-item .dashboard-item-border { 96 | display: -webkit-flex; 97 | display: -ms-flexbox; 98 | display: flex; 99 | -webkit-justify-content: center; 100 | -ms-flex-pack: center; 101 | justify-content: center; 102 | -webkit-align-items: center; 103 | -ms-flex-align: center; 104 | align-items: center; 105 | background-color: rgba(255, 255, 255, 0.9); 106 | color: #b2b2b2; 107 | font-size: 50px; 108 | pointer-events: auto; 109 | } 110 | .jupyter-dashboard.all_cell_drag:not(.view-only) .grid-stack .grid-stack-item .dashboard-item-border:hover { 111 | cursor: -webkit-grab; 112 | cursor: grab; 113 | } 114 | .jupyter-dashboard.all_cell_drag:not(.view-only) .grid-stack .grid-stack-item .cell-control-container, 115 | .jupyter-dashboard.all_cell_drag:not(.view-only) .grid-stack .grid-stack-item .ui-resizable-handle { 116 | display: none !important; /* important needed to override inline style set by gridstack */ 117 | } 118 | .jupyter-dashboard:not(.all_cell_drag):not(.view-only) .grid-stack .dashboard-item-border i, 119 | .jupyter-dashboard .grid-stack > .cell:not(.grid-stack-item) .dashboard-item-border i { 120 | display: none; 121 | } 122 | 123 | /* Cell controls: add buttons */ 124 | .jupyter-dashboard .grid-stack .cell .cell-control.add-btn { 125 | display: -webkit-flex; 126 | display: -ms-flexbox; 127 | display: flex; 128 | overflow: hidden; 129 | position: relative; 130 | min-width: 25px; 131 | width: auto; 132 | } 133 | .jupyter-dashboard .grid-stack .cell .cell-control.add-btn > .bar-container { 134 | display: -webkit-flex; 135 | display: -ms-flexbox; 136 | display: flex; 137 | flex-direction: column; 138 | } 139 | .jupyter-dashboard .grid-stack .cell .cell-control.add-btn > .bar-container > .bar { 140 | width: 1em; 141 | height: 3px; 142 | background-color: #b2b2b2; 143 | display: inline-block; 144 | margin-bottom: 2px; 145 | } 146 | .jupyter-dashboard .grid-stack .cell .cell-control.add-btn > .bar-container > .bar.bar-lighter { 147 | background-color: #dadada; 148 | } 149 | .jupyter-dashboard .grid-stack .cell .cell-control.add-btn:hover > .bar-container > .bar { 150 | background-color: #306c9e; 151 | } 152 | .jupyter-dashboard .grid-stack .cell .cell-control.add-btn:hover > .bar-container > .bar.bar-lighter { 153 | background-color: #A6D3F9; 154 | } 155 | .jupyter-dashboard .grid-stack .cell .cell-control.add-btn > .fa-plus { 156 | margin-left: 2px; 157 | margin-top: 4px; 158 | font-size: 0.8em; 159 | } 160 | 161 | /* Hide specific grid controls based on hidden state */ 162 | .jupyter-dashboard .grid-stack .cell.grid-stack-item .cell-control.add-btn-relative, 163 | .jupyter-dashboard .grid-stack .cell.grid-stack-item .cell-control .fa-plus, 164 | .jupyter-dashboard .grid-stack .cell:not(.grid-stack-item) .cell-control.drag-handle, 165 | .jupyter-dashboard .grid-stack .cell:not(.grid-stack-item) .cell-control.hide-btn, 166 | .jupyter-dashboard .grid-stack .cell:not(.grid-stack-item) .gs-resize-handle { 167 | display: none; 168 | } 169 | 170 | /* static view */ 171 | .jupyter-dashboard.view-only .grid-stack-static .cell.ui-state-disabled { 172 | /* override disabled state set by jquery-ui */ 173 | opacity: 1; 174 | -webkit-filter: none; 175 | filter: none; 176 | } 177 | .jupyter-dashboard.view-only .grid-stack .cell:not(.grid-stack-item), 178 | .jupyter-dashboard.view-only .grid-stack .dashboard-item-background, 179 | .jupyter-dashboard.view-only .grid-stack .dashboard-item-border { 180 | display: none; 181 | } 182 | 183 | /* Hidden cells */ 184 | .grid-stack .cell:not(.grid-stack-item) { 185 | position: absolute; 186 | min-height: 100px; 187 | transition: left 0.3s, top 0.3s, height 0.3s, width 0.3s; 188 | } 189 | .grid-stack .cell.code_cell:not(.grid-stack-item) .input_area { 190 | max-height: 200px; 191 | overflow: scroll; 192 | } 193 | 194 | /* Gridstack Overrides */ 195 | #notebook-container.grid-stack > .grid-stack-item > .ui-resizable-se, 196 | #notebook-container.grid-stack > .grid-stack-item > .ui-resizable-sw { 197 | width: 8px; 198 | height: 8px; 199 | bottom: 5px; 200 | border: 2px solid rgb(178, 178, 178); 201 | border-top: none; 202 | -webkit-transform: none; 203 | transform: none; 204 | } 205 | #notebook-container.grid-stack > .grid-stack-item > .ui-resizable-se { 206 | /* 207 | computed in gridstack-custom: 208 | 209 | right: 5px + (margin/2)px; 210 | */ 211 | border-left: none; 212 | } 213 | #notebook-container.grid-stack > .grid-stack-item > .ui-resizable-sw { 214 | /* 215 | computed in gridstack-custom: 216 | 217 | left: 5px + (margin/2)px; 218 | */ 219 | border-right: none; 220 | } 221 | #notebook-container.grid-stack > .grid-stack-item > .ui-resizable-se::before, 222 | #notebook-container.grid-stack > .grid-stack-item > .ui-resizable-sw::before { 223 | content: ""; /* remove the existing drag icons */ 224 | } 225 | 226 | #notebook-container.grid-stack > .grid-stack-item > .ui-resizable-e, 227 | #notebook-container.grid-stack > .grid-stack-item > .ui-resizable-w { 228 | top: 25px; 229 | bottom: 25px; 230 | height: auto; 231 | } 232 | #notebook-container.grid-stack > .grid-stack-item > .ui-resizable-e { 233 | right: 0; 234 | } 235 | #notebook-container.grid-stack > .grid-stack-item > .ui-resizable-w { 236 | left: 0; 237 | } 238 | #notebook-container.grid-stack > .grid-stack-item > .ui-resizable-s { 239 | width: auto; 240 | } 241 | -------------------------------------------------------------------------------- /jupyter_dashboards/nbextension/notebook/dashboard-view/layout/report/cell-controls.html: -------------------------------------------------------------------------------- 1 | 3 |
    4 | 5 |
    6 |
    7 | 8 | 9 |
    10 |
    11 | 12 |
    13 | -------------------------------------------------------------------------------- /jupyter_dashboards/nbextension/notebook/dashboard-view/layout/report/collapse-button.html: -------------------------------------------------------------------------------- 1 | 3 |
    4 | collapse 5 | expand 6 | 0 7 | hidden cells 8 |
    9 | -------------------------------------------------------------------------------- /jupyter_dashboards/nbextension/notebook/dashboard-view/layout/report/layout.css: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) Jupyter Development Team. 3 | * Distributed under the terms of the Modified BSD License. 4 | */ 5 | 6 | /* Dashboard container */ 7 | .jupyter-dashboard[data-dashboard-layout="report"] #notebook-container { 8 | padding-left: 0; 9 | padding-right: 0; 10 | transition: background-color 0.75s, 11 | box-shadow 0.75s; 12 | } 13 | .jupyter-dashboard[data-dashboard-layout="report"]:not(.view-only) #notebook-container:hover { 14 | background-color: transparent; 15 | box-shadow: none; 16 | } 17 | 18 | /* Dashboard cell */ 19 | .jupyter-dashboard[data-dashboard-layout="report"] .cell { 20 | background-color: white; 21 | margin-bottom: 1em; 22 | } 23 | .jupyter-dashboard[data-dashboard-layout="report"]:not(.view-only) .cell { 24 | min-height: 5em; 25 | } 26 | .jupyter-dashboard[data-dashboard-layout="report"] .cell.dashboard-hidden { 27 | height: 5em; 28 | overflow: hidden; 29 | } 30 | 31 | /* Hidden cells */ 32 | .jupyter-dashboard[data-dashboard-layout="report"] .dashboard-report-collapse-btn { 33 | background-color: #f8f8f8; 34 | color: #b2b2b2; 35 | cursor: pointer; 36 | font-variant: small-caps; 37 | height: 2em; 38 | line-height: 1.8em; 39 | margin-bottom: 1em; 40 | text-align: center; 41 | } 42 | .jupyter-dashboard[data-dashboard-layout="report"] .dashboard-report-collapse-btn:hover { 43 | background-color: #f6f6f6; 44 | } 45 | .jupyter-dashboard[data-dashboard-layout="report"] .dashboard-report-collapse-btn .dashboard-report-hidden-count { 46 | font-size: smaller; 47 | } 48 | .jupyter-dashboard[data-dashboard-layout="report"] .cell.dashboard-hidden { 49 | border-top: 1px solid #eee; 50 | } 51 | .jupyter-dashboard[data-dashboard-layout="report"] .dashboard-report-collapse-btn:not(.dashboard-collapsed) .dashboard-report-expand-label, 52 | .jupyter-dashboard[data-dashboard-layout="report"] .dashboard-report-collapse-btn.dashboard-collapsed .dashboard-report-collapse-label, 53 | .jupyter-dashboard[data-dashboard-layout="report"] .dashboard-report-collapse-btn .dashboard-report-collapse-text[data-cell-count="1"] .plural-s, 54 | .jupyter-dashboard[data-dashboard-layout="report"].view-only .dashboard-report-collapse-btn, 55 | .jupyter-dashboard[data-dashboard-layout="report"].view-only .cell.dashboard-hidden { 56 | display: none; 57 | } 58 | .jupyter-dashboard[data-dashboard-layout="report"] .cell.dashboard-collapsed { 59 | display: none; 60 | } 61 | .jupyter-dashboard[data-dashboard-layout="report"] .dashboard-report-collapse-btn:not(.dashboard-collapsed), 62 | .jupyter-dashboard[data-dashboard-layout="report"] .cell.dashboard-hidden { 63 | margin-bottom: 0; 64 | } 65 | .jupyter-dashboard[data-dashboard-layout="report"] .cell.dashboard-hidden, 66 | .jupyter-dashboard[data-dashboard-layout="report"] .cell.dashboard-hidden .cell-control-container { 67 | background-color: #f8f8f8; 68 | } 69 | .jupyter-dashboard[data-dashboard-layout="report"] .cell.dashboard-hidden:not(.dashboard-collapsed) + .cell:not(.dashboard-hidden) { 70 | margin-top: 1em; 71 | } 72 | .jupyter-dashboard[data-dashboard-layout="report"] .cell .cell-control-se { 73 | border: none; 74 | padding-right: 1em; 75 | visibility: visible; 76 | } 77 | 78 | /* Hide specific cell controls based on hidden state */ 79 | .jupyter-dashboard[data-dashboard-layout="report"] .cell:not(.dashboard-hidden) .cell-control.add-btn, 80 | .jupyter-dashboard[data-dashboard-layout="report"] .cell.dashboard-hidden .cell-control.hide-btn, 81 | .jupyter-dashboard[data-dashboard-layout="report"] .cell:not(.dashboard-hidden) .cell-control-se { 82 | display: none; 83 | } 84 | -------------------------------------------------------------------------------- /jupyter_dashboards/nbextension/notebook/dashboard-view/layout/report/layout.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) Jupyter Development Team. 3 | * Distributed under the terms of the Modified BSD License. 4 | */ 5 | define([ 6 | 'jquery', 7 | '../../../link-css', 8 | '../../dashboard-metadata', 9 | '../../notebook-util', 10 | 'template!./cell-controls.html', 11 | 'template!./collapse-button.html' 12 | ], function( 13 | $, 14 | linkCSS, 15 | Metadata, 16 | nbUtil, 17 | $cellControlsTemplate, 18 | $collapseButtonTemplate 19 | ) { 20 | 'use strict'; 21 | 22 | var cssLoaded = false; 23 | 24 | function ReportLayout(opts) { 25 | this.opts = opts; 26 | this.$container = opts.$container; 27 | 28 | if (!cssLoaded) { 29 | cssLoaded = linkCSS('./dashboard-view/layout/report/layout.css'); 30 | } 31 | 32 | Metadata.activeView = Metadata.DASHBOARD_VIEW.REPORT; 33 | 34 | $.when(cssLoaded).then(function() { 35 | // setup cells for report layout 36 | var self = this; 37 | this.$container.find('.cell') 38 | .css('min-height', '0px') // we detect empty cells by height 39 | .each(function() { 40 | var $cell = $(this); 41 | 42 | // mark new & empty cells hidden 43 | if (!Metadata.hasCellBeenRendered($cell)) { 44 | // mark the cell as rendered by hiding or showing 45 | if ($cell.height() === 0) { 46 | Metadata.hideCell($cell); 47 | } else { 48 | Metadata.showCell($cell); 49 | } 50 | } 51 | 52 | // set hidden state in UI 53 | $cell.toggleClass('dashboard-hidden dashboard-collapsed', 54 | !Metadata.isCellVisible($cell)); 55 | 56 | // add controls for hide, add, edit 57 | self._addCellControls($cell); 58 | 59 | self._updateCollapseBtns(); 60 | }) 61 | .css('min-height',''); 62 | }.bind(this)); 63 | } 64 | 65 | ReportLayout.prototype._addCellControls = function($cell) { 66 | var self = this; 67 | if ($cell.find('.cell-control-nw').length === 0) { 68 | var gc = $cellControlsTemplate.clone().appendTo($cell); 69 | gc.find('.add-btn').click(function() { 70 | self._setCellVisibility(nbUtil.getParentCell(this), true); 71 | }); 72 | gc.find('.edit-btn').click(function() { 73 | var $cell = nbUtil.getParentCell(this); 74 | self.opts.exit(); 75 | nbUtil.editCell($cell); 76 | }); 77 | gc.find('.hide-btn').click(function() { 78 | self._setCellVisibility(nbUtil.getParentCell(this), false); 79 | }); 80 | } 81 | }; 82 | 83 | ReportLayout.prototype._setCellVisibility = function($cell, visibility) { 84 | $cell.toggleClass('dashboard-hidden', !visibility); 85 | if (visibility) { 86 | Metadata.showCell($cell); 87 | } else { 88 | Metadata.hideCell($cell); 89 | } 90 | this._updateCollapseBtns(); 91 | }; 92 | 93 | ReportLayout.prototype._updateCollapseBtns = function() { 94 | // insert collapse button between adjacent visible and hidden cells 95 | this.$container.find('.cell:not(.dashboard-hidden) + .cell.dashboard-hidden, .cell.dashboard-hidden:first-child') 96 | .each(function() { 97 | var $collapseBtn = $collapseButtonTemplate.clone() 98 | .filter('.dashboard-report-collapse-btn') 99 | .click(function() { 100 | var $btn = $(this); 101 | $btn.toggleClass('dashboard-collapsed'); 102 | $btn.nextUntil('.dashboard-report-collapse-btn', '.cell.dashboard-hidden') 103 | .toggleClass('dashboard-collapsed', $btn.is('.dashboard-collapsed')); 104 | }); 105 | $(this).before($collapseBtn); 106 | 107 | // Set to collapsed if either of the next two cells is collapsed 108 | // This helps merge collapse groups 109 | $collapseBtn.toggleClass('dashboard-collapsed', 110 | $collapseBtn.next().is('.dashboard-collapsed') || 111 | $collapseBtn.next().next().is('.dashboard-collapsed')); 112 | }); 113 | 114 | // remove out of place collapse buttons 115 | this.$container.find('.dashboard-report-collapse-btn + .cell:not(.dashboard-hidden)') 116 | .prev().remove(); 117 | this.$container.find('.cell.dashboard-hidden + .dashboard-report-collapse-btn') 118 | .remove(); 119 | 120 | // update collapse button groups 121 | this.$container.find('.dashboard-report-collapse-btn').each(function() { 122 | var $btn = $(this); 123 | var $collapseGroup = $btn.nextUntil('.dashboard-report-collapse-btn', 124 | '.cell.dashboard-hidden'); 125 | // update text of collapse buttons 126 | $btn.find('.dashboard-report-hidden-count').text($collapseGroup.length); 127 | $btn.find('.dashboard-report-collapse-text').attr('data-cell-count', 128 | $collapseGroup.length); 129 | // update hidden cell collapsed state 130 | $collapseGroup.toggleClass('dashboard-collapsed', 131 | $btn.is('.dashboard-collapsed')); 132 | }); 133 | }; 134 | 135 | /* PUBLIC API */ 136 | 137 | ReportLayout.prototype.destroy = function() { 138 | this.$container.find('.cell').removeClass('dashboard-hidden dashboard-collapsed'); 139 | this.$container.find('.cell-control-container').remove(); 140 | this.$container.find('.dashboard-report-collapse-btn').remove(); 141 | }; 142 | ReportLayout.prototype.hideAllCells = function() { 143 | this.$container.find('.cell').addClass('dashboard-hidden').each(function() { 144 | Metadata.hideCell($(this)); 145 | }); 146 | this._updateCollapseBtns(); 147 | }; 148 | ReportLayout.prototype.setInteractive = function() { 149 | // no-op since report interactivity can be done using CSS 150 | }; 151 | ReportLayout.prototype.showAllCells = function() { 152 | this.$container.find('.cell').removeClass('dashboard-hidden').each(function() { 153 | Metadata.showCell($(this)); 154 | }); 155 | this._updateCollapseBtns(); 156 | }; 157 | 158 | return { 159 | /** 160 | * @return {Object} helpText - text for dashboard help area 161 | * @return {String} helpText.snippet - summary text for report layout 162 | */ 163 | get helpText() { 164 | return { 165 | snippet: 'Report Layout: Show/hide cells in notebook order to create your dashboard.' 166 | }; 167 | }, 168 | /** 169 | * Instantiate the report layout. 170 | * @param {Object} opts - layout options 171 | * @param {jQuery} opts.$container - notebook container 172 | * @param {Function} opts.exit callback which is invoked when the Dashboard 173 | * initiates exiting from Dashboard Mode (for 174 | * example, if user clicks on cell edit button to 175 | * go back to Notebook view) 176 | * @return {ReportLayout} instance of ReportLayout 177 | */ 178 | create: function(opts) { 179 | return new ReportLayout(opts); 180 | } 181 | }; 182 | }); 183 | -------------------------------------------------------------------------------- /jupyter_dashboards/nbextension/notebook/dashboard-view/notebook-util.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) Jupyter Development Team. 3 | * Distributed under the terms of the Modified BSD License. 4 | */ 5 | define([ 6 | 'jquery', 7 | 'base/js/namespace' 8 | ], function( 9 | $, 10 | IPython 11 | ) { 12 | 'use strict'; 13 | 14 | return { 15 | /** 16 | * @param {(DOM Element|jQuery)} el - child element of a cell 17 | * @return {jQuery} cell containing el 18 | */ 19 | getParentCell: function(el) { 20 | return $(el).parents('.cell').first(); 21 | }, 22 | /** 23 | * Selects the specified cell and puts it into edit mode 24 | * @param {(DOM Element|jQuery)} cell - cell to edit 25 | */ 26 | editCell: function(cell) { 27 | var $cell = $(cell); 28 | var nbCell = $cell.data('cell'); 29 | var nbIndex = IPython.notebook.find_cell_index(nbCell); 30 | IPython.notebook.select(nbIndex).edit_mode(nbCell); 31 | 32 | $cell.get(0).scrollIntoView({ behavior: 'smooth' }); 33 | $cell.one('animationend', function() { 34 | // highlight animation cleanup 35 | $cell.removeClass('edit-select'); 36 | }); 37 | // commence highlight animation 38 | $cell.addClass('edit-select'); 39 | } 40 | }; 41 | }); 42 | -------------------------------------------------------------------------------- /jupyter_dashboards/nbextension/notebook/dashboard-view/object-util.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) Jupyter Development Team. 3 | * Distributed under the terms of the Modified BSD License. 4 | */ 5 | define([], function() { 6 | 'use strict'; 7 | 8 | return { 9 | /** 10 | * @param {Object} obj - Object to test 11 | * @param {string} prop - Name of property to test. 12 | * May be a '.'-delimited string to check nested objects 13 | * @return {boolean} true if specified object has specified property 14 | */ 15 | has: function(obj, prop) { 16 | var currentLevel = obj; 17 | return prop.split('.').every(function(prop) { 18 | var has = currentLevel.hasOwnProperty(prop); 19 | currentLevel = currentLevel[prop]; 20 | return has; 21 | }); 22 | }, 23 | /** 24 | * Ensures a property is present in an object. 25 | * Sets the property to an empty object if not set. 26 | * @param {Object} obj - Object to test 27 | * @param {string} prop - Name of property to test. 28 | * May be a '.'-delimited string to ensure nested objects 29 | */ 30 | ensure: function(obj, prop) { 31 | var currentLevel = obj; 32 | prop.split('.').forEach(function(p) { 33 | if (!currentLevel.hasOwnProperty(p)) { 34 | currentLevel[p] = {}; 35 | } 36 | currentLevel = currentLevel[p]; 37 | }); 38 | } 39 | }; 40 | }); 41 | -------------------------------------------------------------------------------- /jupyter_dashboards/nbextension/notebook/dashboard-view/polymer-support.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) Jupyter Development Team. 3 | * Distributed under the terms of the Modified BSD License. 4 | */ 5 | 6 | /** 7 | * This module adds support for Polymer elements when used within the Dashboard view. 8 | * 9 | * Polymer Element Resizing 10 | * ------------------------ 11 | * To make a Polymer element get notified if its parent/ancestor cell is resized, add the 12 | * [iron-resizable-behavior](https://elements.polymer-project.org/elements/iron-resizable-behavior) 13 | * to that element. The Dashboard will notify the element when a cell has resized -- simply listen 14 | * for the `iron-resize` event. 15 | */ 16 | define([ 17 | 'jquery', 18 | 'base/js/namespace', 19 | ], function( 20 | $, 21 | IPython 22 | ) { 23 | 'use strict'; 24 | 25 | var resizableElements = $(); 26 | 27 | // Listen for Polymer elements that include the `iron-resizable-behavior`. Store for later use. 28 | function registerPolymerResizeRequest(cell) { 29 | $(cell.element).on('iron-request-resize-notifications', function(event) { 30 | console.log('Polymer element requesting resize notifications'); 31 | 32 | var target = event.path ? event.path[0] : event.target; 33 | resizableElements = resizableElements.add(target); 34 | fireIronResizeEvent(target); 35 | event.stopPropagation(); 36 | }); 37 | } 38 | 39 | function fireIronResizeEvent(node) { 40 | var evt = new Event('iron-resize', { bubbles: false }); 41 | node.dispatchEvent(evt); 42 | } 43 | 44 | function onResize(cellNode) { 45 | resizableElements.filter(function() { 46 | return $(this).parents().is(cellNode); 47 | }) 48 | .each(function() { 49 | fireIronResizeEvent(this); 50 | }); 51 | } 52 | 53 | function notifyResizeAll() { 54 | resizableElements.each(function() { 55 | fireIronResizeEvent(this); 56 | }); 57 | } 58 | 59 | function init() { 60 | // add our listener to newly create cells 61 | IPython.notebook.events.on('create.Cell', function(evt, args) { 62 | registerPolymerResizeRequest(args.cell); 63 | }); 64 | 65 | // remove references to Polymer elements from deleted cells 66 | IPython.notebook.events.on('delete.Cell', function(evt, args) { 67 | // filter out elements which are within given cell 68 | resizableElements = resizableElements.filter(function() { 69 | return !$(this).parents().is(args.cell.element); 70 | }); 71 | }); 72 | 73 | // The Notebook triggers the 'create.Cell' event when loading a notebook, but before our 74 | // extension is loaded. Therefore, add our listener to all existing cells. 75 | IPython.notebook.get_cells().forEach(registerPolymerResizeRequest); 76 | } 77 | 78 | return { 79 | /** 80 | * Registers resize listeners on cells. 81 | */ 82 | init: init, 83 | 84 | /** 85 | * Invoke when a Dashboard cell is resized. 86 | * @param {DOMNode} cellNode - the dashboard cell which was resized 87 | */ 88 | onResize: onResize, 89 | 90 | /** 91 | * Notify all managed Polymer elements that their parent cell may have been resized. 92 | */ 93 | notifyResizeAll: notifyResizeAll 94 | }; 95 | }); 96 | -------------------------------------------------------------------------------- /jupyter_dashboards/nbextension/notebook/dashboard-view/sub-menu.html: -------------------------------------------------------------------------------- 1 | 3 | 4 |
  • 22 | -------------------------------------------------------------------------------- /jupyter_dashboards/nbextension/notebook/dashboard-view/template-loader.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) Jupyter Development Team. 3 | * Distributed under the terms of the Modified BSD License. 4 | */ 5 | /** 6 | * Requirejs plugin to load HTML template files without comment nodes. 7 | * This avoids us polluting the DOM with copyright header comments. 8 | * Returns a jQuery selection containing the template nodes 9 | */ 10 | define(['text'], function (text) { 11 | 'use strict'; 12 | 13 | return { 14 | load: function (name, req, load, config) { 15 | if (config.isBuild) { 16 | load(); 17 | return; 18 | } 19 | req(['jquery', 'text!' + name], function ($, template) { 20 | load($(template).not(function() { 21 | // filter out comment nodes 22 | // (avoids polluting the DOM with copyright header comments) 23 | return this.nodeType === 8; 24 | })); 25 | }); 26 | } 27 | }; 28 | }); 29 | -------------------------------------------------------------------------------- /jupyter_dashboards/nbextension/notebook/dashboard-view/view-menu.html: -------------------------------------------------------------------------------- 1 | 3 | 4 |
  • 7 | Notebook 8 |
  • 9 | 25 |
  • 28 | Dashboard Preview 29 |
  • 30 | -------------------------------------------------------------------------------- /jupyter_dashboards/nbextension/notebook/dashboard-view/view-toolbar-buttons.html: -------------------------------------------------------------------------------- 1 | 3 | 4 |
    5 | Dashboard View: 6 | 7 | 8 | 12 | 13 | 14 | 15 | 17 | 20 | 24 | 34 | 35 | 36 | 37 | 41 |
    42 | -------------------------------------------------------------------------------- /jupyter_dashboards/nbextension/notebook/link-css.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) Jupyter Development Team. 3 | * Distributed under the terms of the Modified BSD License. 4 | */ 5 | 6 | /* global console, require */ 7 | define([ 8 | 'require', 9 | 'jquery' 10 | ], function( 11 | require, 12 | $ 13 | ) { 14 | // load the associated stylesheet 15 | return function(url) { 16 | var link = document.createElement('link'); 17 | link.type = 'text/css'; 18 | link.rel = 'stylesheet'; 19 | link.href = require.toUrl(url); 20 | 21 | // set a callback to let us know when the CSS has loaded 22 | var deferred = $.Deferred(); 23 | $(link).on('load', function() { 24 | deferred.resolve(); 25 | }); 26 | 27 | document.getElementsByTagName('head')[0].appendChild(link); 28 | 29 | return deferred; 30 | }; 31 | }); 32 | -------------------------------------------------------------------------------- /jupyter_dashboards/nbextension/notebook/main.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) Jupyter Development Team. 3 | * Distributed under the terms of the Modified BSD License. 4 | */ 5 | 6 | /* global define */ 7 | define([ 8 | './dashboard-view/dashboard-view', 9 | 'notebook/js/notebook' 10 | ], function( 11 | View, 12 | Notebook 13 | ) { 14 | return { 15 | load_ipython_extension: function() { 16 | console.debug('jupyter_dashboards loaded'); 17 | if (Notebook.Notebook.prototype.copy_cell) { 18 | Notebook.Notebook.prototype.__copy_cell = 19 | Notebook.Notebook.prototype.copy_cell; 20 | Notebook.Notebook.prototype.copy_cell = function() { 21 | this.__copy_cell(); 22 | for (var i = 0; i < this.clipboard.length; i++) { 23 | var cell_json = this.clipboard[i]; 24 | if (cell_json.metadata.extensions !== undefined && 25 | cell_json.metadata.extensions.jupyter_dashboards !== undefined && 26 | cell_json.metadata.extensions.jupyter_dashboards.views !== undefined) { 27 | 28 | // Clear out data for each view. 29 | // Other dashboard metadata may need to be preserved. 30 | var views = cell_json.metadata.extensions.jupyter_dashboards.views; 31 | var viewIds = Object.keys(views); 32 | for (var j = 0; j < viewIds.length; j++) { 33 | views[viewIds[j]] = { hidden: true }; 34 | } 35 | } 36 | } 37 | }; 38 | } 39 | } 40 | }; 41 | }); 42 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "jupyter-dashboards", 3 | "description": "Frontend dependencies for the Jupyter Notebook dashboards extension", 4 | "dependencies": {}, 5 | "devDependencies": { 6 | "bower": "^1.4.1", 7 | "mocha" :"^2.0.0", 8 | "wd": "latest", 9 | "chai": "latest", 10 | "chai-as-promised": "latest", 11 | "colors": "latest", 12 | "minimist": "latest" 13 | }, 14 | "scripts": { 15 | "bower": "bower --allow-root install", 16 | "system-test": "node_modules/mocha/bin/mocha system-test/**/*-test.js --timeout 300000 --reporter spec" 17 | }, 18 | "repository": { 19 | "type": "git", 20 | "url": "https://github.com/jupyter/dashboards.git" 21 | }, 22 | "keywords": [ 23 | "ipython", 24 | "jupyter", 25 | "dashboards" 26 | ], 27 | "author": "Jupyter Community" 28 | } 29 | -------------------------------------------------------------------------------- /postcss-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "autoprefixer": { 3 | "browsers": "last 2 versions" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /readthedocs.yml: -------------------------------------------------------------------------------- 1 | conda: 2 | file: docs/environment.yml 3 | python: 4 | version: 3 5 | -------------------------------------------------------------------------------- /requirements-demo.txt: -------------------------------------------------------------------------------- 1 | bokeh==0.12.4 2 | jupyter_declarativewidgets 3 | ipywidgets 4 | matplotlib 5 | pandas 6 | seaborn 7 | widgetsnbextension 8 | -------------------------------------------------------------------------------- /requirements-doc.txt: -------------------------------------------------------------------------------- 1 | sphinx_rtd_theme 2 | sphinx 3 | recommonmark 4 | -------------------------------------------------------------------------------- /requirements-test.txt: -------------------------------------------------------------------------------- 1 | nodejs 2 | nose 3 | notebook 4 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | notebook>=4.0 2 | -------------------------------------------------------------------------------- /scripts/jupyter-dashboards: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Copyright (c) Jupyter Development Team. 3 | # Distributed under the terms of the Modified BSD License. 4 | import jupyter_dashboards.extensionapp 5 | 6 | if __name__ == '__main__': 7 | jupyter_dashboards.extensionapp.main() 8 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Jupyter Development Team. 2 | # Distributed under the terms of the Modified BSD License. 3 | 4 | import os 5 | import sys 6 | from setuptools import setup 7 | 8 | # Get location of this file at runtime 9 | HERE = os.path.abspath(os.path.dirname(__file__)) 10 | 11 | # Eval the version tuple and string from the source 12 | VERSION_NS = {} 13 | with open(os.path.join(HERE, 'jupyter_dashboards/_version.py')) as f: 14 | exec(f.read(), {}, VERSION_NS) 15 | 16 | setup_args = dict( 17 | name='jupyter_dashboards', 18 | author='Jupyter Development Team', 19 | author_email='jupyter@googlegroups.com', 20 | description='Extension for Jupyter Notebook for laying out, viewing, and deploying notebooks as dynamic dashboards', 21 | long_description = ''' 22 | This package adds the following features to Jupyter Notebook: 23 | 24 | * Dashboard layout mode for arranging notebook cell outputs in a grid-like fashion 25 | * Dashboard view mode for interacting with an assembled dashboard within the Jupyter Notebook 26 | * Ability to share notebooks with dashboard layout metadata in them with other Jupyter Notebook users 27 | 28 | See `the project README `_ 29 | for more information. 30 | ''', 31 | url='https://github.com/jupyter/dashboards', 32 | version=VERSION_NS['__version__'], 33 | license='BSD', 34 | platforms=['Jupyter Notebook 4.x', 'Jupyter Notebook 5.x'], 35 | packages=[ 36 | 'jupyter_dashboards' 37 | ], 38 | include_package_data=True, 39 | install_requires=[ 40 | 'notebook>=4.0', 41 | ], 42 | scripts=[ 43 | 'scripts/jupyter-dashboards' 44 | ], 45 | classifiers=[ 46 | 'Intended Audience :: Developers', 47 | 'Intended Audience :: System Administrators', 48 | 'Intended Audience :: Science/Research', 49 | 'License :: OSI Approved :: BSD License', 50 | 'Programming Language :: Python', 51 | 'Programming Language :: Python :: 2.7', 52 | 'Programming Language :: Python :: 3.3', 53 | 'Programming Language :: Python :: 3.4', 54 | 'Programming Language :: Python :: 3.5' 55 | ] 56 | ) 57 | 58 | if 'setuptools' in sys.modules: 59 | # setupstools turns entrypoint scripts into executables on windows 60 | setup_args['entry_points'] = { 61 | 'console_scripts': [ 62 | 'jupyter-dashboards = jupyter_dashboards.extensionapp:main' 63 | ] 64 | } 65 | # Don't bother installing the .py scripts if if we're using entrypoints 66 | setup_args.pop('scripts', None) 67 | 68 | if __name__ == '__main__': 69 | setup(**setup_args) 70 | -------------------------------------------------------------------------------- /system-test/bin/run-system-test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright (c) Jupyter Development Team. 3 | # Distributed under the terms of the Modified BSD License. 4 | 5 | TEST_SERVER=${TEST_SERVER:-127.0.0.1:4444} 6 | TEST_TYPE=${TEST_TYPE:-local} 7 | 8 | kill $(cat /tmp/selenium.pid) 9 | kill $(cat /tmp/notebook.pid) 10 | 11 | # Start selenium if local 12 | if [[ "$TEST_TYPE" == "local" ]]; then 13 | set -e 14 | which chromedriver || (echo "chromedriver not found"; exit 1) 15 | which selenium-server || (echo "selenium-server not found"; exit 1) 16 | set +e 17 | selenium-server -port 4444 & 18 | echo $! > /tmp/selenium.pid 19 | fi 20 | 21 | # Start the notebook server 22 | source activate dashboards 23 | jupyter notebook --ip 127.0.0.1 \ 24 | --port 8888 \ 25 | --notebook-dir=./etc/notebooks \ 26 | --no-browser \ 27 | --NotebookApp.token='' & 28 | echo $! > /tmp/notebook.pid 29 | 30 | # Run the tests 31 | npm run system-test -- \ 32 | --baseurl "http://127.0.0.1:8888" \ 33 | --server "$TEST_SERVER" \ 34 | --test-type "$TEST_TYPE" 35 | 36 | kill $(cat /tmp/selenium.pid) 37 | kill $(cat /tmp/notebook.pid) 38 | -------------------------------------------------------------------------------- /system-test/dashboard-buttons-test.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) Jupyter Development Team. 2 | // Distributed under the terms of the Modified BSD License. 3 | 4 | var Boilerplate = require('./utils/boilerplate'); 5 | var boilerplate = new Boilerplate(); 6 | /** 7 | * Tests clicking through the dashboard buttons in the notebook toolbar. 8 | */ 9 | describe('Dashboard View Buttons', function() { 10 | boilerplate.setup(this.title, '/notebooks/test/system-test/Basic.ipynb'); 11 | var dashboard = boilerplate.dashboard; 12 | 13 | it('clicking layout view should switch to layout view', function(done) { 14 | dashboard.clickLayoutViewButton(); 15 | dashboard.assertInLayoutView(); 16 | dashboard.done(done); 17 | }); 18 | 19 | it('clicking notebook view should switch to notebook view', function(done) { 20 | dashboard.clickNotebookViewButton(); 21 | dashboard.assertInNotebookView(); 22 | dashboard.done(done); 23 | }); 24 | 25 | it('clicking dashboard view should switch to dashboard view', function(done) { 26 | dashboard.clickDashboardViewButton(); 27 | dashboard.assertInDashboardView(); 28 | dashboard.done(done); 29 | }); 30 | }); 31 | -------------------------------------------------------------------------------- /system-test/dashboard-menu-test.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) Jupyter Development Team. 2 | // Distributed under the terms of the Modified BSD License. 3 | 4 | var Boilerplate = require('./utils/boilerplate'); 5 | var boilerplate = new Boilerplate(); 6 | /** 7 | * Tests clicking through the dashboard buttons in the View menu. 8 | */ 9 | describe('Dashboard View Menu Buttons', function() { 10 | boilerplate.setup(this.title, '/notebooks/test/system-test/Basic.ipynb'); 11 | var dashboard = boilerplate.dashboard; 12 | it('clicking "Layout Dashboard" should switch to layout view', function(done) { 13 | dashboard.clickLayoutViewMenuButton(); 14 | dashboard.assertInLayoutView(); 15 | dashboard.done(done); 16 | }); 17 | 18 | it('clicking "Notebook" should switch to notebook view', function(done) { 19 | dashboard.clickNotebookViewMenuButton(); 20 | dashboard.assertInNotebookView(); 21 | dashboard.done(done); 22 | }); 23 | 24 | it('clicking "View Dashboard" should switch to dashboard view', function(done) { 25 | dashboard.clickDashboardViewMenuButton(); 26 | dashboard.assertInDashboardView(); 27 | dashboard.done(done); 28 | }); 29 | }); 30 | -------------------------------------------------------------------------------- /system-test/utils/boilerplate.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) Jupyter Development Team. 2 | // Distributed under the terms of the Modified BSD License. 3 | 4 | var wd = require('wd'); 5 | require('colors'); 6 | var chai = require('chai'); 7 | var chaiAsPromised = require('chai-as-promised'); 8 | var parseArgs = require('minimist'); 9 | var Dashboard = require('./dashboard'); 10 | 11 | // Parse the args 12 | var args = parseArgs(process.argv); 13 | args.local = args['test-type'] === 'local'; 14 | args.remote = !args.local; 15 | 16 | // Setup chai 17 | chai.use(chaiAsPromised); 18 | chai.should(); 19 | chaiAsPromised.transferPromiseness = wd.transferPromiseness; 20 | 21 | // Configure webdriver 22 | wd.configureHttp({ 23 | timeout: 60000, 24 | retryDelay: 15000, 25 | retries: 5, 26 | baseUrl: args.baseurl 27 | }); 28 | 29 | // The browser capabilities we would like setup by selenium 30 | var desired = {browserName: 'chrome', platform: 'OS X 10.10'}; 31 | desired.platform = args.platform || desired.platform; 32 | desired.browserName = args.browser || desired.browserName; 33 | desired.tags = ['dashboard', 'system-test', desired.browserName]; 34 | // If there is a build number, include it in the desired attributes for sauce labs 35 | if(process.env.TRAVIS_JOB_NUMBER) { 36 | desired.tunnelIdentifier = process.env.TRAVIS_JOB_NUMBER; 37 | desired.build = 'dashboards-build-' + process.env.TRAVIS_JOB_NUMBER; 38 | } 39 | 40 | // The selenium test server, local or remote, we will be using to test against 41 | var testServer = 'http://' + args.server + '/wd/hub'; 42 | if(args.remote) { 43 | testServer = 'http://' + process.env.SAUCE_USERNAME + ':' + process.env.SAUCE_ACCESS_KEY + '@' + args.server + '/wd/hub'; 44 | } 45 | 46 | console.log('Travis job number is: ', process.env.TRAVIS_JOB_NUMBER); 47 | console.log('Sauce user name is not defined? ', !!process.env.SAUCE_USERNAME); 48 | console.log('Sauce access key is defined? ', !!process.env.SAUCE_ACCESS_KEY); 49 | 50 | /** 51 | * A helper class to setup webdriver, create a browser, and dashboard objects for 52 | * use within the system tests. 53 | */ 54 | var Boilerplate = function(){ 55 | this.browser = wd.promiseChainRemote(testServer); 56 | this.dashboard = new Dashboard(wd, this.browser); 57 | this.allPassed = true; 58 | }; 59 | 60 | /** 61 | * Setups the before and after calls for each of your tests. The boilerplate 62 | * will start each test on startingURL, which is a relative path to the resource to load. 63 | */ 64 | Boilerplate.prototype.setup = function(testName, startingURL){ 65 | var that = this; 66 | startingURL = startingURL ? startingURL : '/'; 67 | desired.name = testName ? 'Urth Dashboard System Test - ' + testName 68 | : 'Urth Dashboard System Test'; 69 | 70 | before(function(done){ 71 | this.browser.init(desired).nodeify(done); 72 | }.bind(this)); 73 | 74 | beforeEach(function(done){ 75 | this.browser.get(startingURL).nodeify(done); 76 | }.bind(this)); 77 | 78 | after(function(done){ 79 | var result = this.browser.quit(); 80 | if(args.remote) { 81 | result = result.sauceJobStatus(this.allPassed); 82 | } 83 | result.nodeify(done); 84 | }.bind(this)); 85 | 86 | afterEach(function(done) { 87 | that.allPassed = that.allPassed && (this.currentTest.state === 'passed'); 88 | done(); 89 | }); 90 | }; 91 | 92 | module.exports = Boilerplate; 93 | -------------------------------------------------------------------------------- /system-test/utils/dashboard.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) Jupyter Development Team. 2 | // Distributed under the terms of the Modified BSD License. 3 | 4 | /** 5 | * Encapsulates the features of the dashboard UI. 6 | * TODO: As more features are added, this file will grow. Need to refactor 7 | * functionality into submodules to keep this file maintainable. 8 | */ 9 | var Dashboard = function(wd, browser) { 10 | this.browser = browser; 11 | this.wd = wd; 12 | this.lastCommand = browser; 13 | }; 14 | 15 | // Represents different UI elements in the notebook/dashboard UI 16 | var DashboardElements = { 17 | "notebookViewButton": "#jupyter-dashboard-view-toolbar-buttons > button:nth-of-type(1)", 18 | "layoutViewButton": "#jupyter-dashboard-view-toolbar-buttons > .dashboard-authoring-btn-container > button:nth-of-type(1)", 19 | "dashboardViewButton": "#jupyter-dashboard-view-toolbar-buttons > button:nth-of-type(2)", 20 | "layoutViewHelpArea" : "#notebook_panel > .help-area", 21 | "jupyterHeaderContainer": "#header-container", 22 | "viewMenuButton" : "ul.nav > li:nth-child(3)", 23 | "notebookViewMenuButton" : "#jupyter-dashboard-notebook-view", 24 | "layoutViewMenuButton" : "#jupyter-dashboard-layout-menu", 25 | "layoutViewGridMenuButton" : "#jupyter-dashboard-auth-grid", 26 | "dashboardViewMenuButton" : "#jupyter-dashboard-view" 27 | }; 28 | // Represents expressions run in the browser for verification 29 | var DashboardExpressions = { 30 | "noJupyterHeader": "document.querySelectorAll('#notebook_panel > .help-area').length === 0" 31 | }; 32 | // Genereic error logging function for callbacks below 33 | var logError = function(msg,err) { 34 | if(err) { 35 | console.error(err, msg); 36 | } 37 | }; 38 | // Timeout to check for elements 39 | var timeout = 20000; 40 | 41 | /** 42 | * Performs a click on the Notebook View Button in the notebook toolbar. 43 | * Assumes the current page is in notebook view. 44 | */ 45 | Dashboard.prototype.clickNotebookViewButton = function(){ 46 | this.lastCommand = this.lastCommand 47 | .waitForElementByCssSelector( 48 | DashboardElements.notebookViewButton, this.wd.asserters.isDisplayed, timeout, 49 | logError.bind(undefined,'Could not find Notebook View Button')) 50 | .elementByCssSelector(DashboardElements.notebookViewButton) 51 | .click(); 52 | return this; 53 | }; 54 | /** 55 | * Performs a click on the Notebook View Button in the notebook toolbar. 56 | * Assumes the current page is in notebook view. 57 | */ 58 | Dashboard.prototype.clickLayoutViewButton = function(){ 59 | this.lastCommand = this.lastCommand 60 | .waitForElementByCssSelector( 61 | DashboardElements.layoutViewButton,this.wd.asserters.isDisplayed, timeout, 62 | logError.bind(undefined,'Could not find Layout View Button')) 63 | .elementByCssSelector(DashboardElements.layoutViewButton) 64 | .click(); 65 | return this; 66 | }; 67 | /** 68 | * Performs a click on the Notebook View Button in the notebook toolbar. 69 | * Assumes the current page is in notebook view. 70 | */ 71 | Dashboard.prototype.clickDashboardViewButton = function(){ 72 | this.lastCommand = this.lastCommand 73 | .waitForElementByCssSelector( 74 | DashboardElements.dashboardViewButton, this.wd.asserters.isDisplayed, timeout, 75 | logError.bind(undefined,'Could not find Dashboard View Button')) 76 | .elementByCssSelector(DashboardElements.dashboardViewButton) 77 | .click(); 78 | return this; 79 | }; 80 | /** 81 | * Performs a click on the Notebook View Button in the notebook toolbar. 82 | * Assumes the current page is in notebook view. 83 | */ 84 | Dashboard.prototype.clickNotebookViewMenuButton = function(){ 85 | this.lastCommand = this.lastCommand 86 | .waitForElementByCssSelector( 87 | DashboardElements.viewMenuButton, this.wd.asserters.isDisplayed, timeout, 88 | logError.bind(undefined,'Could not find "View" menu button')) 89 | .elementByCssSelector(DashboardElements.viewMenuButton) 90 | .click() 91 | .waitForElementByCssSelector( 92 | DashboardElements.notebookViewMenuButton, this.wd.asserters.isDisplayed, timeout, 93 | logError.bind(undefined,'Could not find notebook view menu button')) 94 | .elementByCssSelector(DashboardElements.notebookViewMenuButton) 95 | .click(); 96 | return this; 97 | }; 98 | /** 99 | * Performs a click on the Notebook View Button in the notebook toolbar. 100 | * Assumes the current page is in notebook view. 101 | */ 102 | Dashboard.prototype.clickLayoutViewMenuButton = function(){ 103 | this.lastCommand = this.lastCommand 104 | .waitForElementByCssSelector( 105 | DashboardElements.viewMenuButton, this.wd.asserters.isDisplayed, timeout, 106 | logError.bind(undefined,'Could not find "View" menu button')) 107 | .elementByCssSelector(DashboardElements.viewMenuButton) 108 | .click() 109 | .waitForElementByCssSelector( 110 | DashboardElements.layoutViewMenuButton,this.wd.asserters.isDisplayed, timeout, 111 | logError.bind(undefined,'Could not find layout view menu button')) 112 | .elementByCssSelector(DashboardElements.layoutViewMenuButton) 113 | .moveTo() 114 | .waitForElementByCssSelector( 115 | DashboardElements.layoutViewGridMenuButton,this.wd.asserters.isDisplayed, timeout, 116 | logError.bind(undefined,'Could not find layout view grid menu button')) 117 | .elementByCssSelector(DashboardElements.layoutViewGridMenuButton) 118 | .click(); 119 | return this; 120 | }; 121 | /** 122 | * Performs a click on the Notebook View Button in the notebook toolbar. 123 | * Assumes the current page is in notebook view. 124 | */ 125 | Dashboard.prototype.clickDashboardViewMenuButton = function(){ 126 | this.lastCommand = this.lastCommand 127 | .waitForElementByCssSelector( 128 | DashboardElements.viewMenuButton, this.wd.asserters.isDisplayed, timeout, 129 | logError.bind(undefined,'Could not find "View" menu button')) 130 | .elementByCssSelector(DashboardElements.viewMenuButton) 131 | .click() 132 | .waitForElementByCssSelector( 133 | DashboardElements.dashboardViewMenuButton, this.wd.asserters.isDisplayed, timeout, 134 | logError.bind(undefined,'Could not find dashboard view menu button')) 135 | .elementByCssSelector(DashboardElements.dashboardViewMenuButton) 136 | .click(); 137 | return this; 138 | }; 139 | 140 | /** 141 | * Asserts the current view is the notebook view. 142 | */ 143 | Dashboard.prototype.assertInNotebookView = function(){ 144 | this.lastCommand = this.lastCommand 145 | // Assert there is no help area in notebook view 146 | .waitForConditionInBrowser( 147 | DashboardExpressions.noJupyterHeader, timeout) 148 | // Assert we can see the notebook header 149 | .waitForElementByCssSelector( 150 | DashboardElements.jupyterHeaderContainer, this.wd.asserters.isDisplayed, timeout, 151 | logError.bind(undefined,'Could not find the jupyter header')); 152 | return this; 153 | }; 154 | /** 155 | * Asserts the current view is the layout view. 156 | */ 157 | Dashboard.prototype.assertInLayoutView = function(){ 158 | this.lastCommand = this.lastCommand 159 | .waitForElementByCssSelector( 160 | DashboardElements.layoutViewHelpArea, this.wd.asserters.isDisplayed, timeout, 161 | logError.bind(undefined,'Could not find layout mode help area')); 162 | return this; 163 | }; 164 | /** 165 | * Asserts the current view is the dashboard view. 166 | */ 167 | Dashboard.prototype.assertInDashboardView = function(){ 168 | this.lastCommand = this.lastCommand 169 | .waitForElementByCssSelector( 170 | DashboardElements.jupyterHeaderContainer, this.wd.asserters.isNotDisplayed, timeout, 171 | logError.bind(undefined,'The jupyter header is diplayed')); 172 | return this; 173 | }; 174 | 175 | Dashboard.prototype.done = function(done) { 176 | this.lastCommand 177 | .execute('Jupyter.notebook.dirty = false;') 178 | .nodeify(done); 179 | return this; 180 | }; 181 | module.exports = Dashboard; 182 | --------------------------------------------------------------------------------