From 91aba26814f2ed433498c4ed9e2ad6d4aeba8c11 Mon Sep 17 00:00:00 2001 From: Jeremy Tuloup Date: Thu, 16 Feb 2023 13:24:50 +0000 Subject: [PATCH 1/6] Add trusted indicator --- packages/notebook-extension/src/index.ts | 34 ++++++- packages/notebook-extension/src/trusted.tsx | 101 ++++++++++++++++++++ packages/notebook-extension/style/base.css | 13 +++ 3 files changed, 147 insertions(+), 1 deletion(-) create mode 100644 packages/notebook-extension/src/trusted.tsx diff --git a/packages/notebook-extension/src/index.ts b/packages/notebook-extension/src/index.ts index 9ee368a31a..8de449f8a2 100644 --- a/packages/notebook-extension/src/index.ts +++ b/packages/notebook-extension/src/index.ts @@ -34,6 +34,8 @@ import { Poll } from '@lumino/polling'; import { Widget } from '@lumino/widgets'; +import { TrustedComponent } from './trusted'; + /** * The class for kernel status errors. */ @@ -364,6 +366,35 @@ const notebookToolsWidget: JupyterFrontEndPlugin = { } }; +/** + * A plugin that adds a Trusted indicator to the menu area + */ +const trusted: JupyterFrontEndPlugin = { + id: '@jupyter-notebook/notebook-extension:trusted', + autoStart: true, + requires: [INotebookShell, ITranslator], + activate: ( + app: JupyterFrontEnd, + notebookShell: INotebookShell, + translator: ITranslator + ): void => { + const onChange = async () => { + const current = notebookShell.currentWidget; + if (!(current instanceof NotebookPanel)) { + return; + } + + const notebook = current.content; + await current.context.ready; + + const widget = TrustedComponent.create({ notebook, translator }); + notebookShell.add(widget, 'menu', { rank: 11_000 }); + }; + + notebookShell.currentChanged.connect(onChange); + } +}; + /** * Export the plugins as default. */ @@ -372,7 +403,8 @@ const plugins: JupyterFrontEndPlugin[] = [ kernelLogo, kernelStatus, scrollOutput, - notebookToolsWidget + notebookToolsWidget, + trusted, ]; export default plugins; diff --git a/packages/notebook-extension/src/trusted.tsx b/packages/notebook-extension/src/trusted.tsx new file mode 100644 index 0000000000..87515b7291 --- /dev/null +++ b/packages/notebook-extension/src/trusted.tsx @@ -0,0 +1,101 @@ +import { ReactWidget } from '@jupyterlab/apputils'; + +import { Notebook, NotebookActions } from '@jupyterlab/notebook'; + +import { ITranslator } from '@jupyterlab/translation'; + +import { toArray } from '@lumino/algorithm'; + +import React, { useEffect, useState } from 'react'; + +const isTrusted = (notebook: Notebook): boolean => { + const model = notebook.model; + if (!model) { + return false; + } + const cells = toArray(model.cells); + + const trusted = cells.reduce((accum, current) => { + if (current.trusted) { + return accum + 1; + } else { + return accum; + } + }, 0); + + const total = cells.length; + return trusted === total; +}; + +/** + * A React component to display the Trusted badge in the menu bar. + * @param notebook The Notebook + * @param translator The Translation service + */ +const TrustedButton = ({ + notebook, + translator +}: { + notebook: Notebook; + translator: ITranslator; +}): JSX.Element => { + const trans = translator.load('retrolab'); + const [trusted, setTrusted] = useState(isTrusted(notebook)); + + const checkTrust = () => { + const v = isTrusted(notebook); + setTrusted(v); + }; + + const trust = async () => { + await NotebookActions.trust(notebook, translator); + checkTrust(); + }; + + useEffect(() => { + notebook.modelContentChanged.connect(checkTrust); + notebook.activeCellChanged.connect(checkTrust); + return () => { + notebook.modelContentChanged.disconnect(checkTrust); + notebook.activeCellChanged.disconnect(checkTrust); + }; + }); + + return ( + + ); +}; + +/** + * A namespace for TrustedComponent statics. + */ +export namespace TrustedComponent { + /** + * Create a new TrustedComponent + * + * @param notebook The notebook + * @param translator The translator + */ + export const create = ({ + notebook, + translator + }: { + notebook: Notebook; + translator: ITranslator; + }): ReactWidget => { + return ReactWidget.create( + + ); + }; +} diff --git a/packages/notebook-extension/style/base.css b/packages/notebook-extension/style/base.css index f26b23e606..6617940767 100644 --- a/packages/notebook-extension/style/base.css +++ b/packages/notebook-extension/style/base.css @@ -220,6 +220,19 @@ body[data-notebook='notebooks'] animation: 0.5s fade-out forwards; } +.jp-RetroTrustedStatus { + background: var(--jp-layout-color1); + color: var(--jp-ui-font-color1); + margin-top: 4px; + margin-bottom: 4px; + border: solid 1px var(--jp-border-color2); + cursor: help; +} + +.jp-RetroTrustedStatus-not-trusted { + cursor: pointer; +} + @keyframes fade-out { 0% { opacity: 1; From fe5f291f0d4f99bb9d9c899e261e2d8fe8a5e63b Mon Sep 17 00:00:00 2001 From: Jeremy Tuloup Date: Thu, 16 Feb 2023 13:32:35 +0000 Subject: [PATCH 2/6] Lint --- packages/notebook-extension/src/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/notebook-extension/src/index.ts b/packages/notebook-extension/src/index.ts index 8de449f8a2..88f204cf53 100644 --- a/packages/notebook-extension/src/index.ts +++ b/packages/notebook-extension/src/index.ts @@ -404,7 +404,7 @@ const plugins: JupyterFrontEndPlugin[] = [ kernelStatus, scrollOutput, notebookToolsWidget, - trusted, + trusted ]; export default plugins; From 1c02d144a1ebd614605dcd129908f3efbf6b8743 Mon Sep 17 00:00:00 2001 From: Jeremy Tuloup Date: Thu, 16 Feb 2023 14:12:16 +0000 Subject: [PATCH 3/6] Add docstring --- packages/notebook-extension/src/trusted.tsx | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/packages/notebook-extension/src/trusted.tsx b/packages/notebook-extension/src/trusted.tsx index 87515b7291..beaf275838 100644 --- a/packages/notebook-extension/src/trusted.tsx +++ b/packages/notebook-extension/src/trusted.tsx @@ -8,6 +8,11 @@ import { toArray } from '@lumino/algorithm'; import React, { useEffect, useState } from 'react'; +/** + * Check if a notebook is trusted + * @param notebook The notebook to check + * @returns true if the notebook is trusted, false otherwise + */ const isTrusted = (notebook: Notebook): boolean => { const model = notebook.model; if (!model) { @@ -55,6 +60,7 @@ const TrustedButton = ({ useEffect(() => { notebook.modelContentChanged.connect(checkTrust); notebook.activeCellChanged.connect(checkTrust); + checkTrust(); return () => { notebook.modelContentChanged.disconnect(checkTrust); notebook.activeCellChanged.disconnect(checkTrust); From aef4b323dd8c8d180cd21a293437818cd42cd7ad Mon Sep 17 00:00:00 2001 From: Jeremy Tuloup Date: Thu, 16 Feb 2023 14:13:20 +0000 Subject: [PATCH 4/6] Fix retro names --- packages/notebook-extension/src/trusted.tsx | 4 ++-- packages/notebook-extension/style/base.css | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/notebook-extension/src/trusted.tsx b/packages/notebook-extension/src/trusted.tsx index beaf275838..53e77b1f6b 100644 --- a/packages/notebook-extension/src/trusted.tsx +++ b/packages/notebook-extension/src/trusted.tsx @@ -44,7 +44,7 @@ const TrustedButton = ({ notebook: Notebook; translator: ITranslator; }): JSX.Element => { - const trans = translator.load('retrolab'); + const trans = translator.load('notebook'); const [trusted, setTrusted] = useState(isTrusted(notebook)); const checkTrust = () => { @@ -69,7 +69,7 @@ const TrustedButton = ({ return (