├── .editorconfig ├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md ├── PULL_REQUEST_TEMPLATE.md └── workflows │ └── test.yml ├── .gitignore ├── .npmrc ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── binder ├── postBuild └── requirements.txt ├── datasets.yml ├── docs ├── development.md ├── img │ ├── both.png │ ├── debugger.png │ ├── notebook.png │ ├── nteract.png │ └── registry.png └── usage.md ├── etc ├── eslint │ └── .eslintrc.js ├── jest │ ├── jest-environment.js │ ├── jest-puppeteer.config.js │ └── jest.config.js ├── lint-staged │ └── lint-staged.config.js ├── prettier │ └── .prettierrc └── stylelint │ └── .stylelintrc.json ├── icons ├── code.svg ├── code_dark.svg ├── csv.svg ├── csv_dark.svg ├── datagrid.svg ├── datagrid_dark.svg ├── folder.svg ├── folder_dark.svg ├── hdf5.svg ├── hdf5_dark.svg ├── hdf5group.svg ├── hdf5group_dark.svg ├── metadata.svg ├── metadata_dark.svg ├── notebookcell.svg ├── notebookcell_dark.svg ├── notebookcelloutput.svg ├── notebookcelloutput_dark.svg ├── pdf.svg ├── pdf_dark.svg ├── rdf.svg ├── rdf_dark.svg ├── tsv.svg └── tsv_dark.svg ├── lerna.json ├── notebooks ├── datasets.py ├── demo.ipynb ├── reference.ipynb └── tmp.csv ├── package.json ├── packages ├── dataregistry-csvviewer-extension │ ├── package.json │ ├── src │ │ ├── activate.ts │ │ ├── csv_to_data_grid.ts │ │ ├── data_grid.ts │ │ ├── datatypes.ts │ │ ├── extension_to_mimetype.ts │ │ ├── index.ts │ │ └── text_to_csv.ts │ └── tsconfig.json ├── dataregistry-extension │ ├── package.json │ ├── src │ │ ├── active.ts │ │ ├── browser.tsx │ │ ├── datatypes.ts │ │ ├── debugger.tsx │ │ ├── documents.ts │ │ ├── explorer.tsx │ │ ├── file.ts │ │ ├── files.tsx │ │ ├── folders.tsx │ │ ├── index.ts │ │ ├── notebooks.ts │ │ ├── observables.ts │ │ ├── react-inspector.ts │ │ ├── rendermime.tsx │ │ ├── snippets.ts │ │ ├── tableData.tsx │ │ ├── urls.ts │ │ ├── utils.tsx │ │ ├── viewers.ts │ │ └── widgets.tsx │ ├── style.css │ └── tsconfig.json ├── dataregistry-registry-extension │ ├── package.json │ ├── src │ │ ├── activate.ts │ │ └── index.ts │ └── tsconfig.json └── dataregistry │ ├── babel.config.js │ ├── package.json │ ├── src │ ├── cachedObservable.ts │ ├── converters.ts │ ├── createConverter.ts │ ├── datasets.ts │ ├── datatypes.ts │ ├── external.ts │ ├── files.ts │ ├── folders.ts │ ├── index.test.ts │ ├── index.ts │ ├── nested.ts │ ├── registry.ts │ ├── resolvers.ts │ ├── testutils.ts │ ├── urls.ts │ ├── urltemplates.ts │ └── utils.ts │ └── tsconfig.json ├── press_release.md ├── test └── ui │ └── test.ts ├── tsconfig.test.json └── tsconfigbase.json /.editorconfig: -------------------------------------------------------------------------------- 1 | #/ 2 | # @license BSD-3-Clause 3 | # 4 | # Copyright (c) 2019 Project Jupyter Contributors. 5 | # Distributed under the terms of the 3-Clause BSD License. 6 | #/ 7 | 8 | # EditorConfig configuration file (see ). 9 | 10 | # Indicate that this file is a root-level configuration file: 11 | root = true 12 | 13 | # Set properties for all files: 14 | [*] 15 | end_of_line = lf 16 | charset = utf-8 17 | trim_trailing_whitespace = true 18 | insert_final_newline = true 19 | 20 | # Set properties for JavaScript files: 21 | [*.js] 22 | indent_style = space 23 | indent_size = 2 24 | quote_type = single 25 | 26 | # Set properties for TypeScript files: 27 | [*.ts] 28 | indent_style = space 29 | indent_size = 2 30 | quote_type = single 31 | 32 | # Set properties for TSX files: 33 | [*.tsx] 34 | indent_style = space 35 | indent_size = 2 36 | quote_type = single 37 | 38 | # Set properties for Python files: 39 | [*.py] 40 | indent_style = space 41 | indent_size = 4 42 | 43 | # Set properties for Julia files: 44 | [*.jl] 45 | indent_style = tab 46 | 47 | # Set properties for R files: 48 | [*.R] 49 | indent_style = tab 50 | 51 | # Set properties for C files: 52 | [*.c] 53 | indent_style = tab 54 | 55 | # Set properties for C header files: 56 | [*.h] 57 | indent_style = tab 58 | 59 | # Set properties for C++ files: 60 | [*.cpp] 61 | indent_style = tab 62 | 63 | # Set properties for C++ header files: 64 | [*.hpp] 65 | indent_style = tab 66 | 67 | # Set properties for Fortran files: 68 | [*.f] 69 | indent_style = space 70 | indent_size = 2 71 | insert_final_newline = false 72 | 73 | # Set properties for shell files: 74 | [*.sh] 75 | indent_style = tab 76 | 77 | # Set properties for AWK files: 78 | [*.awk] 79 | indent_style = tab 80 | 81 | # Set properties for HTML files: 82 | [*.html] 83 | indent_style = tab 84 | tab_width = 2 85 | 86 | # Set properties for CSS files: 87 | [*.css] 88 | indent_style = tab 89 | 90 | # Set properties for Makefiles: 91 | [Makefile] 92 | indent_style = tab 93 | 94 | [*.mk] 95 | indent_style = tab 96 | 97 | # Set properties for Markdown files: 98 | [*.md] 99 | indent_style = space 100 | indent_size = 4 101 | trim_trailing_whitespace = false 102 | 103 | # Set properties for `package.json` files: 104 | [package.json] 105 | indent_style = space 106 | indent_size = 2 107 | 108 | # Set properties for `datapackage.json` files: 109 | [datapackage.json] 110 | indent_style = space 111 | indent_size = 2 112 | 113 | # Set properties for `lerna.json` files: 114 | [lerna.json] 115 | indent_style = space 116 | indent_size = 2 117 | 118 | # Set properties for `tslint.json` files: 119 | [tslint.json] 120 | indent_style = space 121 | indent_size = 2 122 | 123 | # Set properties for `tsconfig.json` files: 124 | [tsconfig.json] 125 | indent_style = space 126 | indent_size = 2 127 | 128 | # Set properties for LaTeX files: 129 | [*.tex] 130 | indent_style = tab 131 | 132 | # Set properties for LaTeX Bibliography files: 133 | [*.bib] 134 | indent_style = tab 135 | 136 | # Set properties for YAML files: 137 | [*.yml] 138 | indent_style = space 139 | indent_size = 2 140 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: 🐛 Bug Report 3 | about: Something isn't working as I expected. 🤔 4 | --- 5 | 6 | 7 | 8 | ## Checklist 9 | 10 | > Please ensure the following tasks are completed before filing a bug report. 11 | 12 | - [ ] Read and understood the [Code of Conduct][code-of-conduct]. 13 | - [ ] Searched for existing issues and pull requests. 14 | 15 | ## Description 16 | 17 | > Description of the issue. 18 | 19 | Encountered an error when . 20 | 21 | ## Related Issues 22 | 23 | > Does this issue have any related issues? 24 | 25 | Related issues # , # , and # . 26 | 27 | ## Questions 28 | 29 | > Any questions for reviewers? 30 | 31 | No. 32 | 33 | ## Other 34 | 35 | > Any other information relevant to this issue? This may include screenshots, references, stack traces, sample output, and/or implementation notes. 36 | 37 | #### Demo 38 | 39 | > If relevant, provide a link to a live demo. 40 | 41 | For a live demo of the issue, see 42 | 43 | - (link) 44 | 45 | #### Reproduction 46 | 47 | > What steps are required to reproduce the unexpected output? 48 | 49 | In order to reproduce this bug, do the following: 50 | 51 | - Go to '...' 52 | - Click on '...' 53 | - Scroll down to '...' 54 | 55 | #### Expected Results 56 | 57 | > What are the expected results? 58 | 59 | The following results are expected: 60 | 61 | ```text 62 | (insert expected results here) 63 | ``` 64 | 65 | #### Actual Results 66 | 67 | > What are the actual results? 68 | 69 | The following are the actual results: 70 | 71 | ```text 72 | (insert actual results here) 73 | ``` 74 | 75 | #### Environments 76 | 77 | > What environments are affected (e.g., if unique to a particular browser, `Chrome`, `IE 11`)? Include the Python package version, extension version, and any other potentially relevant platform information. 78 | 79 | The following environments are affected: 80 | 81 | - Device: 82 | - OS: 83 | - Browser: 84 | - Version: 85 | 86 | 87 | 88 | [code-of-conduct]: https://github.com/jupyter/governance/blob/master/conduct/code_of_conduct.md 89 | 90 | 91 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: 🚀 Feature Request 3 | about: I have a suggestion (and may want to help contribute 🙂)! 4 | --- 5 | 6 | 7 | 8 | ## Checklist 9 | 10 | > Please ensure the following tasks are completed before submitting a feature request. 11 | 12 | - [ ] Read and understood the [Code of Conduct][code-of-conduct]. 13 | - [ ] Searched for existing issues and pull requests. 14 | 15 | ## Description 16 | 17 | > Description of the feature request. 18 | 19 | This feature request proposes . 20 | 21 | ## Related Issues 22 | 23 | > Does this feature request have any related issues? 24 | 25 | Related issues # , # , and # . 26 | 27 | ## Questions 28 | 29 | > Any questions for reviewers? 30 | 31 | No. 32 | 33 | ## Other 34 | 35 | > Any other information relevant to this feature request? This may include screenshots, references, sample output, and/or implementation notes. 36 | 37 | No. 38 | 39 | 40 | 41 | [code-of-conduct]: https://github.com/jupyter/governance/blob/master/conduct/code_of_conduct.md 42 | 43 | 44 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | Resolves # . 2 | 3 | 4 | 5 | ## Checklist 6 | 7 | > Please ensure the following tasks are completed before submitting this pull request. 8 | 9 | - [ ] Read and understand the [Code of Conduct][code-of-conduct]. 10 | - [ ] Read and understood the [licensing terms][license]. 11 | - [ ] Searched for existing issues and pull requests **before** submitting this pull request. 12 | - [ ] Filed an issue (or an issue already existed) **prior to** submitting this pull request. 13 | - [ ] Submitted against `master` branch. 14 | 15 | ## Description 16 | 17 | > What is the purpose of this pull request? 18 | 19 | This pull request: 20 | 21 | - a 22 | - b 23 | - c 24 | 25 | ## Related Issues 26 | 27 | > Does this pull request have any related issues? 28 | 29 | This pull request: 30 | 31 | - resolves # 32 | - fixes # 33 | 34 | ## Questions 35 | 36 | > Any questions for reviewers of this pull request? 37 | 38 | No. 39 | 40 | ## Other 41 | 42 | > Any other information relevant to this pull request? This may include screenshots, references, and/or implementation notes. 43 | 44 | No. 45 | 46 | 47 | 48 | [code-of-conduct]: https://github.com/jupyter/governance/blob/master/conduct/code_of_conduct.md 49 | [license]: https://github.com/jupyterlab/jupyterlab-data-explorer/blob/master/LICENSE 50 | 51 | 52 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | on: [push, pull_request] 2 | jobs: 3 | lint: 4 | runs-on: ubuntu-latest 5 | steps: 6 | - uses: actions/checkout@v1 7 | - uses: actions/setup-python@v1 8 | with: 9 | python-version: '3.6' 10 | - uses: actions/setup-node@v1 11 | with: 12 | node-version: '10.x' 13 | - run: python -m pip install --upgrade pip 14 | - run: pip install jupyterlab 15 | - run: jlpm 16 | - run: jlpm run lint:check 17 | test: 18 | runs-on: ubuntu-latest 19 | 20 | steps: 21 | - uses: actions/checkout@v1 22 | - uses: actions/setup-python@v1 23 | with: 24 | python-version: '3.6' 25 | - uses: actions/setup-node@v1 26 | with: 27 | node-version: '10.x' 28 | - run: python -m pip install --upgrade pip 29 | - run: pip install jupyterlab 30 | - run: jlpm run build 31 | - run: jupyter lab build --debug-log-path log.txt 32 | - if: failure() 33 | run: cat log.txt 34 | - run: jlpm run test 35 | - name: upload screenshots 36 | if: failure() 37 | uses: actions/upload-artifact@v1 38 | with: 39 | name: screenshots 40 | path: screenshots 41 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | #/ 2 | # @license BSD-3-Clause 3 | # 4 | # Copyright (c) 2019 Project Jupyter Contributors. 5 | # Distributed under the terms of the 3-Clause BSD License. 6 | #/ 7 | 8 | build 9 | lib 10 | node_modules 11 | screenshots 12 | 13 | **/.ipynb_checkpoints 14 | *.tsbuildinfo 15 | 16 | .idea 17 | *.iml 18 | .vscode 19 | 20 | __pycache__/ 21 | 22 | yarn.lock 23 | yarn-error.log 24 | package-lock.json 25 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | #/ 2 | # @license BSD-3-Clause 3 | # 4 | # Copyright (c) 2019 Project Jupyter Contributors. 5 | # Distributed under the terms of the 3-Clause BSD License. 6 | #/ 7 | 8 | # Configuration for [npm][1]. 9 | # 10 | # [1]: https://docs.npmjs.com/files/npmrc 11 | 12 | # Disable the creation of a lock file: 13 | package-lock = false 14 | shrinkwrap = false 15 | 16 | # Disable automatically "saving" dependencies on install: 17 | save = false -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2019 Project Jupyter Contributors 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | 1. Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | 2. Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | 3. Neither the name of the copyright holder nor the names of its 17 | contributors may be used to endorse or promote products derived from 18 | this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | **This repository has been archived by lack of maintainers.** 2 | 3 | # JupyterLab Data Explorer 4 | 5 | ![Stability Experimental][badge-stability] [![npm][badge-npm-version-dataregistry-extension]][npm-package-dataregistry-extension] [![npm][badge-npm-version-dataregistry]][npm-package-dataregistry] 6 | 7 | To experiment with the extension in a live notebook environment, 8 | 9 | - latest release (stable version): [![Binder (stable)][badge-binder]][binder-stable] 10 | - latest master (bleeding edge): [![Binder (latest)][badge-binder]][binder-master] 11 | 12 | ## Overview 13 | 14 | - Bring any data type you can imagine! **Extensible** and **type safe** data registry system. 15 | - Register **conversions** between the different data types. 16 | - Data changing on you? Use [`RxJS` **observables**][rxjs] to represent data over time. 17 | - Have a new way to look at your data? Create **React** or **lumino** components to view a certain type. 18 | - Built-in data **explorer UI** to find and use available datasets. 19 | - Dataset in your dataset? Use the **nested** datatype. 20 | - Building another data centric application? Use the [`@jupyterlab/dataregistry`][npm-package-dataregistry] package which can be used independently of [JupyterLab][jupyterlab]. 21 | - Check out the project vision in the ["Press Release from the Future"](./press_release.md)! 22 | 23 | ![](https://user-images.githubusercontent.com/1186124/59360085-85becf80-8cfd-11e9-8fc8-98d8a7b83934.png) 24 | 25 | ## Prerequisites 26 | 27 | When used as a [JupyterLab][jupyterlab] extension, 28 | 29 | - [JupyterLab][jupyterlab] (version >= 1.0.0) 30 | 31 | ## Installation 32 | 33 | ```bash 34 | $ jupyter labextension install @jupyterlab/dataregistry-extension 35 | ``` 36 | 37 | ## Usage 38 | 39 | [Usage docs](./docs/usage.md) 40 | 41 | ## Contributing 42 | 43 | This repository is in active development, and we welcome collaboration. For development guidance, please consult the [development guide](./docs/development.md). 44 | 45 | If you have ideas or questions, feel free to open an issue, or, if you feel like getting your hands dirty, feel free to tackle an existing issue by contributing a pull request. 46 | 47 | We try to keep the current issues relevant and matched to relevant milestones. 48 | 49 | ### Third Party Extenson 50 | 51 | You can either add support by adding a new converter to this repository or creating a new [JupyterLab][jupyterlab] extension that depends on the `IRegistry` exposed by this extension. You can access a `Registry`, which you can use to add your own converter. 52 | 53 | It might also be useful to view the existing data types by looking at the source code in this repository and by using the debugger. You can open this in [JupyterLab][jupyterlab] by looking for the "Data Debugger" command: 54 | 55 | ![](./docs/img/debugger.png) 56 | 57 | 58 | 59 | [badge-stability]: https://img.shields.io/badge/stability-experimental-red.svg 60 | [badge-binder]: https://mybinder.org/badge_logo.svg 61 | [binder-stable]: https://mybinder.org/v2/gh/jupyterlab/jupyterlab-data-explorer/4a47ff159818159450814b33b0b33f2221c223a5?urlpath=lab%2Ftree%2Fnotebooks%2Fdemo.ipynb 62 | [binder-master]: https://mybinder.org/v2/gh/jupyterlab/jupyterlab-data-explorer/master?urlpath=lab%2Ftree%2Fnotebooks%2Fdemo.ipynb 63 | [badge-npm-version-dataregistry-extension]: https://img.shields.io/npm/v/@jupyterlab/dataregistry-extension?label=%40jupyterlab%2Fdataregistry-extension&style=flat 64 | [npm-package-dataregistry-extension]: https://www.npmjs.com/package/@jupyterlab/dataregistry-extension 65 | [badge-npm-version-dataregistry]: https://img.shields.io/npm/v/@jupyterlab/dataregistry?label=%40jupyterlab%2Fdataregistry&style=flat 66 | [npm-package-dataregistry]: https://www.npmjs.com/package/@jupyterlab/dataregistry 67 | [jupyterlab]: https://github.com/jupyterlab/jupyterlab 68 | [rxjs]: https://rxjs.dev/ 69 | [nteract-data-explorer]: https://github.com/nteract/nteract/tree/master/packages/data-explorer 70 | 71 | 72 | -------------------------------------------------------------------------------- /binder/postBuild: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # 3 | # @license BSD-3-Clause 4 | # 5 | # Copyright (c) 2019 Project Jupyter Contributors. 6 | # Distributed under the terms of the 3-Clause BSD License. 7 | 8 | set -o errexit 9 | set -o xtrace 10 | 11 | jlpm install 12 | jlpm run registry & 13 | jlpm run registry:init 14 | jlpm run build 15 | jupyter lab build || (jlpm run build:jupyter:remediate && jupyter lab build) 16 | -------------------------------------------------------------------------------- /binder/requirements.txt: -------------------------------------------------------------------------------- 1 | pandas 2 | jupyterlab>=2.0 3 | vega_datasets 4 | -------------------------------------------------------------------------------- /datasets.yml: -------------------------------------------------------------------------------- 1 | children: 2 | - 'test:///hi' 3 | datasets: 4 | - url: 'test:///hi' 5 | label: 'Custom label!' 6 | snippets: 7 | some code: "It's code!" 8 | other code: "It's code!" 9 | children: 10 | - 'test:///other' 11 | - url: 'test:///other' 12 | snippets: 13 | more code: 'another code' 14 | -------------------------------------------------------------------------------- /docs/development.md: -------------------------------------------------------------------------------- 1 | 9 | 10 | # Development 11 | 12 | > Development guide. 13 | 14 | ## Introduction 15 | 16 | Before we begin, development requires some setup and configuration. What follows is an overview of environment requirements and a sequence of steps for getting up and running. We use [Git][git] for version control, and for most tasks, we use [npm][npm] scripts to help us get things done quickly and effectively. For the most part, the project is able to internally manage dependencies for testing and linting, so, once you follow the steps below, you should be ready to start developing! 17 | 18 | So, without further ado, let's get you started! 19 | 20 | ## Prerequisites 21 | 22 | Development requires the following prerequisites: 23 | 24 | - [Git][git]: version control 25 | - [Python][python]: general purpose language (version `>= 3.6`) 26 | - [pip][pip]: Python package manager (version `>= 9.0.0`) 27 | - [Node.js][node-js]: JavaScript runtime (latest stable version is **strongly** recommended) 28 | - [npm][npm]: package manager (version `> 2.7.0`) 29 | - [JupyterLab][jupyterlab]: computational environment (version `>= 1.0.0`) 30 | 31 | While not required, you are encouraged to create an [Anaconda][anaconda] environment. 32 | 33 | ```bash 34 | $ conda create -n jupyterlab-data-explorer -c conda-forge python=3.6 jupyterlab nodejs 35 | ``` 36 | 37 | To activate the environment, 38 | 39 | ```bash 40 | $ conda activate jupyterlab-data-explorer 41 | ``` 42 | 43 | > **NOTE**: for each new terminal window, you'll need to explicitly activate the [Anaconda][anaconda] environment. 44 | 45 | ## Download 46 | 47 | To acquire the source code, first navigate to the parent directory in which you want to place the project [Git][git] repository. 48 | 49 | > **NOTE**: avoid directory paths which include spaces or any other shell meta characters such as `$` or `:`, as these characters can be problematic for certain build tools. 50 | 51 | ```bash 52 | $ cd /path/to/parent/destination/directory 53 | ``` 54 | 55 | Next, clone the repository. 56 | 57 | ```bash 58 | $ git clone https://github.com/jupyterlab/jupyterlab-data-explorer.git 59 | ``` 60 | 61 | If you are wanting to contribute to this GitHub repository, first [fork][github-fork] the repository and amend the previous command. 62 | 63 | ```bash 64 | $ git clone https://github.com//jupyterlab-data-explorer.git 65 | ``` 66 | 67 | where `` is your GitHub username (assuming you are using GitHub to manage public repositories). The repository may have a large commit history, leading to slow download times. If you are not interested in code archeology, you can reduce the download time by limiting the [depth][git-clone-depth]. 68 | 69 | ```bash 70 | $ git clone --depth= https://github.com//jupyterlab-data-explorer.git 71 | ``` 72 | 73 | where `` refers to the number of commits you want to download (as few as 1 and as many as the entire project history). 74 | 75 | If you are behind a firewall, you may need to use the `http` protocol, rather than the [`git`][git] protocol. 76 | 77 | ```bash 78 | $ git config --global url."https://".insteadOf git:// 79 | ``` 80 | 81 | Once you have finished cloning the repository into the destination directory, you should see the folder `jupyterlab-data-explorer`. To proceed with configuring your environment, navigate to the project folder. 82 | 83 | ```bash 84 | $ cd jupyterlab-data-explorer 85 | ``` 86 | 87 | ## Installation 88 | 89 | To install development dependencies (e.g., [Node.js][node-js] module dependencies), 90 | 91 | ```bash 92 | $ jlpm install 93 | ``` 94 | 95 | where `jlpm` is the JupyterLab package manager which is bundled with [JupyterLab][jupyterlab]. 96 | 97 | During development, we need to maintain a local [npm][npm] package registry for storing unpublished data explorer packages. In a separate terminal window, 98 | 99 | ```bash 100 | $ jlpm run registry 101 | ``` 102 | 103 | Returning to the previous terminal window, initialize the local package registry 104 | 105 | ```bash 106 | $ jlpm run registry:init 107 | ``` 108 | 109 | To verify that the local package registry is running and that local packages have been published to that registry, 110 | 111 | ```bash 112 | $ open http://localhost:4873 113 | ``` 114 | 115 | ## Build 116 | 117 | To build data explorer packages, 118 | 119 | ```bash 120 | $ jlpm run build 121 | ``` 122 | 123 | If your environment has been configured correctly, the previous command should complete without errors. 124 | 125 | To build the [JupyterLab][jupyterlab] extensions found in this repository and to launch the [JupyterLab][jupyterlab] environment, 126 | 127 | ```bash 128 | $ jlpm run build:jupyter 129 | ``` 130 | 131 | ## Clean 132 | 133 | To clean your local environment, including [Node.js][node-js] module dependencies, 134 | 135 | ```bash 136 | $ jlpm run clean 137 | ``` 138 | 139 | To remove build artifacts, such as compiled JavaScript files, from data explorer packages, 140 | 141 | ```bash 142 | $ jlpm run clean:packages 143 | ``` 144 | 145 | To remove [JupyterLab][jupyterlab] extension artifacts, such as linked extensions, 146 | 147 | ```bash 148 | $ jlpm run clean:jupyter 149 | ``` 150 | 151 | ## Reset 152 | 153 | To clean and rebuild the data explorer extensions, 154 | 155 | ```bash 156 | $ jlpm run all 157 | ``` 158 | 159 | ## Watch 160 | 161 | During development, you'll likely want data explorer extensions to automatically recompile and update. Accordingly, in a separate terminal window, 162 | 163 | ```bash 164 | $ jlpm run build:watch 165 | ``` 166 | 167 | which will automatically trigger recompilation upon updates to source files. 168 | 169 | In another terminal window, 170 | 171 | ```bash 172 | $ jlpm run build:jupyter:watch 173 | ``` 174 | 175 | which will launch the [JupyterLab][jupyterlab] environment and automatically update the running lab environment upon recompilation changes. 176 | 177 | ## Update 178 | 179 | If you have previously downloaded the repository using `git clone`, you can update an existing source tree from the base project directory using `git pull`. 180 | 181 | ```bash 182 | $ git pull 183 | ``` 184 | 185 | If you are working with a [forked][github-fork] repository and wish to [sync][github-fork-sync] your local repository with the [upstream][git-remotes] project (i.e., incorporate changes from the main project repository into your local repository), assuming you have [configured a remote][github-remote] which points to the upstream repository, 186 | 187 | ```bash 188 | $ git fetch upstream 189 | $ git merge upstream/ 190 | ``` 191 | 192 | where `upstream` is the remote name and `` refers to the branch you want to merge into your local copy. 193 | 194 | ## Organization 195 | 196 | The repository is organized as follows: 197 | 198 | ```text 199 | binder Binder configuration 200 | docs top-level documentation 201 | etc project configuration files 202 | notebooks Jupyter notebooks 203 | packages project packages 204 | scripts development scripts 205 | test project tests 206 | ``` 207 | 208 | ## Core concepts 209 | 210 | The data registry is a global collection of datasets. Each dataset is conceptually a tuple of `(URL, MimeType, cost, data)`; however, we store them in nested maps of `Map>` so that, for every unique pair of URL and MimeType, we only have one dataset ([`./dataregistry/src/datasets.ts`](./../packages/dataregistry/src/datasets.ts)). 211 | 212 | A "converter" takes in a dataset and returns several other datasets that all have the same URL. We can apply a converter to a certain URL by viewing it as a graph exploration problem. There is one node per Mime Type and we can [fill in the graph][dijkstras-algorithm] to add every reachable mime type with the lowest cost ([`./dataregistry/src/converters.ts`](./../packages/dataregistry/src/converters.ts)). 213 | 214 | Conceptually, each Mime Type should correspond to some defined runtime type of data. For example `text/csv` corresponds to an `Observable` which is the contents of CSV file. We need to be able to agree about these definitions so that, if create a converter to produce a `text/csv` mime type and you create one that takes in that mime type and creates some visualization, we know we are dealing with the same type. A "data type" helps us here because we map a set of mime types to a TypeScript type. For example, we could define the CSV mime type as `new DataTypeNoArgs>("text/csv")`. We provide a way to create a converter from one data type to another, which is `createConverter`. Data types abstract away the textual representation of the mime type from the consumer of a data type and provide a type safe way to convert to or from that data type. All of our core conversions use this typed API ([`./dataregistry/src/datatypes.ts`](./../packages/dataregistry/src/datatypes.ts)): 215 | 216 | - [`resolveDataType`](./../packages/dataregistry/src/resolvers.ts) `void`: Every URL starts with this data type when you ask for it. It has no actual data in it, so when you write a converter from it you will use the URL. 217 | - [`nestedDataType`](./../packages/dataregistry/src/nested.ts) `Observable>`: This specifies the URLs that are "nested" under a URL. Use this if your dataset has some sense of children like a folder has a number of files in it or a database has a number of tables. These are exposed in the data explorer as the children in the hierarchy. 218 | - [`viewerDataType`](./../packages/dataregistry-extension/src/viewers.ts) `() => void`: This is a function you can call to "view" that dataset in some way. It has a parameter as well, the "label", which is included in the mime type as an argument. This is exposed in the explorer as a button on the dataset. 219 | 220 | 227 | 228 | ## Editors 229 | 230 | - This repository uses [EditorConfig][editorconfig] to maintain consistent coding styles between different editors and IDEs, including [browsers][editorconfig-chrome]. 231 | 232 | 233 | 234 | [git]: http://git-scm.com/ 235 | [python]: https://www.python.org/ 236 | [pip]: https://github.com/pypa/pip 237 | [node-js]: https://nodejs.org/en/ 238 | [npm]: https://www.npmjs.com/ 239 | [jupyterlab]: https://github.com/jupyterlab/jupyterlab 240 | [anaconda]: https://docs.conda.io/projects/conda/en/latest/user-guide/tasks/manage-environments.html 241 | [github-fork]: https://help.github.com/articles/fork-a-repo/ 242 | [github-fork-sync]: https://help.github.com/articles/syncing-a-fork/ 243 | [github-remote]: https://help.github.com/articles/configuring-a-remote-for-a-fork/ 244 | [git-clone-depth]: https://git-scm.com/docs/git-clone#git-clone---depthltdepthgt 245 | [git-remotes]: https://git-scm.com/book/en/v2/Git-Basics-Working-with-Remotes 246 | [dijkstras-algorithm]: https://en.wikipedia.org/wiki/Dijkstra's_algorithm 247 | [editorconfig]: http://editorconfig.org/ 248 | [editorconfig-chrome]: https://chrome.google.com/webstore/detail/github-editorconfig/bppnolhdpdfmmpeefopdbpmabdpoefjh?hl=en-US 249 | 250 | 251 | -------------------------------------------------------------------------------- /docs/img/both.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jupyterlab/jupyterlab-data-explorer/db762f98a5c362ecf9617d94d17e4fe78de6b9dc/docs/img/both.png -------------------------------------------------------------------------------- /docs/img/debugger.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jupyterlab/jupyterlab-data-explorer/db762f98a5c362ecf9617d94d17e4fe78de6b9dc/docs/img/debugger.png -------------------------------------------------------------------------------- /docs/img/notebook.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jupyterlab/jupyterlab-data-explorer/db762f98a5c362ecf9617d94d17e4fe78de6b9dc/docs/img/notebook.png -------------------------------------------------------------------------------- /docs/img/nteract.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jupyterlab/jupyterlab-data-explorer/db762f98a5c362ecf9617d94d17e4fe78de6b9dc/docs/img/nteract.png -------------------------------------------------------------------------------- /docs/img/registry.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jupyterlab/jupyterlab-data-explorer/db762f98a5c362ecf9617d94d17e4fe78de6b9dc/docs/img/registry.png -------------------------------------------------------------------------------- /docs/usage.md: -------------------------------------------------------------------------------- 1 | # Usage 2 | 3 | The Data Registry JupyterLab extension adds two new UI elements, a Data Explorer in the left pane, and a Data Browser in the right pane: 4 | 5 | ![Data registry and data browser panes](./img/both.png) 6 | 7 | The Data Registry lets you browse datasets that are available to you. It is a nested view that shows a number of actions you can take for each dataset along with any children datasets. 8 | 9 | ![Show children datasets of a folder and actions](./img/registry.png) 10 | 11 | We currently provide built-in support for a limited number of data types. These are meant to show examples of different types of interactions and stress test the system. They can be extended by creating custom JupyterLab extensions which add new data types and/or viewers: 12 | 13 | - CSV files 14 | - Viewing in a data grid 15 | - Inserting a code snippet to load with Pandas 16 | - `datasets.yml` files can be created which allow you to create nested datasets to display, without having to write a JupyterLab extension 17 | - Custom snippets for the datasets defined within the file 18 | - Custom labels to change how it is displayed in the data registry 19 | - JSON Table Schema 20 | - [`nteract`'s data explorer][nteract-data-explorer] 21 | - Images 22 | - Viewing 23 | - Folders 24 | - Showing contents as children 25 | - Notebooks 26 | - Showing cells and outputs as children 27 | - Registering output MIME types 28 | 29 | If you are browsing a number of datasets and want to preview the different ways to view them, you can use the Data Browser. It will display any views of the currently "active" dataset. A dataset becomes active if you click on it in the Data Registry, switch to a file widget, or change cells. This is also extensibble, so if you create a custom widget, you can update the active dataset to include selections inside of it. We provide a `demo.ipynb` Notebook which shows a number of different MIME types we support, that you can explore in the Data Browser: 30 | 31 | ![Gif data browser showing output from notebook cell](./img/notebook.png) 32 | 33 | Note that you must enable Panda's JSON outputs to see the nteract table viewer: 34 | 35 | ```python 36 | pandas.set_option('display.html.table_schema', True) 37 | ``` 38 | 39 | You can also install other extensions to add functionality to the data registry, including: 40 | 41 | - [`@jupyterlab/hdf5`][hdf5] Adds support for viewing HDF5 files 42 | 43 | 44 | 45 | [nteract-data-explorer]: https://github.com/nteract/nteract/tree/master/packages/data-explorer 46 | [hdf5]: https://github.com/jupyterlab/jupyterlab-hdf5 47 | 48 | 49 | -------------------------------------------------------------------------------- /etc/eslint/.eslintrc.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @license BSD-3-Clause 3 | * 4 | * Copyright (c) 2019 Project Jupyter Contributors. 5 | * Distributed under the terms of the 3-Clause BSD License. 6 | */ 7 | 8 | const resolve = require('path').resolve; 9 | 10 | const config = { 11 | env: { 12 | browser: true, 13 | es6: true, 14 | }, 15 | extends: [ 16 | 'eslint:recommended', 17 | 'plugin:@typescript-eslint/eslint-recommended', 18 | 'plugin:@typescript-eslint/recommended', 19 | 'prettier/@typescript-eslint', 20 | ], 21 | parser: '@typescript-eslint/parser', 22 | parserOptions: { 23 | tsconfigRootDir: resolve(__dirname, '..', '..'), 24 | project: ['./tsconfig.test.json', './packages/**/tsconfig.json'], 25 | ecmaFeatures: { 26 | jsx: true, 27 | }, 28 | ecmaVersion: 2018, 29 | sourceType: 'module', 30 | }, 31 | plugins: ['prettier', 'react', 'react-hooks', '@typescript-eslint'], 32 | rules: { 33 | '@typescript-eslint/no-use-before-define': 'off', 34 | '@typescript-eslint/explicit-function-return-type': 'off', 35 | '@typescript-eslint/no-non-null-assertion': 'off', 36 | '@typescript-eslint/no-unused-vars': 'off', 37 | '@typescript-eslint/interface-name-prefix': 'off', 38 | '@typescript-eslint/no-explicit-any': 'off', 39 | 'react-hooks/rules-of-hooks': 'error', 40 | 'react-hooks/exhaustive-deps': 'warn', 41 | 'prettier/prettier': ['error', { singleQuote: true }], 42 | 'linebreak-style': ['error', 'unix'], 43 | 'no-console': ['error', { allow: ['warn', 'error'] }], 44 | }, 45 | }; 46 | 47 | /** 48 | * Exports. 49 | */ 50 | module.exports = config; 51 | -------------------------------------------------------------------------------- /etc/jest/jest-environment.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @license BSD-3-Clause 3 | * 4 | * Copyright (c) 2019 Project Jupyter Contributors. 5 | * Distributed under the terms of the 3-Clause BSD License. 6 | */ 7 | 8 | // Based on from https://yarnpkg.com/en/package/@rws-air/jestscreenshot 9 | 10 | const PuppeteerEnvironment = require('jest-environment-puppeteer'); 11 | const JestScreenshot = require('@rws-air/jestscreenshot'); 12 | const resolve = require('path').resolve; 13 | 14 | class CustomEnvironment extends PuppeteerEnvironment { 15 | async setup() { 16 | await super.setup(); 17 | } 18 | async teardown() { 19 | await this.global.page.waitFor(2000); 20 | await super.teardown(); 21 | } 22 | 23 | async handleTestEvent(event, state) { 24 | if (event.name === 'test_fn_failure') { 25 | const testName = state.currentlyRunningTest.name; 26 | 27 | const jestScreenshot = new JestScreenshot({ 28 | page: this.global.page, 29 | dirName: resolve(__dirname, '..', '..'), 30 | testName, 31 | }); 32 | 33 | await jestScreenshot.setup(); 34 | } 35 | } 36 | } 37 | 38 | /** 39 | * Exports. 40 | */ 41 | module.exports = CustomEnvironment; 42 | -------------------------------------------------------------------------------- /etc/jest/jest-puppeteer.config.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @license BSD-3-Clause 3 | * 4 | * Copyright (c) 2019 Project Jupyter Contributors. 5 | * Distributed under the terms of the 3-Clause BSD License. 6 | */ 7 | 8 | const config = { 9 | launch: { 10 | headless: process.env.HEADLESS !== 'false', 11 | slowMo: process.env.SLOWMO === 'true', 12 | }, 13 | // https://github.com/smooth-code/jest-puppeteer/tree/master/packages/jest-dev-server#options 14 | server: { 15 | command: "jupyter lab --port 8080 --no-browser --LabApp.token=''", 16 | port: 8080, 17 | }, 18 | }; 19 | 20 | /** 21 | * Exports. 22 | */ 23 | module.exports = config; 24 | -------------------------------------------------------------------------------- /etc/jest/jest.config.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @license BSD-3-Clause 3 | * 4 | * Copyright (c) 2019 Project Jupyter Contributors. 5 | * Distributed under the terms of the 3-Clause BSD License. 6 | */ 7 | 8 | const resolve = require('path').resolve; 9 | const { defaults: tsjPreset } = require('ts-jest/presets'); 10 | 11 | // Resolve the root project directory: 12 | const ROOT = resolve(__dirname, '..', '..'); 13 | 14 | const config = { 15 | rootDir: ROOT, 16 | 17 | // Needed for jest-screenshots 18 | testRunner: 'jest-circus/runner', 19 | 20 | testEnvironment: resolve(__dirname, 'jest-environment.js'), 21 | globalSetup: 'jest-environment-puppeteer/setup', 22 | globalTeardown: 'jest-environment-puppeteer/teardown', 23 | setupFilesAfterEnv: ['expect-puppeteer'], 24 | transform: { 25 | ...tsjPreset.transform, 26 | }, 27 | moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'node'], 28 | testMatch: ['**/test/**/test*.ts?(x)'], 29 | testPathIgnorePatterns: ['/build/', '/lib/', '/node_modules/'], 30 | globals: { 31 | 'ts-jest': { 32 | tsConfig: resolve(ROOT, 'tsconfig.test.json'), 33 | }, 34 | }, 35 | }; 36 | 37 | /** 38 | * Exports. 39 | */ 40 | module.exports = config; 41 | -------------------------------------------------------------------------------- /etc/lint-staged/lint-staged.config.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @license BSD-3-Clause 3 | * 4 | * Copyright (c) 2019 Project Jupyter Contributors. 5 | * Distributed under the terms of the 3-Clause BSD License. 6 | */ 7 | 8 | const resolve = require('path').resolve; 9 | 10 | const rc = resolve(__dirname, '..', 'prettier', '.prettierrc'); 11 | const ignore = resolve(__dirname, '..', 'prettier', '.prettierignore'); 12 | 13 | const config = { 14 | '**/*{.ts,.tsx,.js,.jsx,.css,.json,.md}': [ 15 | 'prettier --config=' + rc + ' --ignore-path=' + ignore + ' --write', 16 | 'git add', 17 | ], 18 | }; 19 | 20 | /** 21 | * Exports. 22 | */ 23 | module.exports = config; 24 | -------------------------------------------------------------------------------- /etc/prettier/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "singleQuote": true 3 | } 4 | -------------------------------------------------------------------------------- /etc/stylelint/.stylelintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["stylelint-config-standard", "stylelint-config-prettier"] 3 | } 4 | -------------------------------------------------------------------------------- /icons/code.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /icons/code_dark.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /icons/csv.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /icons/csv_dark.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /icons/datagrid.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /icons/datagrid_dark.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /icons/folder.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /icons/folder_dark.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /icons/hdf5.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /icons/hdf5_dark.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /icons/hdf5group.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /icons/hdf5group_dark.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /icons/metadata.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /icons/metadata_dark.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /icons/notebookcell.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /icons/notebookcell_dark.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /icons/notebookcelloutput.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /icons/notebookcelloutput_dark.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /icons/pdf.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /icons/pdf_dark.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /icons/rdf.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /icons/rdf_dark.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /icons/tsv.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /icons/tsv_dark.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /lerna.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "independent", 3 | "packages": ["packages/*"], 4 | "npmClient": "jlpm", 5 | "npmClientArgs": ["--no-lockfile"], 6 | "useWorkspaces": true 7 | } 8 | -------------------------------------------------------------------------------- /notebooks/datasets.py: -------------------------------------------------------------------------------- 1 | # 2 | # @license BSD-3-Clause 3 | # 4 | # Copyright (c) 2019 Project Jupyter Contributors. 5 | # Distributed under the terms of the 3-Clause BSD License. 6 | 7 | import IPython.display 8 | import pandas 9 | 10 | 11 | def output_url(url): 12 | IPython.display.publish_display_data( 13 | {"application/x.jupyter.relative-dataset-urls+json": [url]} 14 | ) 15 | -------------------------------------------------------------------------------- /notebooks/reference.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "From this notebook we can reference an output in the the other notebook:" 8 | ] 9 | }, 10 | { 11 | "cell_type": "code", 12 | "execution_count": 1, 13 | "metadata": {}, 14 | "outputs": [], 15 | "source": [ 16 | "from datasets import *" 17 | ] 18 | }, 19 | { 20 | "cell_type": "code", 21 | "execution_count": 2, 22 | "metadata": {}, 23 | "outputs": [ 24 | { 25 | "data": { 26 | "application/x.jupyter.relative-dataset-urls+json": [ 27 | "./Table.ipynb#/cells/4" 28 | ] 29 | }, 30 | "metadata": {}, 31 | "output_type": "display_data" 32 | } 33 | ], 34 | "source": [ 35 | "output_url(\"./Table.ipynb#/cells/4\")" 36 | ] 37 | }, 38 | { 39 | "cell_type": "code", 40 | "execution_count": null, 41 | "metadata": {}, 42 | "outputs": [], 43 | "source": [] 44 | } 45 | ], 46 | "metadata": { 47 | "kernelspec": { 48 | "display_name": "Python 3", 49 | "language": "python", 50 | "name": "python3" 51 | }, 52 | "language_info": { 53 | "codemirror_mode": { 54 | "name": "ipython", 55 | "version": 3 56 | }, 57 | "file_extension": ".py", 58 | "mimetype": "text/x-python", 59 | "name": "python", 60 | "nbconvert_exporter": "python", 61 | "pygments_lexer": "ipython3", 62 | "version": "3.6.7" 63 | } 64 | }, 65 | "nbformat": 4, 66 | "nbformat_minor": 4 67 | } 68 | -------------------------------------------------------------------------------- /notebooks/tmp.csv: -------------------------------------------------------------------------------- 1 | petalLength,petalWidth,sepalLength,sepalWidth,species 2 | 1.4,0.2,5.1,3.5,setosa 3 | 1.4,0.2,4.9,3.0,setosa 4 | 1.3,0.2,4.7,3.2,setosa 5 | 1.5,0.2,4.6,3.1,setosa 6 | 1.4,0.2,5.0,3.6,setosa 7 | 1.7000000000000002,0.4,5.4,3.9,setosa 8 | 1.4,0.30000000000000004,4.6,3.4,setosa 9 | 1.5,0.2,5.0,3.4,setosa 10 | 1.4,0.2,4.4,2.9,setosa 11 | 1.5,0.1,4.9,3.1,setosa 12 | 1.5,0.2,5.4,3.7,setosa 13 | 1.6,0.2,4.8,3.4,setosa 14 | 1.4,0.1,4.8,3.0,setosa 15 | 1.1,0.1,4.3,3.0,setosa 16 | 1.2,0.2,5.8,4.0,setosa 17 | 1.5,0.4,5.7,4.4,setosa 18 | 1.3,0.4,5.4,3.9,setosa 19 | 1.4,0.30000000000000004,5.1,3.5,setosa 20 | 1.7000000000000002,0.30000000000000004,5.7,3.8,setosa 21 | 1.5,0.30000000000000004,5.1,3.8,setosa 22 | 1.7000000000000002,0.2,5.4,3.4,setosa 23 | 1.5,0.4,5.1,3.7,setosa 24 | 1.0,0.2,4.6,3.6,setosa 25 | 1.7000000000000002,0.5,5.1,3.3,setosa 26 | 1.9,0.2,4.8,3.4,setosa 27 | 1.6,0.2,5.0,3.0,setosa 28 | 1.6,0.4,5.0,3.4,setosa 29 | 1.5,0.2,5.2,3.5,setosa 30 | 1.4,0.2,5.2,3.4,setosa 31 | 1.6,0.2,4.7,3.2,setosa 32 | 1.6,0.2,4.8,3.1,setosa 33 | 1.5,0.4,5.4,3.4,setosa 34 | 1.5,0.1,5.2,4.1,setosa 35 | 1.4,0.2,5.5,4.2,setosa 36 | 1.5,0.2,4.9,3.1,setosa 37 | 1.2,0.2,5.0,3.2,setosa 38 | 1.3,0.2,5.5,3.5,setosa 39 | 1.4,0.1,4.9,3.6,setosa 40 | 1.3,0.2,4.4,3.0,setosa 41 | 1.5,0.2,5.1,3.4,setosa 42 | 1.3,0.30000000000000004,5.0,3.5,setosa 43 | 1.3,0.30000000000000004,4.5,2.3,setosa 44 | 1.3,0.2,4.4,3.2,setosa 45 | 1.6,0.6000000000000001,5.0,3.5,setosa 46 | 1.9,0.4,5.1,3.8,setosa 47 | 1.4,0.30000000000000004,4.8,3.0,setosa 48 | 1.6,0.2,5.1,3.8,setosa 49 | 1.4,0.2,4.6,3.2,setosa 50 | 1.5,0.2,5.3,3.7,setosa 51 | 1.4,0.2,5.0,3.3,setosa 52 | 4.7,1.4,7.0,3.2,versicolor 53 | 4.5,1.5,6.4,3.2,versicolor 54 | 4.9,1.5,6.9,3.1,versicolor 55 | 4.0,1.3,5.5,2.3,versicolor 56 | 4.6,1.5,6.5,2.8,versicolor 57 | 4.5,1.3,5.7,2.8,versicolor 58 | 4.7,1.6,6.3,3.3,versicolor 59 | 3.3,1.0,4.9,2.4,versicolor 60 | 4.6,1.3,6.6,2.9,versicolor 61 | 3.9,1.4,5.2,2.7,versicolor 62 | 3.5,1.0,5.0,2.0,versicolor 63 | 4.2,1.5,5.9,3.0,versicolor 64 | 4.0,1.0,6.0,2.2,versicolor 65 | 4.7,1.4,6.1,2.9,versicolor 66 | 3.6,1.3,5.6,2.9,versicolor 67 | 4.4,1.4,6.7,3.1,versicolor 68 | 4.5,1.5,5.6,3.0,versicolor 69 | 4.1,1.0,5.8,2.7,versicolor 70 | 4.5,1.5,6.2,2.2,versicolor 71 | 3.9,1.1,5.6,2.5,versicolor 72 | 4.8,1.8,5.9,3.2,versicolor 73 | 4.0,1.3,6.1,2.8,versicolor 74 | 4.9,1.5,6.3,2.5,versicolor 75 | 4.7,1.2,6.1,2.8,versicolor 76 | 4.3,1.3,6.4,2.9,versicolor 77 | 4.4,1.4,6.6,3.0,versicolor 78 | 4.8,1.4,6.8,2.8,versicolor 79 | 5.0,1.7000000000000002,6.7,3.0,versicolor 80 | 4.5,1.5,6.0,2.9,versicolor 81 | 3.5,1.0,5.7,2.6,versicolor 82 | 3.8,1.1,5.5,2.4,versicolor 83 | 3.7,1.0,5.5,2.4,versicolor 84 | 3.9,1.2,5.8,2.7,versicolor 85 | 5.1,1.6,6.0,2.7,versicolor 86 | 4.5,1.5,5.4,3.0,versicolor 87 | 4.5,1.6,6.0,3.4,versicolor 88 | 4.7,1.5,6.7,3.1,versicolor 89 | 4.4,1.3,6.3,2.3,versicolor 90 | 4.1,1.3,5.6,3.0,versicolor 91 | 4.0,1.3,5.5,2.5,versicolor 92 | 4.4,1.2,5.5,2.6,versicolor 93 | 4.6,1.4,6.1,3.0,versicolor 94 | 4.0,1.2,5.8,2.6,versicolor 95 | 3.3,1.0,5.0,2.3,versicolor 96 | 4.2,1.3,5.6,2.7,versicolor 97 | 4.2,1.2,5.7,3.0,versicolor 98 | 4.2,1.3,5.7,2.9,versicolor 99 | 4.3,1.3,6.2,2.9,versicolor 100 | 3.0,1.1,5.1,2.5,versicolor 101 | 4.1,1.3,5.7,2.8,versicolor 102 | 6.0,2.5,6.3,3.3,virginica 103 | 5.1,1.9,5.8,2.7,virginica 104 | 5.9,2.1,7.1,3.0,virginica 105 | 5.6,1.8,6.3,2.9,virginica 106 | 5.8,2.2,6.5,3.0,virginica 107 | 6.6,2.1,7.6,3.0,virginica 108 | 4.5,1.7000000000000002,4.9,2.5,virginica 109 | 6.3,1.8,7.3,2.9,virginica 110 | 5.8,1.8,6.7,2.5,virginica 111 | 6.1,2.5,7.2,3.6,virginica 112 | 5.1,2.0,6.5,3.2,virginica 113 | 5.3,1.9,6.4,2.7,virginica 114 | 5.5,2.1,6.8,3.0,virginica 115 | 5.0,2.0,5.7,2.5,virginica 116 | 5.1,2.4,5.8,2.8,virginica 117 | 5.3,2.3,6.4,3.2,virginica 118 | 5.5,1.8,6.5,3.0,virginica 119 | 6.7,2.2,7.7,3.8,virginica 120 | 6.9,2.3,7.7,2.6,virginica 121 | 5.0,1.5,6.0,2.2,virginica 122 | 5.7,2.3,6.9,3.2,virginica 123 | 4.9,2.0,5.6,2.8,virginica 124 | 6.7,2.0,7.7,2.8,virginica 125 | 4.9,1.8,6.3,2.7,virginica 126 | 5.7,2.1,6.7,3.3,virginica 127 | 6.0,1.8,7.2,3.2,virginica 128 | 4.8,1.8,6.2,2.8,virginica 129 | 4.9,1.8,6.1,3.0,virginica 130 | 5.6,2.1,6.4,2.8,virginica 131 | 5.8,1.6,7.2,3.0,virginica 132 | 6.1,1.9,7.4,2.8,virginica 133 | 6.4,2.0,7.9,3.8,virginica 134 | 5.6,2.2,6.4,2.8,virginica 135 | 5.1,1.5,6.3,2.8,virginica 136 | 5.6,1.4,6.1,2.6,virginica 137 | 6.1,2.3,7.7,3.0,virginica 138 | 5.6,2.4,6.3,3.4,virginica 139 | 5.5,1.8,6.4,3.1,virginica 140 | 4.8,1.8,6.0,3.0,virginica 141 | 5.4,2.1,6.9,3.1,virginica 142 | 5.6,2.4,6.7,3.1,virginica 143 | 5.1,2.3,6.9,3.1,virginica 144 | 5.1,1.9,5.8,2.7,virginica 145 | 5.9,2.3,6.8,3.2,virginica 146 | 5.7,2.5,6.7,3.3,virginica 147 | 5.2,2.3,6.7,3.0,virginica 148 | 5.0,1.9,6.3,2.5,virginica 149 | 5.2,2.0,6.5,3.0,virginica 150 | 5.4,2.3,6.2,3.4,virginica 151 | 5.1,1.8,5.9,3.0,virginica 152 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "workspaces": { 4 | "packages": [ 5 | "packages/*" 6 | ] 7 | }, 8 | "scripts": { 9 | "build": "jlpm && lerna bootstrap --hoist && jlpm run build:packages && jlpm run build:packages:post && jlpm run link:packages", 10 | "build:packages": "tsc --build packages/*", 11 | "build:packages:post": "lerna run postBuild", 12 | "build:watch": "jlpm run build:packages --watch --listEmittedFiles", 13 | "clean": "jlpm run clean:jupyter && jlpm clean:packages && jlpm clean:node", 14 | "clean:jupyter": "jlpm run uninstall:extensions && jupyter lab clean", 15 | "clean:node": "lerna clean --yes && rimraf node_modules yarn.lock", 16 | "clean:packages": "lerna run clean", 17 | "link:packages": "jupyter labextension link ./packages/* --no-build", 18 | "lint": "jlpm run lint:css && jlpm run lint:typescript && jlpm run prettier:write", 19 | "lint:check": "jlpm run lint:css:check && jlpm run lint:typescript:check && jlpm run prettier", 20 | "lint:css": "jlpm run lint:css:check --fix", 21 | "lint:css:check": "stylelint packages/**/*.css --config ./etc/stylelint/.stylelintrc.json", 22 | "lint:typescript": "jlpm run lint:typescript:check --fix", 23 | "lint:typescript:check": "eslint . --ext 'ts,tsx' --ignore-path .gitignore --config ./etc/eslint/.eslintrc.js", 24 | "prettier": "prettier . --config ./etc/prettier/.prettierrc --ignore-path .gitignore --check", 25 | "prettier:write": "jlpm run prettier --write", 26 | "rebuild:packages": "jlpm run clean:packages && jlpm run build:packages", 27 | "test": "jlpm run test:packages && jlpm run test:integration", 28 | "test:packages": "lerna run test", 29 | "test:integration": "env JEST_PUPPETEER_CONFIG=./etc/jest/jest-puppeteer.config.js jest --runInBand --config ./etc/jest/jest.config.js", 30 | "test:integration:debug": "env HEADLESS=false SLOWMO=true jlpm test", 31 | "uninstall:extensions": "jupyter labextension uninstall --all" 32 | }, 33 | "husky": { 34 | "hooks": { 35 | "pre-commit": "lint-staged --config ./etc/lint-staged/lint-staged.config.js" 36 | } 37 | }, 38 | "dependencies": {}, 39 | "devDependencies": { 40 | "@rws-air/jestscreenshot": "^4.0.4", 41 | "@types/expect-puppeteer": "^4.4.1", 42 | "@types/jest": "^25.2.1", 43 | "@types/jest-environment-puppeteer": "^4.3.1", 44 | "@types/puppeteer": "^2.0.1", 45 | "@typescript-eslint/eslint-plugin": "^2.27.0", 46 | "@typescript-eslint/parser": "^2.27.0", 47 | "eslint": "^6.1.0", 48 | "eslint-config-prettier": "^6.0.0", 49 | "eslint-plugin-prettier": "^3.1.1", 50 | "eslint-plugin-react": "^7.14.3", 51 | "eslint-plugin-react-hooks": "^3.0.0", 52 | "husky": "^4.2.3", 53 | "jest": "^25.2.7", 54 | "jest-circus": "^25.2.7", 55 | "jest-puppeteer": "^4.3.0", 56 | "lerna": "^3.16.4", 57 | "lint-staged": "^10.1.2", 58 | "prettier": "^2.0.4", 59 | "puppeteer": "^2.0.0", 60 | "rimraf": "^3.0.2", 61 | "stylelint": "^13.3.0", 62 | "stylelint-config-prettier": "^8.0.1", 63 | "stylelint-config-standard": "^20.0.0", 64 | "ts-jest": "^25.3.1", 65 | "typescript": "^3.5.3" 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /packages/dataregistry-csvviewer-extension/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@jupyterlab/dataregistry-csvviewer-extension", 3 | "version": "1.0.0", 4 | "description": "CSV viewer data converter.", 5 | "keywords": [ 6 | "jupyter", 7 | "jupyterlab", 8 | "jupyterlab-extension" 9 | ], 10 | "homepage": "https://github.com/jupyterlab/jupyterlab-data-explorer", 11 | "bugs": { 12 | "url": "https://github.com/jupyterlab/jupyterlab-data-explorer/issues" 13 | }, 14 | "repository": { 15 | "type": "git", 16 | "url": "https://github.com/jupyterlab/jupyterlab-data-explorer.git" 17 | }, 18 | "license": "BSD-3-Clause", 19 | "author": "Project Jupyter", 20 | "files": [ 21 | "lib/**" 22 | ], 23 | "main": "lib/index.js", 24 | "types": "./lib/index.d.ts", 25 | "directories": { 26 | "lib": "./lib" 27 | }, 28 | "scripts": { 29 | "build": "tsc --build", 30 | "clean": "rimraf lib tsconfig.tsbuildinfo", 31 | "prepublishOnly": "npm run clean && npm run build", 32 | "watch": "tsc --build --watch --listEmittedFiles" 33 | }, 34 | "dependencies": { 35 | "@jupyterlab/application": "^2.1.0", 36 | "@jupyterlab/csvviewer": "^2.1.0", 37 | "@lumino/datagrid": "^0.6.0", 38 | "@lumino/messaging": "^1.2.3", 39 | "@lumino/widgets": "^1.9.0", 40 | "rxjs": "^6.5.2" 41 | }, 42 | "devDependencies": { 43 | "@jupyterlab/dataregistry": "^4.0.0", 44 | "@jupyterlab/dataregistry-registry-extension": "^1.0.0" 45 | }, 46 | "publishConfig": { 47 | "access": "public" 48 | }, 49 | "jupyterlab": { 50 | "extension": true 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /packages/dataregistry-csvviewer-extension/src/activate.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @license BSD-3-Clause 3 | * 4 | * Copyright (c) 2019 Project Jupyter Contributors. 5 | * Distributed under the terms of the 3-Clause BSD License. 6 | */ 7 | 8 | import { JupyterFrontEnd } from '@jupyterlab/application'; 9 | import { Registry } from '@jupyterlab/dataregistry'; 10 | import extension2mimetype from './extension_to_mimetype'; 11 | import text2csv from './text_to_csv'; 12 | import csv2datagrid from './csv_to_data_grid'; 13 | 14 | /** 15 | * Activates the plugin. 16 | * 17 | * @private 18 | * @param app - Jupyter front-end application instance 19 | * @param registry - JupyterLab data registry 20 | */ 21 | function activate(app: JupyterFrontEnd, registry: Registry) { 22 | registry.addConverter(extension2mimetype()); 23 | registry.addConverter(text2csv); 24 | registry.addConverter(csv2datagrid); 25 | } 26 | 27 | /** 28 | * Exports. 29 | */ 30 | export default activate; 31 | -------------------------------------------------------------------------------- /packages/dataregistry-csvviewer-extension/src/csv_to_data_grid.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @license BSD-3-Clause 3 | * 4 | * Copyright (c) 2019 Project Jupyter Contributors. 5 | * Distributed under the terms of the 3-Clause BSD License. 6 | */ 7 | 8 | import { createConverter } from '@jupyterlab/dataregistry'; 9 | import datatypes from './datatypes'; // FIXME 10 | import DataGrid from './data_grid'; 11 | import { Widget } from '@lumino/widgets'; 12 | 13 | /** 14 | * Exports. 15 | */ 16 | export default createConverter( 17 | { 18 | from: datatypes.csv, 19 | to: datatypes.widget, 20 | }, 21 | ({ data }) => ({ type: 'Grid', data: (): Widget => new DataGrid(data) }) 22 | ); 23 | -------------------------------------------------------------------------------- /packages/dataregistry-csvviewer-extension/src/data_grid.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @license BSD-3-Clause 3 | * 4 | * Copyright (c) 2019 Project Jupyter Contributors. 5 | * Distributed under the terms of the 3-Clause BSD License. 6 | */ 7 | 8 | import { Observable, Subscription } from 'rxjs'; 9 | import { 10 | BasicKeyHandler, 11 | BasicMouseHandler, 12 | BasicSelectionModel, 13 | DataGrid, 14 | } from '@lumino/datagrid'; 15 | import { Message } from '@lumino/messaging'; 16 | import { DSVModel } from '@jupyterlab/csvviewer'; 17 | 18 | /** 19 | * Class to support the conversion from CSV data to data grid widget data. 20 | * 21 | * @private 22 | */ 23 | class CSVDataGrid extends DataGrid { 24 | private _data: Observable; 25 | private _subscription?: Subscription; 26 | 27 | /** 28 | * Constructor. 29 | * 30 | * @param data - CSV data as an observable 31 | * @returns class instance 32 | */ 33 | constructor(data: Observable) { 34 | super(); 35 | this._data = data; 36 | this.headerVisibility = 'all'; 37 | } 38 | 39 | /** 40 | * Callback invoked upon receiving a `'before-attach'` message. 41 | * 42 | * @param msg - message 43 | */ 44 | protected onBeforeAttach(msg: Message): void { 45 | super.onBeforeAttach(msg); 46 | 47 | /** 48 | * Callback invoked upon changes to the CSV data. 49 | * 50 | * @private 51 | * @param data - CSV data 52 | */ 53 | const onData = (data: string): void => { 54 | if (this.dataModel) { 55 | (this.dataModel as DSVModel).dispose(); 56 | } 57 | this.dataModel = new DSVModel({ 58 | data: data, 59 | delimiter: ',', 60 | }); 61 | this.keyHandler = new BasicKeyHandler(); 62 | this.mouseHandler = new BasicMouseHandler(); 63 | this.selectionModel = new BasicSelectionModel({ 64 | dataModel: this.dataModel, 65 | }); 66 | }; 67 | this._subscription = this._data.subscribe(onData); 68 | } 69 | 70 | /** 71 | * Callback invoked upon receiving a `'before-detach'` message. 72 | * 73 | * @param msg - message 74 | */ 75 | protected onBeforeDetach(msg: Message): void { 76 | this._subscription && this._subscription.unsubscribe(); 77 | super.onBeforeDetach(msg); 78 | } 79 | } 80 | 81 | /** 82 | * Exports. 83 | */ 84 | export default CSVDataGrid; 85 | -------------------------------------------------------------------------------- /packages/dataregistry-csvviewer-extension/src/datatypes.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @license BSD-3-Clause 3 | * 4 | * Copyright (c) 2019 Project Jupyter Contributors. 5 | * Distributed under the terms of the 3-Clause BSD License. 6 | */ 7 | 8 | import { DataTypeNoArgs, DataTypeStringArg } from '@jupyterlab/dataregistry'; 9 | import { Widget } from '@lumino/widgets'; 10 | import { Observable } from 'rxjs'; 11 | 12 | // TODO: refactor 13 | 14 | /** 15 | * Table of data registry data types. 16 | * 17 | * ## Notes 18 | * 19 | * - See [MDN][1] for MIME type information. 20 | * 21 | * [1]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types 22 | */ 23 | const datatypes = { 24 | csv: new DataTypeNoArgs>('text/csv'), 25 | text: new DataTypeStringArg>('text/plain', 'mimeType'), 26 | widget: new DataTypeStringArg<() => Widget>( 27 | 'application/x.jupyter.widget', 28 | 'label' 29 | ), 30 | }; 31 | 32 | /** 33 | * Exports. 34 | */ 35 | export default datatypes; 36 | -------------------------------------------------------------------------------- /packages/dataregistry-csvviewer-extension/src/extension_to_mimetype.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @license BSD-3-Clause 3 | * 4 | * Copyright (c) 2019 Project Jupyter Contributors. 5 | * Distributed under the terms of the 3-Clause BSD License. 6 | */ 7 | 8 | import { resolveExtensionConverter, Converter } from '@jupyterlab/dataregistry'; 9 | import datatypes from './datatypes'; // FIXME 10 | 11 | /** 12 | * Returns a converter for converting from a resolver MIME type to a file MIME type. 13 | * 14 | * @private 15 | * @returns data type converter 16 | */ 17 | function extension2mimetype(): Converter { 18 | return resolveExtensionConverter('.csv', datatypes.csv.createMimeType()); 19 | } 20 | 21 | /** 22 | * Exports. 23 | */ 24 | export default extension2mimetype; 25 | -------------------------------------------------------------------------------- /packages/dataregistry-csvviewer-extension/src/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @license BSD-3-Clause 3 | * 4 | * Copyright (c) 2019 Project Jupyter Contributors. 5 | * Distributed under the terms of the 3-Clause BSD License. 6 | */ 7 | 8 | import { JupyterFrontEndPlugin } from '@jupyterlab/application'; 9 | import { IRegistry } from '@jupyterlab/dataregistry-registry-extension'; 10 | import activate from './activate'; 11 | 12 | /** 13 | * Plugin registration data. 14 | */ 15 | const extension: JupyterFrontEndPlugin = { 16 | id: '@jupyterlab/dataregistry-extension:csv-viewer', 17 | activate: activate, 18 | autoStart: true, 19 | requires: [IRegistry], 20 | }; 21 | 22 | /** 23 | * Exports. 24 | */ 25 | export default extension; 26 | -------------------------------------------------------------------------------- /packages/dataregistry-csvviewer-extension/src/text_to_csv.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @license BSD-3-Clause 3 | * 4 | * Copyright (c) 2019 Project Jupyter Contributors. 5 | * Distributed under the terms of the 3-Clause BSD License. 6 | */ 7 | 8 | import { createConverter } from '@jupyterlab/dataregistry'; 9 | import datatypes from './datatypes'; // FIXME 10 | 11 | // Generate the CSV MIME type: 12 | const CSV_MIME_TYPE: string = datatypes.csv.createMimeType(); 13 | 14 | /** 15 | * Exports. 16 | */ 17 | export default createConverter( 18 | { 19 | from: datatypes.text, 20 | to: datatypes.csv, 21 | }, 22 | ({ type, data }) => { 23 | if (type === CSV_MIME_TYPE) { 24 | return data; 25 | } 26 | return null; 27 | } 28 | ); 29 | -------------------------------------------------------------------------------- /packages/dataregistry-csvviewer-extension/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfigbase", 3 | "compilerOptions": { 4 | "outDir": "./lib", 5 | "rootDir": "./src", 6 | "skipLibCheck": true, 7 | "sourceRoot": "./@jupyterlab/dataregistry-csvviewer-extension/src", 8 | "types": ["node"] 9 | }, 10 | "include": ["src/**/*"], 11 | "references": [ 12 | { 13 | "path": "../dataregistry" 14 | }, 15 | { 16 | "path": "../dataregistry-registry-extension" 17 | } 18 | ] 19 | } 20 | -------------------------------------------------------------------------------- /packages/dataregistry-extension/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@jupyterlab/dataregistry-extension", 3 | "version": "4.0.0", 4 | "description": "Datasets as first class entities in Juptyerlab.", 5 | "keywords": [ 6 | "jupyter", 7 | "jupyterlab", 8 | "jupyterlab-extension" 9 | ], 10 | "homepage": "https://github.com/jupyterlab/jupyterlab-data-explorer", 11 | "bugs": { 12 | "url": "https://github.com/jupyterlab/jupyterlab-data-explorer/issues" 13 | }, 14 | "repository": { 15 | "type": "git", 16 | "url": "https://github.com/jupyterlab/jupyterlab-data-explorer.git" 17 | }, 18 | "license": "BSD-3-Clause", 19 | "author": "Project Jupyter", 20 | "files": [ 21 | "lib/**", 22 | "style.css" 23 | ], 24 | "main": "lib/index.js", 25 | "types": "./lib/index.d.ts", 26 | "style": "./style.css", 27 | "directories": { 28 | "lib": "./lib" 29 | }, 30 | "scripts": { 31 | "build": "tsc --build && jlpm run postBuild", 32 | "postBuild": "jlpm run generateSchema", 33 | "clean": "rimraf lib tsconfig.tsbuildinfo", 34 | "generateSchema": "ts-json-schema-generator --type datasetsObjectType --no-type-check -f tsconfig.json > lib/datasets-file.schema.json", 35 | "prepublishOnly": "npm run clean && npm run build", 36 | "watch": "tsc --build --watch --listEmittedFiles" 37 | }, 38 | "dependencies": { 39 | "@jupyterlab/application": "^2.1.0", 40 | "@jupyterlab/apputils": "^2.1.0", 41 | "@jupyterlab/coreutils": "^4.1.0", 42 | "@jupyterlab/csvviewer": "^2.1.0", 43 | "@jupyterlab/docmanager": "^2.1.0", 44 | "@jupyterlab/docregistry": "^2.1.0", 45 | "@jupyterlab/filebrowser": "^2.1.0", 46 | "@jupyterlab/notebook": "^2.1.0", 47 | "@jupyterlab/rendermime": "^2.1.0", 48 | "@lumino/datagrid": "^0.6.0", 49 | "@lumino/messaging": "^1.2.3", 50 | "@lumino/widgets": "^1.8.0", 51 | "@nteract/data-explorer": "8.0.3", 52 | "ajv": "^6.10.2", 53 | "js-yaml": "^3.13.1", 54 | "path": "0.12.7", 55 | "react": "^16.8.4", 56 | "react-inspector": "^5.0.1", 57 | "rxjs": "^6.5.2", 58 | "styled-components": "^5.1.0" 59 | }, 60 | "devDependencies": { 61 | "@jupyterlab/dataregistry": "^4.0.0", 62 | "@jupyterlab/dataregistry-registry-extension": "^1.0.0", 63 | "@types/js-yaml": "^3.12.1", 64 | "ts-json-schema-generator": "0.65.0" 65 | }, 66 | "publishConfig": { 67 | "access": "public" 68 | }, 69 | "jupyterlab": { 70 | "extension": true 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /packages/dataregistry-extension/src/active.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @license BSD-3-Clause 3 | * 4 | * Copyright (c) 2019 Project Jupyter Contributors. 5 | * Distributed under the terms of the 3-Clause BSD License. 6 | */ 7 | 8 | import { 9 | ILabShell, 10 | JupyterFrontEnd, 11 | JupyterFrontEndPlugin, 12 | } from '@jupyterlab/application'; 13 | import { 14 | createConverter, 15 | nestedDataType, 16 | Registry, 17 | resolveDataType, 18 | URL_, 19 | } from '@jupyterlab/dataregistry'; 20 | import { IRegistry } from '@jupyterlab/dataregistry-registry-extension'; 21 | import { IDocumentManager } from '@jupyterlab/docmanager'; 22 | import { Token } from '@lumino/coreutils'; 23 | import { Widget } from '@lumino/widgets'; 24 | import { BehaviorSubject } from 'rxjs'; 25 | import { map } from 'rxjs/operators'; 26 | import { hasURL_ } from './widgets'; 27 | 28 | export type IActiveDataset = BehaviorSubject; 29 | export const IActiveDataset = new Token( 30 | '@jupyterlab/dataregistry:IActiveDataset' 31 | ); 32 | 33 | export const ACTIVE_URL = new URL('active:').toString(); 34 | /** 35 | * The active dataset extension. 36 | */ 37 | export default { 38 | activate, 39 | id: '@jupyterlab/dataregistry-extension:active-dataset', 40 | requires: [ILabShell, IRegistry, IDocumentManager], 41 | provides: IActiveDataset, 42 | autoStart: true, 43 | } as JupyterFrontEndPlugin; 44 | 45 | function activate( 46 | app: JupyterFrontEnd, 47 | labShell: ILabShell, 48 | registry: Registry, 49 | docManager: IDocumentManager 50 | ): IActiveDataset { 51 | const active = new BehaviorSubject(null); 52 | 53 | // Show active datasets in explorer 54 | registry.addConverter( 55 | createConverter( 56 | { from: resolveDataType }, 57 | ({ url }) => { 58 | if (url.toString() !== ACTIVE_URL) { 59 | return null; 60 | } 61 | return { 62 | type: nestedDataType.createMimeType(), 63 | data: active.pipe(map((url) => (url ? new Set([url]) : new Set()))), 64 | }; 65 | } 66 | ) 67 | ); 68 | 69 | // Track active documents open. 70 | labShell.currentChanged.connect((sender, args) => { 71 | active.next(getURL_(docManager, args.newValue)); 72 | }); 73 | return active; 74 | } 75 | 76 | function getURL_( 77 | docManager: IDocumentManager, 78 | widget: Widget | null 79 | ): URL_ | null { 80 | if (widget === null) { 81 | return null; 82 | } 83 | const context = docManager.contextForWidget(widget); 84 | if (context) { 85 | return new URL(context.path, 'file:').toString(); 86 | } 87 | if (hasURL_(widget)) { 88 | return widget.url; 89 | } 90 | return null; 91 | } 92 | -------------------------------------------------------------------------------- /packages/dataregistry-extension/src/browser.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * @license BSD-3-Clause 3 | * 4 | * Copyright (c) 2019 Project Jupyter Contributors. 5 | * Distributed under the terms of the 3-Clause BSD License. 6 | */ 7 | 8 | import React from 'react'; 9 | import { 10 | ILayoutRestorer, 11 | JupyterFrontEnd, 12 | JupyterFrontEndPlugin, 13 | ILabShell, 14 | } from '@jupyterlab/application'; 15 | import { ReactWidget } from '@jupyterlab/apputils'; 16 | import { 17 | Registry, 18 | relativeNestedDataType, 19 | nestedDataType, 20 | URL_, 21 | } from '@jupyterlab/dataregistry'; 22 | import { IRegistry } from '@jupyterlab/dataregistry-registry-extension'; 23 | import { Widget } from '@lumino/widgets'; 24 | import { widgetDataType, reactDataType } from './widgets'; 25 | import { IActiveDataset } from '.'; 26 | import { LuminoWidget } from './utils'; 27 | import { Observable } from 'rxjs'; 28 | 29 | function InnerBrowser({ registry, url }: { registry: Registry; url: URL_ }) { 30 | // An array of all possible child paths after the last selected one 31 | const [children, setChildren] = React.useState>([]); 32 | // An observable of all the children we have 33 | const [children$, setChildren$] = React.useState< 34 | Observable | Array> | undefined 35 | >(undefined); 36 | // The current display label to use, if it exists on the current widget 37 | const [label, setLabel] = React.useState(''); 38 | // The current display creators for the submitted URL 39 | const [widgets, setWidgets] = React.useState(new Map Widget>()); 40 | // The current display creators for the submitted URL 41 | const [components, setComponents] = React.useState( 42 | new Map>() 43 | ); 44 | 45 | // Set the children to be all possible children. 46 | React.useEffect(() => { 47 | setChildren$( 48 | url 49 | ? relativeNestedDataType.getDataset(registry.getURL(url)) || 50 | nestedDataType.getDataset(registry.getURL(url)) 51 | : undefined 52 | ); 53 | }, [url, registry]); 54 | 55 | // Set the children to the subscribed children 56 | React.useEffect(() => { 57 | if (children$) { 58 | const subscription = children$.subscribe({ 59 | next: (value) => { 60 | setChildren([...value]); 61 | }, 62 | }); 63 | return () => subscription.unsubscribe(); 64 | } 65 | setChildren([]); 66 | }, [children$]); 67 | 68 | // Update the available widgets whenever the url changes 69 | React.useEffect(() => { 70 | const dataset = url && registry.getURL(url); 71 | setWidgets(dataset ? widgetDataType.filterDataset(dataset) : new Map()); 72 | setComponents(dataset ? reactDataType.filterDataset(dataset) : new Map()); 73 | }, [url, registry]); 74 | 75 | // Fill in options mapping 76 | const options = new Map(); 77 | 78 | for (const key of widgets.keys()) { 79 | options.set(`view-${key}`, { value: key, type: 'view' }); 80 | } 81 | for (const child of children) { 82 | options.set(`child-${child}`, { 83 | value: child, 84 | type: 'child', 85 | }); 86 | } 87 | 88 | const parsedLabel = options.get(label); 89 | 90 | // update the label to be the first one in the options, if there are some options 91 | // and the current label is not in them 92 | React.useEffect(() => { 93 | if (!options.has(label) && options.size) { 94 | setLabel(options.keys().next().value); 95 | } 96 | }, [label, widgets, children, options]); 97 | 98 | const Component: React.ReactElement | undefined = React.useMemo(() => { 99 | const selected = options.get(label); 100 | if (!selected || selected.type === 'child') { 101 | return; 102 | } 103 | const name = selected.value; 104 | const widgetCreator = widgets.get(name); 105 | return ( 106 | components.get(name) || 107 | (widgetCreator && ) 108 | ); 109 | }, [options, label, components, widgets]); 110 | // Use the widget creator to set the current widget 111 | 112 | return ( 113 | <> 114 | 123 | {parsedLabel && parsedLabel.type === 'child' ? ( 124 | 128 | ) : Component ? ( 129 | Component 130 | ) : ( 131 | 'Select another dataset to view it...' 132 | )} 133 | 134 | ); 135 | } 136 | 137 | function Browser({ 138 | registry, 139 | active, 140 | }: { 141 | registry: Registry; 142 | active: IActiveDataset; 143 | }) { 144 | // Current url in the form 145 | const [url, setURL] = React.useState(active.value || ''); 146 | // Last url we have submitted 147 | const [submittedURL, setSubmittedURL] = React.useState(url); 148 | // Whether to update both urls whenever the active dataset changes 149 | const [follow, setFollow] = React.useState(true); 150 | 151 | // Update the URL when the active changes 152 | React.useEffect(() => { 153 | if (follow) { 154 | const subscription = active.subscribe({ 155 | next: (value) => { 156 | setURL(value || ''); 157 | setSubmittedURL(value || ''); 158 | }, 159 | }); 160 | return (): void => subscription.unsubscribe(); 161 | } 162 | }, [active, follow]); 163 | 164 | return ( 165 |
166 |
{ 168 | setSubmittedURL(url); 169 | event.preventDefault(); 170 | }} 171 | className="jl-dr-browser-url" 172 | > 173 | setURL(event.target.value)} 178 | className="jl-dr-browser-url-text" 179 | /> 180 | 181 |
182 | 195 | 196 |
197 | ); 198 | } 199 | 200 | export default { 201 | activate, 202 | id: '@jupyterlab/dataregistry-extension:browser', 203 | requires: [ILabShell, IRegistry, ILayoutRestorer, IActiveDataset], 204 | autoStart: true, 205 | } as JupyterFrontEndPlugin; 206 | 207 | function activate( 208 | app: JupyterFrontEnd, 209 | labShell: ILabShell, 210 | registry: Registry, 211 | restorer: ILayoutRestorer, 212 | active: IActiveDataset 213 | ): void { 214 | const content = ReactWidget.create( 215 | 216 | ); 217 | content.id = '@jupyterlab-dataregistry/browser'; 218 | content.title.iconClass = 'jp-SpreadsheetIcon jp-SideBar-tabIcon'; 219 | content.title.caption = 'Data Browser'; 220 | 221 | restorer.add(content, content.id); 222 | labShell.add(content, 'right'); 223 | } 224 | -------------------------------------------------------------------------------- /packages/dataregistry-extension/src/datatypes.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @license BSD-3-Clause 3 | * 4 | * Copyright (c) 2019 Project Jupyter Contributors. 5 | * Distributed under the terms of the 3-Clause BSD License. 6 | */ 7 | 8 | import { DataTypeNoArgs, DataTypeStringArg } from '@jupyterlab/dataregistry'; 9 | import { INotebookModel } from '@jupyterlab/notebook'; 10 | import { DocumentRegistry, Context } from '@jupyterlab/docregistry'; 11 | import { Widget } from '@lumino/widgets'; 12 | import { Observable } from 'rxjs'; 13 | 14 | /** 15 | * Interface describing a dataset. 16 | */ 17 | interface Dataset { 18 | /** 19 | * Dataset URL. 20 | */ 21 | url: string; 22 | 23 | /** 24 | * List of child dataset identifiers. 25 | */ 26 | children?: Array; 27 | 28 | /** 29 | * Dataset label. 30 | */ 31 | label?: string; 32 | 33 | /** 34 | * Code snippets. 35 | */ 36 | snippets?: { [key: string]: string }; 37 | } 38 | 39 | /** 40 | * Interface for describing datasets. 41 | * 42 | * ## Notes 43 | * 44 | * - Each dataset may consist of (and link to) other datasets. 45 | */ 46 | interface Datasets { 47 | /** 48 | * List of child dataset identifiers. 49 | */ 50 | children?: Array; 51 | 52 | /** 53 | * List of datasets. 54 | */ 55 | datasets?: Array; 56 | } 57 | 58 | /** 59 | * Table of data registry data types. 60 | * 61 | * ## Notes 62 | * 63 | * - See [MDN][1] for MIME type information. 64 | * 65 | * [1]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types 66 | */ 67 | const datatypes = { 68 | csv: new DataTypeNoArgs>('text/csv'), 69 | datagrid: new DataTypeNoArgs>( 70 | 'application/x.lumino.datagrid' 71 | ), 72 | datasetsFile: new DataTypeNoArgs>( 73 | 'application/x.jupyterlab.datasets-file' 74 | ), 75 | label: new DataTypeNoArgs>( 76 | 'application/x.jupyterlab.label' 77 | ), 78 | notebookContext: new DataTypeNoArgs>>( 79 | 'application/x.jupyterlab.notebook-context' 80 | ), 81 | text: new DataTypeStringArg>('text/plain', 'mimeType'), 82 | textContext: new DataTypeStringArg< 83 | Observable> 84 | >('application/x.jupyterlab.text-context', 'mimeType'), 85 | widget: new DataTypeStringArg<() => Widget>( 86 | 'application/x.jupyter.widget', 87 | 'label' 88 | ), 89 | }; 90 | 91 | /** 92 | * Exports. 93 | */ 94 | export { Datasets }; 95 | export default datatypes; 96 | -------------------------------------------------------------------------------- /packages/dataregistry-extension/src/debugger.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * @license BSD-3-Clause 3 | * 4 | * Copyright (c) 2019 Project Jupyter Contributors. 5 | * Distributed under the terms of the 3-Clause BSD License. 6 | */ 7 | 8 | import { 9 | JupyterFrontEnd, 10 | JupyterFrontEndPlugin, 11 | ILayoutRestorer, 12 | } from '@jupyterlab/application'; 13 | import { Inspector } from 'react-inspector'; 14 | import { 15 | ReactWidget, 16 | ICommandPalette, 17 | MainAreaWidget, 18 | WidgetTracker, 19 | } from '@jupyterlab/apputils'; 20 | import { Registry, CachedObservable } from '@jupyterlab/dataregistry'; 21 | import { IRegistry } from '@jupyterlab/dataregistry-registry-extension'; 22 | import React from 'react'; 23 | 24 | import { UseBehaviorSubject } from './utils'; 25 | 26 | const id = '@jupyterlab/dataregistry-extension:data-debugger'; 27 | 28 | class ErrorBoundary extends React.Component { 29 | constructor(props: any) { 30 | super(props); 31 | this.state = { hasError: false }; 32 | } 33 | 34 | static getDerivedStateFromError(error: any) { 35 | // Update state so the next render will show the fallback UI. 36 | return { hasError: true }; 37 | } 38 | 39 | render() { 40 | if (this.state.hasError) { 41 | // You can render any custom fallback UI 42 | return

Something went wrong.

; 43 | } 44 | 45 | return this.props.children; 46 | } 47 | } 48 | function Data({ data }: { data: unknown }) { 49 | if (data instanceof CachedObservable) { 50 | return ( 51 | 52 | {(data_) => } 53 | 54 | ); 55 | } 56 | return ; 57 | } 58 | 59 | function Debugger({ registry }: { registry: Registry }) { 60 | return ( 61 |
62 |
    63 | 64 | {(urls) => 65 | [...urls].sort().map((url) => ( 66 |
  1. 67 | {url} 68 |
      69 | {[...registry.getURL(url).entries()].map( 70 | ([mimeType, [cost, data]]) => ( 71 |
    1. 72 | {mimeType} 73 | 74 | 75 | 76 |
    2. 77 | ) 78 | )} 79 |
    80 |
  2. 81 | )) 82 | } 83 |
    84 |
85 |
86 | ); 87 | } 88 | /** 89 | * Adds a visual data debugger. 90 | */ 91 | export default { 92 | activate, 93 | id, 94 | requires: [IRegistry, ILayoutRestorer, ICommandPalette], 95 | autoStart: true, 96 | } as JupyterFrontEndPlugin; 97 | 98 | function activate( 99 | app: JupyterFrontEnd, 100 | registry: Registry, 101 | restorer: ILayoutRestorer, 102 | palette: ICommandPalette 103 | ): void { 104 | // Declare a widget variable 105 | let widget: MainAreaWidget; 106 | 107 | // Add an application command 108 | const command = 'dataregistry-debugger:open'; 109 | app.commands.addCommand(command, { 110 | label: 'Data Debugger', 111 | execute: () => { 112 | if (!widget) { 113 | // Create a new widget if one does not exist 114 | const content = ReactWidget.create(); 115 | content.addClass('scrollable'); 116 | widget = new MainAreaWidget({ content }); 117 | widget.id = 'dataregistry-debugger'; 118 | widget.title.label = 'Data Debugger'; 119 | widget.title.closable = true; 120 | } 121 | if (!tracker.has(widget)) { 122 | // Track the state of the widget for later restoration 123 | tracker.add(widget); 124 | } 125 | if (!widget.isAttached) { 126 | // Attach the widget to the main work area if it's not there 127 | app.shell.add(widget, 'main'); 128 | } 129 | widget.content.update(); 130 | 131 | // Activate the widget 132 | app.shell.activateById(widget.id); 133 | }, 134 | }); 135 | 136 | // Add the command to the palette. 137 | palette.addItem({ command, category: 'Data Registry' }); 138 | 139 | // Track and restore the widget state 140 | const tracker = new WidgetTracker>({ 141 | namespace: 'dataregistry-debugger', 142 | }); 143 | restorer.restore(tracker, { 144 | command, 145 | name: () => 'dataregistry-debugger', 146 | }); 147 | } 148 | -------------------------------------------------------------------------------- /packages/dataregistry-extension/src/documents.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @license BSD-3-Clause 3 | * 4 | * Copyright (c) 2019 Project Jupyter Contributors. 5 | * Distributed under the terms of the 3-Clause BSD License. 6 | */ 7 | 8 | import { IDocumentManager } from '@jupyterlab/docmanager'; 9 | import { IRegistry } from '@jupyterlab/dataregistry-registry-extension'; 10 | import { 11 | JupyterFrontEnd, 12 | JupyterFrontEndPlugin, 13 | } from '@jupyterlab/application'; 14 | import { 15 | Registry, 16 | DataTypeStringArg, 17 | fileDataType, 18 | createConverter, 19 | DataTypeNoArgs, 20 | resolveExtensionConverter, 21 | textDataType, 22 | } from '@jupyterlab/dataregistry'; 23 | import { Observable, defer } from 'rxjs'; 24 | import { DocumentRegistry, Context } from '@jupyterlab/docregistry'; 25 | import { INotebookModel } from '@jupyterlab/notebook'; 26 | import { observableStringToObservable } from './observables'; 27 | import { switchMap } from 'rxjs/operators'; 28 | 29 | export const textContextDataType = new DataTypeStringArg< 30 | Observable> 31 | >('application/x.jupyterlab.text-context', 'mimeType'); 32 | 33 | export const notebookContextDataType = new DataTypeNoArgs< 34 | Observable> 35 | >('application/x.jupyterlab.notebook-context'); 36 | 37 | async function getContext( 38 | docmanager: any, // eslint-disable-line @typescript-eslint/no-explicit-any 39 | path: string, 40 | factoryName: string 41 | ): Promise> { 42 | // The doc manager doesn't expose a way to get a context without also opening a widget, so we have to duplicate some 43 | // logic from `_createOrOpenDocument` and use private methods. 44 | let context: Context = docmanager._findContext( 45 | path, 46 | factoryName 47 | ); 48 | if (!context) { 49 | context = docmanager._createContext( 50 | path, 51 | docmanager.registry.getModelFactory(factoryName), 52 | docmanager.registry.getKernelPreference(path, 'Kernel') 53 | ); 54 | await context.initialize(false); 55 | } 56 | return context; 57 | } 58 | 59 | const notebookMimeType = 'application/x.jupyterlab.notebook'; 60 | function activate( 61 | app: JupyterFrontEnd, 62 | registry: Registry, 63 | docmanager: IDocumentManager 64 | ): void { 65 | registry.addConverter( 66 | resolveExtensionConverter('.ipynb', notebookMimeType), 67 | createConverter( 68 | { from: fileDataType, to: textContextDataType }, 69 | ({ data, type }) => ({ 70 | type, 71 | data: defer(() => getContext(docmanager, data, 'text')), 72 | }) 73 | ), 74 | createConverter( 75 | { from: fileDataType, to: notebookContextDataType }, 76 | ({ data, type }) => 77 | type === notebookMimeType 78 | ? defer( 79 | () => 80 | getContext(docmanager, data, 'notebook') as Promise< 81 | Context 82 | > 83 | ) 84 | : null 85 | ), 86 | createConverter( 87 | { from: textContextDataType, to: textDataType }, 88 | ({ data, type }) => ({ 89 | type, 90 | data: data.pipe( 91 | switchMap((context) => 92 | observableStringToObservable(context.model.value) 93 | ) 94 | ), 95 | }) 96 | ) 97 | ); 98 | } 99 | 100 | export default { 101 | id: '@jupyterlab/dataregistry-extension:documents', 102 | requires: [IRegistry, IDocumentManager], 103 | activate, 104 | autoStart: true, 105 | } as JupyterFrontEndPlugin; 106 | -------------------------------------------------------------------------------- /packages/dataregistry-extension/src/explorer.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * @license BSD-3-Clause 3 | * 4 | * Copyright (c) 2019 Project Jupyter Contributors. 5 | * Distributed under the terms of the 3-Clause BSD License. 6 | */ 7 | 8 | import React from 'react'; 9 | import { Observable, of, combineLatest } from 'rxjs'; 10 | import { map } from 'rxjs/operators'; 11 | import { classes } from 'typestyle'; 12 | import { Token } from '@lumino/coreutils'; 13 | import { Widget } from '@lumino/widgets'; 14 | import { ReactWidget } from '@jupyterlab/apputils'; 15 | import { 16 | JupyterFrontEnd, 17 | JupyterFrontEndPlugin, 18 | ILabShell, 19 | ILayoutRestorer, 20 | } from '@jupyterlab/application'; 21 | import { 22 | Registry, 23 | URL_, 24 | ObservableSet, 25 | nestedDataType, 26 | DataTypeNoArgs, 27 | externalURLDataType, 28 | } from '@jupyterlab/dataregistry'; 29 | import { IRegistry } from '@jupyterlab/dataregistry-registry-extension'; 30 | import { IActiveDataset, ACTIVE_URL } from './active'; 31 | import { UseObservable } from './utils'; 32 | import { viewerDataType } from './viewers'; 33 | 34 | export const labelDataType = new DataTypeNoArgs>( 35 | 'application/x.jupyterlab.label' 36 | ); 37 | 38 | function Button({ onClick, text }: { onClick: () => void; text: string }) { 39 | return ( 40 | 49 | ); 50 | } 51 | 52 | /** 53 | * Shows/hides the children based on a button 54 | */ 55 | class Collapsable extends React.Component< 56 | { children: React.ReactElement }, 57 | { collapsed: boolean } 58 | > { 59 | state: { collapsed: boolean } = { 60 | collapsed: true, 61 | }; 62 | 63 | render() { 64 | if (this.state.collapsed) { 65 | return ( 66 |