├── .editorconfig
├── .github
├── ISSUE_TEMPLATE
│ ├── bug_report.md
│ └── feature_request.md
├── PULL_REQUEST_TEMPLATE.md
└── workflows
│ └── test.yml
├── .gitignore
├── .npmrc
├── .yarnrc
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── binder
├── postBuild
└── requirements.txt
├── datasets.yml
├── docs
├── development.md
├── img
│ ├── interface.png
│ ├── notebook.png
│ └── screenshot.png
└── usage.md
├── etc
├── jest
│ ├── jest-environment.js
│ ├── jest-puppeteer.config.js
│ └── jest.config.js
├── lint-staged
│ └── lint-staged.config.js
├── prettier
│ ├── .prettierignore
│ └── .prettierrc
├── stylelint
│ └── .stylelintrc.json
└── tslint
│ └── tslint.json
├── notebooks
└── demo.ipynb
├── package.json
├── press_release.md
├── src
├── default_graph.ts
├── find_entity.ts
├── index.ts
├── internal_url.tsx
├── linked_data_browser.tsx
├── linked_data_registry.ts
├── node_entry.tsx
├── node_object.tsx
├── sample_provider.ts
├── types.ts
├── value_object.tsx
└── viewer.tsx
├── style.css
├── test
└── ui
│ └── test.ts
├── tsconfig.json
└── tsconfig.test.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 |
25 | # Set properties for TypeScript files:
26 | [*.ts]
27 | indent_style = space
28 | indent_size = 2
29 |
30 | # Set properties for TSX files:
31 | [*.tsx]
32 | indent_style = space
33 | indent_size = 2
34 |
35 | # Set properties for Python files:
36 | [*.py]
37 | indent_style = space
38 | indent_size = 4
39 |
40 | # Set properties for Julia files:
41 | [*.jl]
42 | indent_style = tab
43 |
44 | # Set properties for R files:
45 | [*.R]
46 | indent_style = tab
47 |
48 | # Set properties for C files:
49 | [*.c]
50 | indent_style = tab
51 |
52 | # Set properties for C header files:
53 | [*.h]
54 | indent_style = tab
55 |
56 | # Set properties for C++ files:
57 | [*.cpp]
58 | indent_style = tab
59 |
60 | # Set properties for C++ header files:
61 | [*.hpp]
62 | indent_style = tab
63 |
64 | # Set properties for Fortran files:
65 | [*.f]
66 | indent_style = space
67 | indent_size = 2
68 | insert_final_newline = false
69 |
70 | # Set properties for shell files:
71 | [*.sh]
72 | indent_style = tab
73 |
74 | # Set properties for AWK files:
75 | [*.awk]
76 | indent_style = tab
77 |
78 | # Set properties for HTML files:
79 | [*.html]
80 | indent_style = tab
81 | tab_width = 2
82 |
83 | # Set properties for CSS files:
84 | [*.css]
85 | indent_style = tab
86 |
87 | # Set properties for Makefiles:
88 | [Makefile]
89 | indent_style = tab
90 |
91 | [*.mk]
92 | indent_style = tab
93 |
94 | # Set properties for Markdown files:
95 | [*.md]
96 | indent_style = space
97 | indent_size = 4
98 | trim_trailing_whitespace = false
99 |
100 | # Set properties for `package.json` files:
101 | [package.json]
102 | indent_style = space
103 | indent_size = 2
104 |
105 | # Set properties for `datapackage.json` files:
106 | [datapackage.json]
107 | indent_style = space
108 | indent_size = 2
109 |
110 | # Set properties for `lerna.json` files:
111 | [lerna.json]
112 | indent_style = space
113 | indent_size = 2
114 |
115 | # Set properties for `tslint.json` files:
116 | [tslint.json]
117 | indent_style = space
118 | indent_size = 2
119 |
120 | # Set properties for `tsconfig.json` files:
121 | [tsconfig.json]
122 | indent_style = space
123 | indent_size = 2
124 |
125 | # Set properties for LaTeX files:
126 | [*.tex]
127 | indent_style = tab
128 |
129 | # Set properties for LaTeX Bibliography files:
130 | [*.bib]
131 | indent_style = tab
132 |
133 | # Set properties for YAML files:
134 | [*.yml]
135 | indent_style = space
136 | indent_size = 2
137 |
--------------------------------------------------------------------------------
/.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-metadata-service/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 | steps:
20 | - uses: actions/checkout@v1
21 | - uses: actions/setup-python@v1
22 | with:
23 | python-version: "3.6"
24 | - uses: actions/setup-node@v1
25 | with:
26 | node-version: "10.x"
27 | - run: python -m pip install --upgrade pip
28 | - run: pip install jupyterlab
29 | - run: jlpm run build
30 | - run: jupyter labextension install . @jupyterlab/dataregistry-extension --debug-log-path log.txt
31 | - if: failure()
32 | run: cat log.txt
33 | - run: jlpm run test
34 | - name: upload screenshots
35 | if: failure()
36 | uses: actions/upload-artifact@v1
37 | with:
38 | name: screenshots
39 | path: screenshots
40 |
--------------------------------------------------------------------------------
/.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 | # Byte-compiled / optimized / DLL files
9 | __pycache__/
10 | *.py[cod]
11 | *$py.class
12 |
13 | # C extensions
14 | *.so
15 |
16 | # Distribution / packaging
17 | .Python
18 | build/
19 | develop-eggs/
20 | dist/
21 | downloads/
22 | eggs/
23 | .eggs/
24 | lib/
25 | lib64/
26 | parts/
27 | sdist/
28 | var/
29 | wheels/
30 | *.egg-info/
31 | .installed.cfg
32 | *.egg
33 | MANIFEST
34 |
35 | # PyInstaller
36 | # Usually these files are written by a python script from a template
37 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
38 | *.manifest
39 | *.spec
40 |
41 | # Installer logs
42 | pip-log.txt
43 | pip-delete-this-directory.txt
44 |
45 | # Unit test / coverage reports
46 | htmlcov/
47 | .tox/
48 | .coverage
49 | .coverage.*
50 | .cache
51 | nosetests.xml
52 | coverage.xml
53 | *.cover
54 | .hypothesis/
55 | .pytest_cache/
56 |
57 | # Translations
58 | *.mo
59 | *.pot
60 |
61 | # Django stuff:
62 | *.log
63 | local_settings.py
64 | db.sqlite3
65 |
66 | # Flask stuff:
67 | instance/
68 | .webassets-cache
69 |
70 | # Scrapy stuff:
71 | .scrapy
72 |
73 | # Sphinx documentation
74 | docs/_build/
75 |
76 | # PyBuilder
77 | target/
78 |
79 | # Jupyter Notebook
80 | .ipynb_checkpoints
81 |
82 | # pyenv
83 | .python-version
84 |
85 | # celery beat schedule file
86 | celerybeat-schedule
87 |
88 | # SageMath parsed files
89 | *.sage.py
90 |
91 | # Environments
92 | .env
93 | .venv
94 | env/
95 | venv/
96 | ENV/
97 | env.bak/
98 | venv.bak/
99 |
100 | # Spyder project settings
101 | .spyderproject
102 | .spyproject
103 |
104 | # Rope project settings
105 | .ropeproject
106 |
107 | # mkdocs documentation
108 | /site
109 |
110 | # mypy
111 | .mypy_cache/
112 | *.bundle.*
113 | lib/
114 | node_modules/
115 | *.egg-info/
116 | .ipynb_checkpoints
117 |
118 | # npm
119 | yarn.lock
120 | package-lock.json
121 | screenshots
122 |
--------------------------------------------------------------------------------
/.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
--------------------------------------------------------------------------------
/.yarnrc:
--------------------------------------------------------------------------------
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 [yarn][1].
9 | #
10 | # [1]: https://yarnpkg.com/lang/en/docs/yarnrc/
11 |
12 | # Disable the creation of a lock file:
13 | --install.no-lockfile true
14 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 |
9 |
10 | # Contribution Guidelines
11 |
12 | > Project contribution guidelines.
13 |
14 | ## Introduction
15 |
16 | First off, thanks for your interest! While this guide focuses on technical development, if you are looking to contribute to the project but are non-technical, you can still contribute! For example, you can contribute by filing issues, writing feature requests, updating documentation, providing build and infrastructure support, and helping market and promote the project, among other things. Every bit helps, and we are grateful for your time and effort!
17 |
18 | ## Code of Conduct
19 |
20 | **Before** contributing, read the [Code of Conduct][jupyter-code-of-conduct], which details the _bare minimum_ behavior expectations that the project requires of its contributors.## Contributions
21 |
22 | ### Issues
23 |
24 | When filing new issues and commenting on existing issues on this repository, please ensure that discussions are related to concrete technical issues.
25 |
26 | **Before** filing a potential bug report,
27 |
28 | - Search for existing issues and pull requests.
29 | - Try some debugging techniques to help isolate the problem, including logging inputs and outputs.
30 |
31 | If the source of the problem is a third party package, file a bug report with the relevant package author, rather than on this repository.
32 |
33 | When filing an issue, provide the following, where possible:
34 |
35 | - A description of the issue.
36 | - Links to any related issues.
37 | - The full error message, including the stacktrace.
38 | - The sequence of steps required to reproduce the issue.
39 | - A minimal working example; i.e., the smallest chunk of code that triggers the error. If the code is larger than `50` lines, consider creating a [gist][github-gist].
40 | - The expected results.
41 | - List of affected environments; e.g., browser, browser version, `npm` version, Node.js version, operating system, and the project version.
42 |
43 | When pasting code blocks or output, use triple backticks to enable proper formatting. Surround inline code with single backticks. For other Markdown formatting tips and trips, see GitHub's [Markdown guide][github-markdown-guide].
44 |
45 | Be aware that the `@` symbol tags users on GitHub, so **always** surround package names with backticks (e.g., `@jupyterlab/metadata-extension`).
46 |
47 | ### Code
48 |
49 | > By contributing code to the project, you are agreeing to release it under the project [license][license].
50 |
51 | **Before** contributing code, be sure to
52 |
53 | - read and understand the [licensing terms][license].
54 |
55 | For instructions on how to setup and configure your environment, be sure to
56 |
57 | - read and follow the [development guide][development-guide].
58 |
59 | If you want to contribute a new feature or a breaking change to this project, be sure to
60 |
61 | - file an issue detailing the proposed change.
62 | - wait for feature request approval.
63 | - adhere to the guidance set forth in the feature request comments.
64 |
65 | If you are unfamiliar with [Git][git], the version control system used by GitHub and this project,
66 |
67 | - see the [Git][git] docs.
68 | - try a tutorial, such as the [tutorial][github-git-tutorial] provided by GitHub.
69 |
70 | Next, take a look around the project, noting the style and organization of documentation, tests, examples, and source implementations. Consistency is highly **prioritized** within this project. Thus, the more you are able to match and adhere to project conventions and style, the more likely your contribution will be accepted. While we have done our best to automate linting and style guidelines, such automation is not perfect and cannot adequately capture the inevitable exceptions and nuance to many rules. In short, the more you study existing practice, the better prepared you will be to contribute to this project.
71 |
72 | #### Step 0: GitHub
73 |
74 | Create a [GitHub account][github-signup]. The project uses GitHub exclusively for hosting source code, managing issues and pull requests, triggering continuous integration, and reporting.
75 |
76 | #### Step 1: Fork
77 |
78 | [Fork][github-fork] the repository on GitHub and clone the repository to your local machine.
79 |
80 | ```bash
81 | $ git clone https://github.com//juptyerlab-metadata-service.git
82 | ```
83 |
84 | where `` is your GitHub username. 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 clone [depth][git-clone-depth].
85 |
86 | ```bash
87 | $ git clone --depth= https://github.com//juptyerlab-metadata-service.git
88 | ```
89 |
90 | where `` refers to the number of commits you want to download (as few as `1` and as many as the entire project history).
91 |
92 | If you are behind a firewall, you may need to use the `https` protocol, rather than the `git` protocol.
93 |
94 | ```bash
95 | $ git config --global url."https://".insteadOf git://
96 | ```
97 |
98 | Once you have finished cloning the repository into the destination directory, you should see the folder `jupyterlab-metadata-service`. To proceed with configuring your environment, navigate to the project folder.
99 |
100 | ```bash
101 | $ cd jupyterlab-metadata-service
102 | ```
103 |
104 | And finally, add an `upstream` [remote][git-remotes] to allow syncing changes between this repository and your local version.
105 |
106 | ```bash
107 | $ git remote add upstream git://github.com/jupyterlab/jupyterlab-metadata-service.git
108 | ```
109 |
110 | #### Step 2: Branch
111 |
112 | For modifications intended to be included in this repository, create a new local branch.
113 |
114 | ```bash
115 | $ git checkout -b
116 | ```
117 |
118 | where `` is the branch name. The `master` branch for this repository is protected, and direct modifications to this branch will **not** be accepted. Instead, all contributions should be made on non-master local branches, including documentation changes and other non-code modifications.
119 |
120 | #### Step 3: Write
121 |
122 | Start making your changes and/or implementing the new feature.
123 |
124 | #### Step 4: Commit
125 |
126 | Ensure that you have configured [Git][git] to know your name and email address.
127 |
128 | ```bash
129 | $ git config --global user.name "Jane Doe"
130 | $ git config --global user.email "jane.doe@example.com"
131 | ```
132 |
133 | Add changed files and commit.
134 |
135 | ```bash
136 | $ git add files/which/changed
137 | $ git commit
138 | ```
139 |
140 | #### Step 5: Sync
141 |
142 | To incorporate recent changes from the `upstream` repository during development, you should [rebase][git-rebase] your local branch, reapplying your local commits on top of the current upstream `HEAD`. This procedure is in contrast to performing a standard [merge][git-merge], which may interleave development histories. The rationale is twofold:
143 |
144 | 1. interleaved histories make [squashing][git-rewriting-history] commits more difficult
145 | 2. a standard merge increases the risk of incomplete/broken commits appearing in the Git history.
146 |
147 | An ideal commit history is one in which, at no point in time, is the project in a broken state. While not always possible (mistakes happen), striving for this ideal facilitates time travel and software archeology.
148 |
149 | ```bash
150 | $ git fetch upstream
151 | $ git rebase upstream/develop
152 | ```
153 |
154 | #### Step 6: Test
155 |
156 | Tests should accompany **all** bug fixes and features. For guidance on how to write tests, consult existing tests within the project.
157 |
158 | **Before** submitting a [pull request][github-pull-request] to the `upstream` repository, ensure that all tests pass, including linting.
159 |
160 | Any [pull requests][github-pull-request] which include failing tests and/or lint errors will **not** be accepted.
161 |
162 | To run the tests:
163 |
164 | ```bash
165 | $ jlpm run test
166 | ```
167 |
168 | You can also run the tests with a browser GUI for debugging with:
169 |
170 | ```bash
171 | $ jlpm run test:debug
172 | ```
173 |
174 | If a test fails, a screenshot will be taken of the current state of the browser and
175 | saved in the `./screenshots` folder for debugging.
176 |
177 | If they fail in CI, this folder will be provided as an archive you can download from the Github Actions UI.
178 |
179 | #### Step 7: Push
180 |
181 | Push your changes to your remote GitHub repository.
182 |
183 | ```bash
184 | $ git push origin
185 | ```
186 |
187 | where `` is the name of your branch.
188 |
189 | #### Step 8: Pull Request
190 |
191 | Once your contribution is ready to be incorporated in the `upstream` repository, open a [pull request][github-pull-request] against the `master` branch. A project contributor will review the contribution, provide feedback, and potentially request changes.
192 |
193 | > Receiving feedback is the most **important**, and often the most **valuable**, part of the submission process. Don't get disheartened!
194 |
195 | To make changes to your [pull request][github-pull-request], make changes to your branch. Each time you push changes to your forked repository, GitHub will automatically update the [pull request][github-pull-request].
196 |
197 | ```bash
198 | $ git add files/which/changed
199 | $ git commit
200 | $ git push origin
201 | ```
202 |
203 | Note that, once a [pull request][github-pull-request] has been made (i.e., your local repository commits have been pushed to a remote server), you should **not** perform any further [rewriting][git-rewriting-history] of Git history. If the history needs modification, a contributor will modify the history during the merge process. The rationale for **not** rewriting public history is that doing so invalidates the commit history for anyone else who has pulled your changes, thus imposing additional burdens on collaborators to ensure that their local versions match the modified history.
204 |
205 | #### Step 9: Land
206 |
207 | After any changes have been resolved, a contributor will approve a [pull request][github-pull-request] for inclusion in the project. Once merged, the [pull request][github-pull-request] will be updated with the merge commit, and the [pull request][github-pull-request] will be closed.
208 |
209 | Note that, during the merge process, multiple commits will often be [squashed][git-rewriting-history].
210 |
211 | #### Step 10: Celebrate
212 |
213 | **Congratulations**! You are an official contributor to this project! Thank you for your hard work and patience!
214 |
215 | ## Notes
216 |
217 | ### GitHub
218 |
219 | - When linking to specific lines of code in an issue or a pull request, hit the `y` key while viewing a file on GitHub. Doing so reloads the page with a URL that includes the specific version of the file you are viewing. This ensures that, when you refer to specific lines, these same lines can be easily viewed in the future, even if the content of the file changes.
220 | - GitHub does not send notifications when you push a commit and update a [pull request][github-pull-request], so be sure to comment on the pull request thread to inform reviewers that you have made changes.
221 |
222 | ### Writing Tests
223 |
224 | > By contributing tests to the project, you are agreeing to release them under the project [license][license].
225 |
226 | ### Writing Documentation
227 |
228 | > By contributing documentation to the project, you are agreeing to release it under the project [license][license].
229 |
230 | Project documentation is localized within each package. Similar to code, you should modify documentation using [Git][git].
231 |
232 | ## Developer's Certificate of Origin 1.1
233 |
234 | By making a contribution to this project, I certify that:
235 |
236 | - (a) The contribution was created in whole or in part by me and I have the right to submit it under the open source license indicated in the file; or
237 | - (b) The contribution is based upon previous work that, to the best of my knowledge, is covered under an appropriate open source license and I have the right under that license to submit that work with modifications, whether created in whole or in part by me, under the same open source license (unless I am permitted to submit under a different license), as indicated in the file; or
238 | - (c) The contribution was provided directly to me by some other person who certified (a), (b) or (c) and I have not modified it.
239 | - (d) I understand and agree that this project and the contribution are public and that a record of the contribution (including all personal information I submit with it, including my sign-off) is maintained indefinitely and may be redistributed consistent with this project or the open source license(s) involved.
240 |
241 | ## Conclusion
242 |
243 | Phew. While the above may be a lot to remember, even for what seem like minor changes, eventually it becomes routine and part of the normal development flow. Part of the motivation for enforcing process is to ensure that all code contributions meet a certain quality threshold, thus helping reviewers focus less on non-substantive issues like style and failing tests and more on substantive issues such as contribution content and merit. Know that your patience, hard work, time, and effort are greatly appreciated!
244 |
245 |
246 |
247 | [jupyter-of-conduct]: https://jupyter.org/conduct/
248 | [license]: https://github.com/jupyter/jupyterlab-metadata-service/blob/master/LICENSE
249 | [development-guide]: https://github.com/jupyter/jupyterlab-metadata-service/blob/master/docs/development.md
250 | [github-signup]: https://github.com/signup/free
251 | [github-pull-request]: https://help.github.com/articles/creating-a-pull-request/
252 | [github-gist]: https://gist.github.com/
253 | [github-markdown-guide]: https://guides.github.com/features/mastering-markdown/
254 | [github-fork]: https://help.github.com/articles/fork-a-repo/
255 | [github-git-tutorial]: http://try.github.io/levels/1/challenges/1
256 | [git]: http://git-scm.com/
257 | [git-clone-depth]: https://git-scm.com/docs/git-clone#git-clone---depthltdepthgt
258 | [git-remotes]: https://git-scm.com/book/en/v2/Git-Basics-Working-with-Remotes
259 | [git-rebase]: https://git-scm.com/docs/git-rebase
260 | [git-merge]: https://git-scm.com/docs/git-merge
261 | [git-rewriting-history]: https://git-scm.com/book/en/v2/Git-Tools-Rewriting-History
262 |
263 |
264 |
--------------------------------------------------------------------------------
/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 project has been archived by lack of maintainers**
2 |
3 | # JupyterLab Metadata Extension
4 |
5 | ![Stability Experimental][badge-stability]
6 | [![Binder][badge-binder]][binder]
7 |
8 | ```bash
9 | jupyter labextension install @jupyterlab/metadata-extension @jupyterlab/dataregistry-extension
10 | ```
11 |
12 | This JupyterLab extension
13 |
14 | - displays linked data about the resources you are interacting with in JuyterLab.
15 | - enables other extensions to register as linked data providers to expose [JSON LD][json-ld] about an entity given the entity's URL.
16 | - exposes linked data to the user as a Linked Data viewer in the Data Browser pane.
17 | - Check out the project vision in the ["Press Release from the Future"](./press_release.md)!
18 |
19 | ## Usage
20 |
21 | [Usage docs](./docs/usage.md)
22 |
23 | ## Contributing
24 |
25 | This repository is in active development, and we welcome collaboration. For development guidance, please consult the [development guide](./docs/development.md).
26 |
27 | 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.
28 |
29 | We try to keep the current issues relevant and matched to relevant milestones.
30 |
31 |
32 |
33 | [badge-stability]: https://img.shields.io/badge/stability-experimental-red.svg
34 | [badge-binder]: https://mybinder.org/badge_logo.svg
35 | [binder]: https://mybinder.org/v2/gh/jupyterlab/jupyterlab-metadata-service/master?urlpath=lab
36 | [json-ld]: https://json-ld.org/
37 |
38 |
39 |
--------------------------------------------------------------------------------
/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 run build
12 | jupyter labextension link . @jupyterlab/dataregistry-extension
13 |
--------------------------------------------------------------------------------
/binder/requirements.txt:
--------------------------------------------------------------------------------
1 | jupyterlab>=1.0
2 |
--------------------------------------------------------------------------------
/datasets.yml:
--------------------------------------------------------------------------------
1 | children:
2 | - "https://github.com/Coleridge-Initiative/adrf-onto/wiki/Vocabulary#publication-5322c3a9d95a8dda1f1b"
3 | datasets:
4 | - url: "https://github.com/Coleridge-Initiative/adrf-onto/wiki/Vocabulary#publication-5322c3a9d95a8dda1f1b"
5 | label: "A Publication"
6 | children:
7 | - "https://github.com/Coleridge-Initiative/adrf-onto/wiki/Vocabulary#dataset-2cea7e830ce94a923473"
8 | - url: "https://github.com/Coleridge-Initiative/adrf-onto/wiki/Vocabulary#dataset-2cea7e830ce94a923473"
9 | label: "Some other dataset"
10 | snippets:
11 | Load in Pandas: "import pandas as pd; ..."
--------------------------------------------------------------------------------
/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-metadata-service -c conda-forge python=3.6 jupyterlab nodejs
35 | ```
36 |
37 | To activate the environment,
38 |
39 | ```bash
40 | $ conda activate jupyterlab-metadata-service
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-metadata-service.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-metadata-service.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-metadata-service.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-metadata-service`. To proceed with configuring your environment, navigate to the project folder.
82 |
83 | ```bash
84 | $ cd jupyterlab-metadata-service
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 | $ jlpm install:extensions
94 | ```
95 |
96 | where `jlpm` is the JupyterLab package manager which is bundled with [JupyterLab][jupyterlab].
97 |
98 | ## Build
99 |
100 | To build the metadata extension,
101 |
102 | ```bash
103 | $ jlpm run build
104 | ```
105 |
106 | If your environment has been configured correctly, the previous command should complete without errors.
107 |
108 | To build the [JupyterLab][jupyterlab] extensions found in this repository and to launch the [JupyterLab][jupyterlab] environment,
109 |
110 | ```bash
111 | $ jlpm run build:jupyter
112 | ```
113 |
114 | ## Clean
115 |
116 | To clean your local environment, including [Node.js][node-js] module dependencies,
117 |
118 | ```bash
119 | $ jlpm run clean
120 | ```
121 |
122 | To remove build artifacts, such as compiled JavaScript files, from repository packages,
123 |
124 | ```bash
125 | $ jlpm run clean:packages
126 | ```
127 |
128 | To remove [JupyterLab][jupyterlab] extension artifacts, such as linked extensions,
129 |
130 | ```bash
131 | $ jlpm run clean:jupyter
132 | ```
133 |
134 | ## Reset
135 |
136 | To clean and rebuild the metadata extension,
137 |
138 | ```bash
139 | $ jlpm run all
140 | ```
141 |
142 | ## Watch
143 |
144 | During development, you'll likely want the metadata extension to automatically recompile and update. Accordingly, in a separate terminal window,
145 |
146 | ```bash
147 | $ jlpm run build:watch
148 | ```
149 |
150 | which will automatically trigger recompilation upon updates to source files.
151 |
152 | In another terminal window,
153 |
154 | ```bash
155 | $ jlpm run build:jupyter:watch
156 | ```
157 |
158 | which will launch the [JupyterLab][jupyterlab] environment and automatically update the running lab environment upon recompilation changes.
159 |
160 | ## Update
161 |
162 | 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`.
163 |
164 | ```bash
165 | $ git pull
166 | ```
167 |
168 | 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,
169 |
170 | ```bash
171 | $ git fetch upstream
172 | $ git merge upstream/
173 | ```
174 |
175 | where `upstream` is the remote name and `` refers to the branch you want to merge into your local copy.
176 |
177 | ## Organization
178 |
179 | The repository is organized as follows:
180 |
181 | ```text
182 | binder Binder configuration
183 | docs top-level documentation
184 | notebooks Jupyter notebooks
185 | src extension source code
186 | ```
187 |
188 | ## Editors
189 |
190 | - This repository uses [EditorConfig][editorconfig] to maintain consistent coding styles between different editors and IDEs, including [browsers][editorconfig-chrome].
191 |
192 |
193 |
194 | [git]: http://git-scm.com/
195 | [python]: https://www.python.org/
196 | [pip]: https://github.com/pypa/pip
197 | [node-js]: https://nodejs.org/en/
198 | [npm]: https://www.npmjs.com/
199 | [jupyterlab]: https://github.com/jupyterlab/jupyterlab
200 | [anaconda]: https://docs.conda.io/projects/conda/en/latest/user-guide/tasks/manage-environments.html
201 | [github-fork]: https://help.github.com/articles/fork-a-repo/
202 | [github-fork-sync]: https://help.github.com/articles/syncing-a-fork/
203 | [github-remote]: https://help.github.com/articles/configuring-a-remote-for-a-fork/
204 | [git-clone-depth]: https://git-scm.com/docs/git-clone#git-clone---depthltdepthgt
205 | [git-remotes]: https://git-scm.com/book/en/v2/Git-Basics-Working-with-Remotes
206 | [editorconfig]: http://editorconfig.org/
207 | [editorconfig-chrome]: https://chrome.google.com/webstore/detail/github-editorconfig/bppnolhdpdfmmpeefopdbpmabdpoefjh?hl=en-US
208 |
209 |
210 |
--------------------------------------------------------------------------------
/docs/img/interface.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jupyterlab/jupyterlab-metadata-service/9925f6af5b1f74a6a0226687bc85a3501f508bbd/docs/img/interface.png
--------------------------------------------------------------------------------
/docs/img/notebook.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jupyterlab/jupyterlab-metadata-service/9925f6af5b1f74a6a0226687bc85a3501f508bbd/docs/img/notebook.png
--------------------------------------------------------------------------------
/docs/img/screenshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jupyterlab/jupyterlab-metadata-service/9925f6af5b1f74a6a0226687bc85a3501f508bbd/docs/img/screenshot.png
--------------------------------------------------------------------------------
/docs/usage.md:
--------------------------------------------------------------------------------
1 | # Usage
2 |
3 | The JupyterLab Metadata extension adds a Linked Data viewer to the [Data Registry][data-registry]. To view metadata about a dataset,
4 | find it in the data explorer and then select the "Linked Data" view:
5 |
6 | 
7 |
8 | You can also register Linked Data about entities from a notebook by outputting the `application/ld+json` MIME type:
9 |
10 | 
11 |
12 | Third party extensions can depend on this extension to expose other linked data providers to register other metadata sources for users.
13 |
14 |
15 |
16 | [data-registry]: https://github.com/jupyterlab/jupyterlab-data-explorer
17 |
18 |
19 |
--------------------------------------------------------------------------------
/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 resolve = require('path').resolve;
11 | const PuppeteerEnvironment = require('jest-environment-puppeteer');
12 | const JestScreenshot = require('@rws-air/jestscreenshot');
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/.prettierignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | **/node_modules
3 | **/lib
4 | **/build
5 | **/static
6 | tests/**/coverage
7 | **/package.json
8 | .eggs
9 | .mypy_cache
10 | .ipynb_checkpoints
11 |
--------------------------------------------------------------------------------
/etc/prettier/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "singleQuote": true
3 | }
4 |
--------------------------------------------------------------------------------
/etc/stylelint/.stylelintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": ["stylelint-config-standard", "stylelint-config-prettier"]
3 | }
4 |
--------------------------------------------------------------------------------
/etc/tslint/tslint.json:
--------------------------------------------------------------------------------
1 | {
2 | "rulesDirectory": ["tslint-plugin-prettier"],
3 | "rules": {
4 | "prettier": [true, { "singleQuote": true }],
5 | "align": [true, "parameters", "statements"],
6 | "await-promise": true,
7 | "ban": [
8 | true,
9 | ["_", "forEach"],
10 | ["_", "each"],
11 | ["$", "each"],
12 | ["angular", "forEach"]
13 | ],
14 | "class-name": true,
15 | "comment-format": [true, "check-space"],
16 | "curly": true,
17 | "eofline": true,
18 | "forin": false,
19 | "indent": [true, "spaces", 2],
20 | "interface-name": [true, "always-prefix"],
21 | "jsdoc-format": true,
22 | "label-position": true,
23 | "max-line-length": [false],
24 | "member-access": false,
25 | "member-ordering": [false],
26 | "new-parens": true,
27 | "no-angle-bracket-type-assertion": true,
28 | "no-any": false,
29 | "no-arg": true,
30 | "no-bitwise": true,
31 | "no-conditional-assignment": true,
32 | "no-consecutive-blank-lines": false,
33 | "no-console": [true, "debug", "info", "time", "timeEnd", "trace"],
34 | "no-construct": true,
35 | "no-debugger": true,
36 | "no-default-export": false,
37 | "no-duplicate-variable": true,
38 | "no-empty": true,
39 | "no-eval": true,
40 | "no-floating-promises": true,
41 | "no-inferrable-types": false,
42 | "no-internal-module": true,
43 | "no-invalid-this": [true, "check-function-in-method"],
44 | "no-null-keyword": false,
45 | "no-reference": true,
46 | "no-require-imports": false,
47 | "no-shadowed-variable": false,
48 | "no-string-literal": false,
49 | "no-switch-case-fall-through": true,
50 | "no-trailing-whitespace": true,
51 | "no-use-before-declare": false,
52 | "no-var-keyword": true,
53 | "no-var-requires": true,
54 | "object-literal-sort-keys": false,
55 | "one-line": [
56 | true,
57 | "check-open-brace",
58 | "check-catch",
59 | "check-else",
60 | "check-finally",
61 | "check-whitespace"
62 | ],
63 | "one-variable-per-declaration": [true, "ignore-for-loop"],
64 | "quotemark": {
65 | "options": [true, "single", "avoid-escape"],
66 | "severity": "off"
67 | },
68 | "radix": true,
69 | "semicolon": [true, "always", "ignore-bound-class-methods"],
70 | "switch-default": true,
71 | "trailing-comma": [
72 | false,
73 | {
74 | "multiline": "never",
75 | "singleline": "never"
76 | }
77 | ],
78 | "triple-equals": [true, "allow-null-check", "allow-undefined-check"],
79 | "typedef": [false],
80 | "typedef-whitespace": [
81 | false,
82 | {
83 | "call-signature": "nospace",
84 | "index-signature": "nospace",
85 | "parameter": "nospace",
86 | "property-declaration": "nospace",
87 | "variable-declaration": "nospace"
88 | },
89 | {
90 | "call-signature": "space",
91 | "index-signature": "space",
92 | "parameter": "space",
93 | "property-declaration": "space",
94 | "variable-declaration": "space"
95 | }
96 | ],
97 | "use-isnan": true,
98 | "use-strict": [false],
99 | "variable-name": [
100 | true,
101 | "check-format",
102 | "allow-leading-underscore",
103 | "ban-keywords",
104 | "allow-pascal-case"
105 | ],
106 | "whitespace": [
107 | true,
108 | "check-branch",
109 | "check-operator",
110 | "check-separator",
111 | "check-type"
112 | ]
113 | },
114 | "linterOptions": {
115 | "exclude": ["../../node_modules/**/*", "../../lib/**/*"]
116 | }
117 | }
118 |
--------------------------------------------------------------------------------
/notebooks/demo.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "code",
5 | "execution_count": 1,
6 | "metadata": {},
7 | "outputs": [],
8 | "source": [
9 | "import IPython.display"
10 | ]
11 | },
12 | {
13 | "cell_type": "code",
14 | "execution_count": 2,
15 | "metadata": {},
16 | "outputs": [
17 | {
18 | "data": {
19 | "application/ld+json": {
20 | "@id": "file:///output.png",
21 | "http://schema.org/name": "Some Name!"
22 | }
23 | },
24 | "metadata": {},
25 | "output_type": "display_data"
26 | }
27 | ],
28 | "source": [
29 | "IPython.display.publish_display_data(\n",
30 | " {\"application/ld+json\": {\n",
31 | " \"@id\": \"file:///output.png\",\n",
32 | " \"http://schema.org/name\": \"Some Name!\"\n",
33 | " }}\n",
34 | ")"
35 | ]
36 | },
37 | {
38 | "cell_type": "code",
39 | "execution_count": 3,
40 | "metadata": {},
41 | "outputs": [
42 | {
43 | "data": {
44 | "application/x.jupyter.relative-dataset-urls+json": [
45 | "file:///output.png"
46 | ]
47 | },
48 | "metadata": {},
49 | "output_type": "display_data"
50 | }
51 | ],
52 | "source": [
53 | "IPython.display.publish_display_data(\n",
54 | " {\"application/x.jupyter.relative-dataset-urls+json\": [\"file:///output.png\"]}\n",
55 | ")"
56 | ]
57 | },
58 | {
59 | "cell_type": "code",
60 | "execution_count": null,
61 | "metadata": {},
62 | "outputs": [],
63 | "source": []
64 | }
65 | ],
66 | "metadata": {
67 | "kernelspec": {
68 | "display_name": "Python 3",
69 | "language": "python",
70 | "name": "python3"
71 | },
72 | "language_info": {
73 | "codemirror_mode": {
74 | "name": "ipython",
75 | "version": 3
76 | },
77 | "file_extension": ".py",
78 | "mimetype": "text/x-python",
79 | "name": "python",
80 | "nbconvert_exporter": "python",
81 | "pygments_lexer": "ipython3",
82 | "version": "3.6.7"
83 | }
84 | },
85 | "nbformat": 4,
86 | "nbformat_minor": 4
87 | }
88 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@jupyterlab/metadata-extension",
3 | "version": "2.0.0",
4 | "description": "A JupyterLab extension to display linked data about the resources you are interacting with in JuyterLab.",
5 | "keywords": [
6 | "jupyter",
7 | "jupyterlab",
8 | "jupyterlab-extension"
9 | ],
10 | "homepage": "https://github.com/jupyterlab/jupyterlab-metadata-service",
11 | "bugs": {
12 | "url": "https://github.com/jupyterlab/jupyterlab-metadata-service/issues"
13 | },
14 | "license": "BSD-3-Clause",
15 | "author": "CalPoly-Quansight",
16 | "files": [
17 | "lib/**/",
18 | "style.css"
19 | ],
20 | "style": "style.css",
21 | "main": "lib/index.js",
22 | "types": "lib/index.d.ts",
23 | "repository": {
24 | "type": "git",
25 | "url": "https://github.com/jupyterlab/jupyterlab-metadata-service.git"
26 | },
27 | "scripts": {
28 | "all": "jlpm run clean && jlpm run build && jlpm run build:jupyter",
29 | "all:watch": "jlpm run clean && jlpm run build && jlpm run build:jupyter:watch",
30 | "build": "jlpm run build:dev",
31 | "build:dev": "jlpm install && jlpm run clean:packages && jlpm run build:packages && jlpm run link:packages && jlpm run install:extensions && jupyter labextension list",
32 | "build:jupyter": "jupyter lab build && jupyter lab",
33 | "build:jupyter:watch": "jupyter lab build && jupyter lab --watch",
34 | "build:packages": "tsc --build",
35 | "build:watch": "tsc --build --watch --listEmittedFiles",
36 | "clean": "jlpm run clean:jupyter && jlpm clean:packages && jlpm clean:node",
37 | "clean:jupyter": "jlpm run uninstall:extensions && jlpm run unlink:packages && jupyter lab clean",
38 | "clean:node": "rimraf node_modules",
39 | "clean:packages": "rimraf lib tsconfig.tsbuildinfo",
40 | "install:extensions": "jupyter labextension install @jupyterlab/dataregistry-extension",
41 | "link": "jlpm run link:packages",
42 | "link:packages": "jupyter labextension link ./ --no-build",
43 | "lint": "jlpm run prettier && jlpm run lint:css && jlpm run lint:typescript",
44 | "lint:check": "jlpm run prettier:check && jlpm run lint:css:check && jlpm run lint:typescript:check",
45 | "lint:css": "stylelint *.css --fix --config ./etc/stylelint/.stylelintrc.json",
46 | "lint:css:check": "stylelint *.css --config ./etc/stylelint/.stylelintrc.json",
47 | "lint:typescript": "tslint --fix -c ./etc/tslint/tslint.json --project tsconfig.json '**/*{.ts,.tsx}'",
48 | "lint:typescript:check": "tslint -c ./etc/tslint/tslint.json --project tsconfig.json '**/*{.ts,.tsx}'",
49 | "prepublishOnly": "npm run clean && npm install && npm run build:packages",
50 | "prettier": "prettier --write '**/*{.ts,.tsx,.js,.jsx,.css,.json,.md}' --config ./etc/prettier/.prettierrc --ignore-path ./etc/prettier/.prettierignore",
51 | "prettier:check": "prettier --list-different '**/*{.ts,.tsx,.js,.jsx,.css,.json,.md}' --config ./etc/prettier/.prettierrc --ignore-path ./etc/prettier/.prettierignore",
52 | "rebuild:packages": "jlpm run clean:packages && jlpm run build:packages",
53 | "test": "env JEST_PUPPETEER_CONFIG=./etc/jest/jest-puppeteer.config.js jest --runInBand --config ./etc/jest/jest.config.js",
54 | "test:debug": "env HEADLESS=false SLOWMO=true jlpm test",
55 | "uninstall:extensions": "jupyter labextension uninstall --all --no-build",
56 | "unlink": "jlpm run unlink:packages",
57 | "unlink:packages": "jupyter labextension unlink ./ --no-build || echo 'Unlink command failed, but continuing...'"
58 | },
59 | "husky": {
60 | "hooks": {
61 | "pre-commit": "lint-staged --config ./etc/lint-staged/lint-staged.config.js"
62 | }
63 | },
64 | "dependencies": {
65 | "@jupyterlab/application": "^1.0.0",
66 | "@phosphor/coreutils": "^1.3.0",
67 | "jsonld": "1.6.2",
68 | "react": "^16.4.2"
69 | },
70 | "peerDependencies": {
71 | "@jupyterlab/dataregistry": "^3.0.0",
72 | "@jupyterlab/dataregistry-extension": "^3.0.0",
73 | "rxjs": "^6.5.2"
74 | },
75 | "devDependencies": {
76 | "@jupyterlab/dataregistry-extension": "^3.0.0",
77 | "@rws-air/jestscreenshot": "^3.0.3",
78 | "@types/expect-puppeteer": "^3.3.2",
79 | "@types/jest": "^24.0.19",
80 | "@types/jest-environment-puppeteer": "^4.3.1",
81 | "@types/jsonld": "^1.5.0",
82 | "@types/puppeteer": "^1.20.2",
83 | "husky": "^3.0.9",
84 | "jest": "^24.9.0",
85 | "jest-circus": "^24.9.0",
86 | "jest-puppeteer": "^4.3.0",
87 | "lint-staged": "^9.4.2",
88 | "prettier": "^1.18.2",
89 | "puppeteer": "^2.0.0",
90 | "rimraf": "~2.6.2",
91 | "stylelint": "^11.0.0",
92 | "stylelint-config-prettier": "^6.0.0",
93 | "stylelint-config-standard": "^19.0.0",
94 | "ts-jest": "^24.1.0",
95 | "tslint": "^5.20.0",
96 | "tslint-config-prettier": "^1.18.0",
97 | "tslint-plugin-prettier": "^2.0.1",
98 | "typescript": "~3.3.1"
99 | },
100 | "publishConfig": {
101 | "access": "public"
102 | },
103 | "jupyterlab": {
104 | "extension": true
105 | }
106 | }
107 |
--------------------------------------------------------------------------------
/press_release.md:
--------------------------------------------------------------------------------
1 | [back to project](./README.md)
2 |
3 | # Press Release from the Future
4 |
5 | ## JupyterLab Metadata Explorer Press Release
6 |
7 | The JupyterLab Metadata Explorer is a step forward in providing _rich context_ to data stewards, analysts, and scientists into the world of meaningful, semantically enriched linked scientific documents and data.
8 | Jupyter Notebooks and JupyterLab have succeeded as general-purpose tools to wrangle, manipulate, and analyze documents and data with programming languages.
9 | The JupyterLab audiences combine various computational documents (eg. narrative, code, applications, notebooks) and media types (e.g. figures, data) to contextualize their expertise in different scientific method.
10 | _Rich context_ metadata connects vocabularies and schema that enrich the context and meaning of information in computational documents.
11 | The JupyterLab Metadata Explorer, a feature of the rich context ecosystem, is a purpose-driven extension that exposes supplementary meaning related to data. It is designed for individuals and organizations capturing knowledge in JupyterLab and Jupyter notebooks.
12 |
13 | There is valuable contextual information–metadata–surrounding all of JupyterLab entities (notebooks, datasets, file, etc) which we call “rich context”.
14 | This _rich context_, when visible, enables the collaborative authoring of an emergent narrative around your work within JupyterLab.
15 | It empowers you to collaborate with your peers, discover new information, techniques, and results to help you make informed decisions.
16 | It gets to the heart of the underlying value of a dataset for stakeholder agencies and organizations and enables researchers to work with the data in a more effective manner.
17 | With the introduction of the JupyterLab Metadata Explorer, we enter a new phase of tooling which will surround the practitioner with _rich context_.
18 |
19 | Classical sciences, the information poor predecessor to modern science, can manage their metadata knowledge without information systems.
20 | The modern information rich landscape of data science is accelerated by global asynchronous collaborations.
21 | The velocity of modern science is too fast for individuals to manage the complex meaning in data and computational documents; the rich context ecosystem is needed for managing meaning.
22 |
23 | Specifically, we are defining metadata as multi-vocabulary knowledge graphs encoded as RDF, through JSON-LD, served by HTTP.
24 | Organizations - with their developers and scientists - collaboratively contribute to collections of interlinked descriptions of entities into knowledge graphs.
25 | These entities range from things, publications, datasets, events and people, along with other objects used in coding languages and scientific frameworks.
26 | The JupyterLab Metadata Explorer consumes an organization’s metadata catalog as knowledge graphs, to enhance interactive computing practices with supplemental meaning about the fundamental entities of data and their relationships.
27 | Ultimately, it connects knowledge generated by multi-faceted organizations of data consumers and creators.
28 |
29 | Taken together, the result is a flexible system that serves an organization’s scientists, analysts, and data stewards.
30 | Organizations with existing metadata catalogs can serve their catalogs to their JupyterLab users by linking knowledge though the metadata provider; data stewards can also supplement their organization’s knowledge through links to various external metadata providers.
31 | Projects in JupyterLab benefit doubly from the auto-generated context supplied by the previous notebooks while maintaining the agency to curate personalized domain knowledge graphs.
32 | Rich Context helps organizations, data stewards, and scientists discover information, techniques, and previous analysis extracted from datasets, notebooks, publications etc., to access the underlying value of data in a more effective manner.
33 | The end result of linking a Metadata Provider for your organization is less duplicated work and faster innovation.
34 |
35 | Metadata Catalogs already exist in various formats, are hosted in various ways by various organizations, and have many uses outside of JupyterLab.
36 | The Metadata Explorer connects the Metadata Service and Metadata Providers.
37 | It relies on well-tested and documented web standards to expose catalogs through the JupyterLab interface to end-users.
38 | The result is that the Metadata Explorer can merge many catalogs together into a unified view!
39 | **Insert gif of Metadata Explorer here**
40 | The Metadata Explorer, and the general rich context suite, aids you as your JupyterLab assistant.
41 | When the Metadata Explorer is open in JupyterLab it automatically accesses the knowledge graph, to surface links between what an end-user is working on and any associated knowledge within the graph.
42 | Keep your hands free as you browse the data that the software has linked for you.
43 | Boom, you’re a scientist collaborating with other Jupyter communities.
44 |
45 | Go download and install the JupyterLab Metadata Explorer, and the other tools in the Jupyterlab rich context ecosystem. Your metadata awaits!
46 |
--------------------------------------------------------------------------------
/src/find_entity.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 { LinkedData } from './types';
9 |
10 | /**
11 | * Returns a linked data entity associated with a specified URL.
12 | *
13 | * @private
14 | * @param entities - list of entities
15 | * @param id - URL
16 | * @returns linked data entity
17 | */
18 | function findEntity(entities: Array, id: URL): LinkedData | undefined {
19 | return entities.find(o => o['@id'] === id.toString());
20 | }
21 |
22 | /**
23 | * Exports.
24 | */
25 | export { findEntity };
26 |
--------------------------------------------------------------------------------
/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 LinkedDataBrowser from './linked_data_browser';
10 | import LinkedDataRegistry from './linked_data_registry';
11 | import SampleProvider from './sample_provider';
12 |
13 | export default [
14 | LinkedDataRegistry,
15 | SampleProvider,
16 | LinkedDataBrowser
17 | ] as JupyterFrontEndPlugin[];
18 |
--------------------------------------------------------------------------------
/src/internal_url.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 |
10 | /**
11 | * Interface describing internal URL properties.
12 | *
13 | * @private
14 | */
15 | interface IProps {
16 | /**
17 | * URL.
18 | */
19 | url: string;
20 |
21 | /**
22 | * Callback invoked upon a "click" event.
23 | *
24 | * @param url - URL
25 | */
26 | onClick: (url: URL) => void;
27 | }
28 |
29 | /**
30 | * Renders a URL.
31 | *
32 | * @private
33 | * @param props - property values
34 | * @returns a rendered URL
35 | */
36 | function InternalURL(props: IProps) {
37 | return (
38 | props.onClick(new URL(props.url))}
41 | >
42 | {props.url}
43 |
44 | );
45 | }
46 |
47 | /**
48 | * Exports.
49 | */
50 | export { InternalURL };
51 |
--------------------------------------------------------------------------------
/src/linked_data_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 { Observable, combineLatest } from 'rxjs';
10 | import { switchMap, map } from 'rxjs/operators';
11 | import {
12 | JupyterFrontEnd,
13 | JupyterFrontEndPlugin
14 | } from '@jupyterlab/application';
15 | import {
16 | createConverter,
17 | resolveDataType,
18 | DataTypeNoArgs
19 | } from '@jupyterlab/dataregistry';
20 | import {
21 | IActiveDataset,
22 | IRegistry,
23 | reactDataType
24 | } from '@jupyterlab/dataregistry-extension';
25 | import { LinkedData, LinkedDataThunk } from './types';
26 | import {
27 | LinkedDataRegistry,
28 | LinkedDataRegistryToken
29 | } from './linked_data_registry';
30 | import { findEntity } from './find_entity';
31 | import { Viewer } from './viewer';
32 |
33 | // // Define a conversion data type for compacted JSON-LD (see https://w3c.github.io/json-ld-syntax/#example-162-http-request-with-profile-requesting-a-compacted-document):
34 | // const jsonLDCompactedDataType = new DataTypeNoArgs>(
35 | // "application/ld+json;profile=http://www.w3.org/ns/json-ld#compacted"
36 | // );
37 |
38 | // Define a conversion data type for a linked data thunk:
39 | const linkedDataThunkDataType = new DataTypeNoArgs(
40 | 'application/x.jupyter.linked-data-thunk'
41 | );
42 |
43 | // Define a conversion data type for JSON-LD:
44 | const jsonLDDataType = new DataTypeNoArgs>(
45 | 'application/ld+json'
46 | );
47 |
48 | /**
49 | * Activates the plugin.
50 | *
51 | * @private
52 | * @param app - Jupyter front-end application instance
53 | * @param registry - linked data registry
54 | * @param dataRegistry - JupyterLab data registry
55 | * @param activate - activate dataset
56 | */
57 | function activate(
58 | app: JupyterFrontEnd,
59 | registry: LinkedDataRegistry,
60 | dataRegistry: IRegistry,
61 | active: IActiveDataset
62 | ) {
63 | // Get linked data from all data types and register them in the graph:
64 | let linkedData: Array = [];
65 | dataRegistry.URLs$.pipe(
66 | switchMap(urls =>
67 | combineLatest(
68 | ...([...urls]
69 | .map(url => {
70 | const res = jsonLDDataType.getDataset(dataRegistry.getURL(url));
71 | if (!res) {
72 | return null;
73 | }
74 | return (res as Observable<{ '@id': string }>).pipe(
75 | map(r => ({
76 | ...r,
77 | // Replace by setting base to current URL:
78 | ...{ '@id': new URL(r['@id'], url).toString() }
79 | }))
80 | );
81 | })
82 | .filter(e => e !== null)
83 | .flat() as Array>)
84 | )
85 | )
86 | ).subscribe({
87 | next: value => {
88 | linkedData = value;
89 | }
90 | });
91 |
92 | const provider = {
93 | get: resolver
94 | };
95 | registry.register(provider);
96 |
97 | dataRegistry.addConverter(
98 | /**
99 | * Convert json ld to compacted form and resolve base url, so that the @id
100 | * can be relative to the dataset
101 | *
102 | * https://github.com/digitalbazaar/jsonld.js/issues/329#issuecomment-532475466
103 | */
104 | // createConverter(
105 | // { from: jsonLDDataType, to: jsonLDCompactedDataType },
106 | // ({ data, url }) =>
107 | // data.pipe(flatMap(doc => compact(doc, {}, { base: url.toString() })))
108 | // ),
109 | createConverter(
110 | { from: resolveDataType, to: linkedDataThunkDataType },
111 | ({ url }) => registry.get(url)
112 | ),
113 | createConverter(
114 | { from: linkedDataThunkDataType, to: reactDataType },
115 | ({ url, data }) => ({
116 | type: 'Linked Data',
117 | data: (
118 | active.next(url.toString())}
122 | />
123 | )
124 | })
125 | )
126 | );
127 |
128 | /**
129 | * Returns a thunk to fetch linked data associated with a specified URL.
130 | *
131 | * @private
132 | * @param url - URL
133 | * @returns a function returning a promise which resolves linked data
134 | */
135 | function resolver(url: URL) {
136 | const result = findEntity(linkedData, url);
137 | if (!result) {
138 | return null;
139 | }
140 | return async () => result;
141 | }
142 | }
143 |
144 | /**
145 | * Plugin registration data.
146 | */
147 | const extension: JupyterFrontEndPlugin = {
148 | id: 'jupyterlab-metadata-service:data-browser',
149 | activate: activate,
150 | autoStart: true,
151 | requires: [LinkedDataRegistryToken, IRegistry, IActiveDataset]
152 | };
153 |
154 | /**
155 | * Exports.
156 | */
157 | export default extension;
158 |
--------------------------------------------------------------------------------
/src/linked_data_registry.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 { expand, flatten } from 'jsonld';
9 | import { Token } from '@phosphor/coreutils';
10 | import { JupyterFrontEndPlugin } from '@jupyterlab/application';
11 | import { LinkedDataThunk } from './types';
12 | import { findEntity } from './find_entity';
13 |
14 | /**
15 | * Interface describing a linked data "provider".
16 | *
17 | * @private
18 | */
19 | interface ILinkedDataProvider {
20 | /**
21 | * Returns a thunk to fetch the linked data associated with a specified URL.
22 | *
23 | * ## Notes
24 | *
25 | * - If no information is associated with a specified URL, the method should return `null`.
26 | *
27 | * @param url - URL
28 | * @returns a function returning a promise which resolves linked data
29 | */
30 | get(url: URL): LinkedDataThunk | null;
31 | }
32 |
33 | /**
34 | * Linked data registry class.
35 | *
36 | * @private
37 | */
38 | class LinkedDataRegistry {
39 | /**
40 | * Registers a linked data provider.
41 | *
42 | * @param provider - linked data provider
43 | */
44 | register(provider: ILinkedDataProvider): void {
45 | this._providers.add(provider);
46 | }
47 |
48 | /**
49 | * Returns a promise for resolving linked data associated with a specified URL.
50 | *
51 | * ## Notes
52 | *
53 | * - If a URL is not associated with linked data, the method returns `null`.
54 | *
55 | * @param url - URL
56 | * @returns a function returning a promise which resolves linked data
57 | */
58 | get(url: URL): LinkedDataThunk | null {
59 | const thunks = [...this._providers]
60 | .map(p => p.get(url))
61 | .filter(v => v) as Array;
62 | if (thunks.length === 0) {
63 | return null;
64 | }
65 | return async () =>
66 | findEntity(
67 | (await expand(
68 | await flatten(await Promise.all(thunks.map(t => t())), null)
69 | )) as Array,
70 | url
71 | )!;
72 | }
73 |
74 | /**
75 | * List of linked data "providers".
76 | */
77 | private _providers = new Set();
78 | }
79 |
80 | /**
81 | * Linked data registry token.
82 | *
83 | * @private
84 | */
85 | const LinkedDataRegistryToken = new Token('LinkedDataRegistry');
86 |
87 | /**
88 | * Activates the plugin.
89 | *
90 | * @private
91 | * @returns a linked data registry
92 | */
93 | function activate() {
94 | return new LinkedDataRegistry();
95 | }
96 |
97 | /**
98 | * Plugin registration data.
99 | */
100 | const extension: JupyterFrontEndPlugin = {
101 | id: 'jupyterlab-metadata-service:linked-data-registry',
102 | activate: activate,
103 | autoStart: true,
104 | requires: [],
105 | provides: LinkedDataRegistryToken
106 | };
107 |
108 | /**
109 | * Exports.
110 | */
111 | export { LinkedDataRegistry };
112 | export { LinkedDataRegistryToken };
113 | export default extension;
114 |
--------------------------------------------------------------------------------
/src/node_entry.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 { InternalURL } from './internal_url';
10 | import { ValueObject } from './value_object';
11 | import { NodeObject } from './node_object';
12 |
13 | /**
14 | * Interface describing node entry properties.
15 | *
16 | * ## Notes
17 | *
18 | * - The entries of a node object whose keys are not keywords are also called properties of the node object. See [W3C][w3c].
19 | *
20 | * [w3c]: https://w3c.github.io/json-ld-syntax/#syntax-tokens-and-keywords
21 | *
22 | * @private
23 | */
24 | interface IProps {
25 | /**
26 | * Keyword.
27 | */
28 | keyword: string;
29 |
30 | /**
31 | * Node object.
32 | */
33 | object: object;
34 |
35 | /**
36 | * Callback invoked upon a "click" event.
37 | *
38 | * @param url - URL
39 | */
40 | onClick: (url: URL) => void;
41 | }
42 |
43 | /**
44 | * Renders a node entry.
45 | *
46 | * @private
47 | * @param props - node entry property values
48 | * @returns rendered node entry
49 | */
50 | function NodeEntry(props: IProps) {
51 | if (props.keyword === '@id') {
52 | return (
53 | <>
54 |
55 |
56 |
60 |
61 | >
62 | );
63 | }
64 | if (props.keyword === '@type') {
65 | return (
66 | <>
67 | type
68 | {(Array.isArray(props.object) ? props.object : [props.object]).map(
69 | type => (
70 |
71 |
72 |
73 | )
74 | )}
75 | >
76 | );
77 | }
78 | return (
79 | <>
80 | {props.keyword}
81 | {(Array.isArray(props.object) ? props.object : [props.object]).map(
82 | (innerObject, idx) => (
83 |
84 | {'@value' in innerObject ? (
85 |
86 | ) : (
87 |
88 | )}
89 |
90 | )
91 | )}
92 | >
93 | );
94 | }
95 |
96 | /**
97 | * Exports.
98 | */
99 | export { NodeEntry };
100 |
--------------------------------------------------------------------------------
/src/node_object.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 { NodeEntry } from './node_entry';
10 |
11 | /**
12 | * Interface describing [node object][1] properties.
13 | *
14 | * [1]:https://w3c.github.io/json-ld-syntax/#node-objects
15 | */
16 | interface IProps {
17 | /**
18 | * [Node object][1].
19 | *
20 | * [1]:https://w3c.github.io/json-ld-syntax/#node-objects
21 | */
22 | nodeObject: object;
23 |
24 | /**
25 | * Callback invoked upon a "click" event.
26 | *
27 | * @param url - URL
28 | */
29 | onClick: (url: URL) => void;
30 | }
31 |
32 | /**
33 | * Renders a node object.
34 | *
35 | * @private
36 | * @param props - node object property values
37 | * @returns rendered node object
38 | */
39 | function NodeObject(props: IProps) {
40 | const entries = Object.entries(props.nodeObject);
41 | if (entries.length === 0) {
42 | return No properties.
;
43 | }
44 | return (
45 |
46 | {entries.map(([keyword, object]) => (
47 |
51 | ))}
52 |
53 | );
54 | }
55 |
56 | /**
57 | * Exports.
58 | */
59 | export { NodeObject };
60 |
--------------------------------------------------------------------------------
/src/sample_provider.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 | JupyterFrontEnd,
10 | JupyterFrontEndPlugin
11 | } from '@jupyterlab/application';
12 | import {
13 | LinkedDataRegistry,
14 | LinkedDataRegistryToken
15 | } from './linked_data_registry';
16 | import { findEntity } from './find_entity';
17 | import defaultGraph from './default_graph';
18 |
19 | /**
20 | * Returns a thunk to fetch linked data associated with a specified URL.
21 | *
22 | * @private
23 | * @param url - URL
24 | * @returns a function returning a promise which resolves linked data
25 | */
26 | function resolver(url: URL) {
27 | const result = findEntity(defaultGraph, url);
28 | if (!result) {
29 | return null;
30 | }
31 | return async () => result;
32 | }
33 |
34 | /**
35 | * Activates the plugin.
36 | *
37 | * @private
38 | * @param _ - Jupyter front-end application instance
39 | * @param registry - linked data registry
40 | */
41 | function activate(app: JupyterFrontEnd, registry: LinkedDataRegistry) {
42 | const provider = {
43 | get: resolver
44 | };
45 | registry.register(provider);
46 | }
47 |
48 | /**
49 | * Plugin registration data.
50 | */
51 | const extension: JupyterFrontEndPlugin = {
52 | id: 'jupyterlab-metadata-service:sample-provider',
53 | activate: activate,
54 | autoStart: true,
55 | requires: [LinkedDataRegistryToken]
56 | };
57 |
58 | /**
59 | * Exports.
60 | */
61 | export default extension;
62 |
--------------------------------------------------------------------------------
/src/types.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 | /**
9 | * Linked data object.
10 | *
11 | * @private
12 | */
13 | type LinkedData = object;
14 |
15 | /**
16 | * Returns a promise which resolves a linked data object.
17 | *
18 | * @private
19 | * @returns a promise which resolves a linked data object
20 | */
21 | type LinkedDataThunk = () => Promise;
22 |
23 | /**
24 | * Exports.
25 | */
26 | export { LinkedData };
27 | export { LinkedDataThunk };
28 |
--------------------------------------------------------------------------------
/src/value_object.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 |
10 | /**
11 | * Interface describing properties for an object containing a [value object][1].
12 | *
13 | * [1]: https://w3c.github.io/json-ld-syntax/#value-objects
14 | */
15 | interface IProps {
16 | /**
17 | * Value object.
18 | */
19 | valueObject: { '@value': any };
20 | }
21 |
22 | /**
23 | * Renders a [value object][1].
24 | *
25 | * [1]: https://w3c.github.io/json-ld-syntax/#value-objects
26 | *
27 | * @private
28 | * @param props - value object property values
29 | * @returns a rendered value object
30 | */
31 | function ValueObject(props: IProps) {
32 | const value = props.valueObject['@value'];
33 | return (
34 |
35 | {typeof value === 'object' ? JSON.stringify(value, null, ' ') : value}
36 |
37 | );
38 | }
39 |
40 | /**
41 | * Exports.
42 | */
43 | export { ValueObject };
44 |
--------------------------------------------------------------------------------
/src/viewer.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 { LinkedData, LinkedDataThunk } from './types';
10 | import { NodeObject } from './node_object';
11 |
12 | /**
13 | * Interface describing viewer properties.
14 | *
15 | * @private
16 | */
17 | interface IProps {
18 | /**
19 | * URL.
20 | */
21 | url: URL;
22 |
23 | /**
24 | * Callback invoked upon a "click" event.
25 | *
26 | * @param url - URL
27 | */
28 | onClick: (url: URL) => void;
29 |
30 | /**
31 | * Function returning a promise which resolves linked data.
32 | */
33 | thunk: LinkedDataThunk;
34 | }
35 |
36 | /**
37 | * Interface describing viewer state.
38 | */
39 | interface IState {
40 | /**
41 | * Linked data.
42 | */
43 | data?: LinkedData;
44 | }
45 |
46 | /**
47 | * Component for viewing linked data.
48 | */
49 | class Viewer extends React.Component {
50 | /**
51 | * Viewer state.
52 | */
53 | readonly state: IState = {};
54 |
55 | /**
56 | * Component hook invoked prior to mounting.
57 | */
58 | async componentWillMount() {
59 | this.setState({ data: await this.props.thunk() });
60 | }
61 |
62 | /**
63 | * Component hook invoked after updating.
64 | *
65 | * @param prevProps - previous properties
66 | */
67 | componentDidUpdate(prevProps: IProps) {
68 | if (this.props.url.toString() !== prevProps.url.toString()) {
69 | return this.componentWillMount();
70 | }
71 | }
72 |
73 | /**
74 | * Renders the component.
75 | *
76 | * @returns rendered component
77 | */
78 | render() {
79 | const { data } = this.state;
80 | if (data === undefined) {
81 | return ...
;
82 | }
83 | return (
84 |
85 |
86 |
87 | );
88 | }
89 | }
90 |
91 | /**
92 | * Exports.
93 | */
94 | export { Viewer };
95 |
--------------------------------------------------------------------------------
/style.css:
--------------------------------------------------------------------------------
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 | .jl-metadata {
9 | padding: 16px;
10 | }
11 |
12 | .jl-metadata-node {
13 | color: var(--jp-content-font-color1);
14 | }
15 |
16 | .jl-metadata-node dt {
17 | font-weight: bold;
18 | float: left;
19 | clear: left;
20 | padding-right: 8px;
21 | max-width: 108px;
22 | overflow: hidden;
23 | text-overflow: ellipsis;
24 | white-space: nowrap;
25 | direction: rtl;
26 | }
27 |
28 | .jl-metadata-node dt::before {
29 | content: ':';
30 | }
31 |
32 | .jl-metadata-node dd {
33 | margin: 0;
34 | padding-bottom: 8px;
35 | overflow: hidden;
36 | direction: ltr;
37 | }
38 |
39 | .jl-metadata-value {
40 | color: var(--jp-content-font-color1);
41 | }
42 |
43 | .jl-metadata-internal-url {
44 | color: #2196f3;
45 | direction: rtl;
46 | }
47 |
48 | .jl-metadata-internal-url a {
49 | color: #2196f3;
50 | overflow: hidden;
51 | white-space: nowrap;
52 | direction: rtl;
53 | text-overflow: ellipsis;
54 | display: block;
55 | }
56 |
57 | .jl-metadata-internal-url a:hover {
58 | color: #2196f3;
59 | }
60 |
61 | .jl-metadata-internal-url a:active {
62 | color: #2196f3;
63 | }
64 | .jl-metadata-id-keyword {
65 | display: none;
66 | }
67 |
68 | .jl-metadata-id-field {
69 | color: var(--jp-content-font-color1);
70 | }
71 |
--------------------------------------------------------------------------------
/test/ui/test.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 { ElementHandle } from 'puppeteer';
9 |
10 | const { setDefaultOptions } = require('expect-puppeteer');
11 |
12 | const timeout = 15 * 1000;
13 |
14 | jest.setTimeout(timeout);
15 | setDefaultOptions({ timeout });
16 |
17 | async function getXPath(xpath: string): Promise> {
18 | await page.waitForXPath(xpath);
19 | const elements = await page.$x(xpath);
20 | expect(elements.length).toBe(1);
21 | return elements[0];
22 | }
23 |
24 | function sleep(ms: number): Promise {
25 | return new Promise(resolve => setTimeout(resolve, ms));
26 | }
27 | describe('JupyterLab', () => {
28 | beforeAll(async () => {
29 | // Load JupyterLab:
30 | await page.goto('http://localhost:8080/lab?reset');
31 |
32 | // NOTE: depending on system resource constraints, this may NOT be enough time for JupyterLab to load and get "settled", so to speak. If CI tests begin inexplicably failing due to timeout failures, may want to consider increasing the sleep duration...
33 | await sleep(3000);
34 |
35 | // Attempt to find the data explorer tab on the page (all tests essentially presume that we can load the data explorer via the tab bar button):
36 | const el = await page.$('[title="Data Explorer"]');
37 | if (el !== null) {
38 | // Clicking on the data explorer tab should open the data explorer, thus allowing us to test data explorer UI interactions:
39 | el.click();
40 | } else {
41 | console.log('Unable to find expected tab.');
42 | }
43 | });
44 |
45 | it('should show JupyterLab logo', async () => {
46 | expect.assertions(1);
47 | await expect(page).toMatchElement('#jp-MainLogo', { visible: true } as any);
48 | });
49 |
50 | it("show be able to show 'Data Explorer' tab", async () => {
51 | expect.assertions(1);
52 | await expect(page).toMatchElement('.jl-explorer-heading', {
53 | text: 'Datasets',
54 | visible: true
55 | } as any);
56 | });
57 |
58 | it('should see files marker', async () => {
59 | expect.assertions(1);
60 | await expect(page).toMatchElement('h3', {
61 | text: 'file:///',
62 | visible: true
63 | } as any);
64 | });
65 |
66 | it('should be able to expand files', async () => {
67 | expect.assertions(1);
68 | const filebutton = await getXPath('//button[../h3/text()="file:///"]');
69 | await filebutton.click();
70 | });
71 |
72 | it('should see datasets.yml marker', async () => {
73 | expect.assertions(1);
74 | await expect(page).toMatchElement('h3', {
75 | text: 'datasets.yml',
76 | visible: true
77 | } as any);
78 | });
79 |
80 | it('should be able to expand datasets.yml', async () => {
81 | expect.assertions(1);
82 | const datasetsButton = await getXPath(
83 | '//button[../h3/text()="datasets.yml"]'
84 | );
85 | await datasetsButton.click();
86 | });
87 |
88 | it('should show datasets label', async () => {
89 | expect.assertions(1);
90 | await expect(page).toMatchElement('h3', {
91 | text: 'A Publication',
92 | visible: true
93 | } as any);
94 | });
95 |
96 | it("show be able to show 'Data Browser' tab", async () => {
97 | expect.assertions(2);
98 | await expect(page).toClick('[title="Data Browser"]');
99 | await expect(page).toMatchElement('.jl-dr-browser', {
100 | text: 'Follow active?',
101 | visible: true
102 | } as any);
103 | });
104 | });
105 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "allowSyntheticDefaultImports": true,
4 | "composite": true,
5 | "declaration": true,
6 | "skipLibCheck": true,
7 | "esModuleInterop": true,
8 | "jsx": "react",
9 | "module": "esnext",
10 | "moduleResolution": "node",
11 | "noEmitOnError": true,
12 | "noImplicitAny": true,
13 | "noUnusedLocals": true,
14 | "preserveWatchOutput": true,
15 | "resolveJsonModule": true,
16 | "outDir": "lib",
17 | "rootDir": "src",
18 | "lib": ["dom", "esnext"],
19 | "strict": true,
20 | "strictNullChecks": true,
21 | "target": "es2017"
22 | },
23 | "include": ["src/*"]
24 | }
25 |
--------------------------------------------------------------------------------
/tsconfig.test.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "./tsconfig.json",
3 | "compilerOptions": {
4 | "outDir": "build/test",
5 | "rootDir": "test"
6 | },
7 | "include": ["test/*", "test/**/*"]
8 | }
9 |
--------------------------------------------------------------------------------