UNPKG

7.37 kBTypeScriptView Raw
1/*
2 * Copyright (c) Jupyter Development Team.
3 * Distributed under the terms of the Modified BSD License.
4 */
5
6import { Cell } from '@jupyterlab/cells';
7import { ITranslator, nullTranslator } from '@jupyterlab/translation';
8import {
9 notTrustedIcon,
10 trustedIcon,
11 VDomModel,
12 VDomRenderer
13} from '@jupyterlab/ui-components';
14import React from 'react';
15import { INotebookModel, Notebook } from '.';
16
17const TRUST_CLASS = 'jp-StatusItem-trust';
18
19/**
20 * Determine the notebook trust status message.
21 */
22function cellTrust(
23 props: NotebookTrustComponent.IProps | NotebookTrustStatus.Model,
24 translator?: ITranslator
25): string {
26 translator = translator || nullTranslator;
27 const trans = translator.load('jupyterlab');
28
29 if (props.trustedCells === props.totalCells) {
30 return trans.__(
31 'Notebook trusted: %1 of %2 code cells trusted.',
32 props.trustedCells,
33 props.totalCells
34 );
35 } else if (props.activeCellTrusted) {
36 return trans.__(
37 'Active cell trusted: %1 of %2 code cells trusted.',
38 props.trustedCells,
39 props.totalCells
40 );
41 } else {
42 return trans.__(
43 'Notebook not trusted: %1 of %2 code cells trusted.',
44 props.trustedCells,
45 props.totalCells
46 );
47 }
48}
49
50/**
51 * A pure function for a notebook trust status component.
52 *
53 * @param props: the props for the component.
54 *
55 * @returns a tsx component for notebook trust.
56 */
57function NotebookTrustComponent(
58 props: NotebookTrustComponent.IProps
59): React.ReactElement<NotebookTrustComponent.IProps> {
60 if (props.allCellsTrusted) {
61 return <trustedIcon.react top={'2px'} stylesheet={'statusBar'} />;
62 } else {
63 return <notTrustedIcon.react top={'2px'} stylesheet={'statusBar'} />;
64 }
65}
66
67/**
68 * A namespace for NotebookTrustComponent statics.
69 */
70namespace NotebookTrustComponent {
71 /**
72 * Props for the NotebookTrustComponent.
73 */
74 export interface IProps {
75 /**
76 * Whether all the cells are trusted.
77 */
78 allCellsTrusted: boolean;
79
80 /**
81 * Whether the currently active cell is trusted.
82 */
83 activeCellTrusted: boolean;
84
85 /**
86 * The total number of code cells for the current notebook.
87 */
88 totalCells: number;
89
90 /**
91 * The number of trusted code cells for the current notebook.
92 */
93 trustedCells: number;
94 }
95}
96
97/**
98 * The NotebookTrust status item.
99 */
100export class NotebookTrustStatus extends VDomRenderer<NotebookTrustStatus.Model> {
101 /**
102 * Construct a new status item.
103 */
104 constructor(translator?: ITranslator) {
105 super(new NotebookTrustStatus.Model());
106 this.translator = translator || nullTranslator;
107 this.node.classList.add(TRUST_CLASS);
108 }
109
110 /**
111 * Render the NotebookTrust status item.
112 */
113 render(): JSX.Element | null {
114 if (!this.model) {
115 return null;
116 }
117 const newTitle = cellTrust(this.model, this.translator);
118 if (newTitle !== this.node.title) {
119 this.node.title = newTitle;
120 }
121 return (
122 <NotebookTrustComponent
123 allCellsTrusted={this.model.trustedCells === this.model.totalCells}
124 activeCellTrusted={this.model.activeCellTrusted}
125 totalCells={this.model.totalCells}
126 trustedCells={this.model.trustedCells}
127 />
128 );
129 }
130
131 translator: ITranslator;
132}
133
134/**
135 * A namespace for NotebookTrust statics.
136 */
137export namespace NotebookTrustStatus {
138 /**
139 * A VDomModel for the NotebookTrust status item.
140 */
141 export class Model extends VDomModel {
142 /**
143 * The number of trusted code cells in the current notebook.
144 */
145 get trustedCells(): number {
146 return this._trustedCells;
147 }
148
149 /**
150 * The total number of code cells in the current notebook.
151 */
152 get totalCells(): number {
153 return this._totalCells;
154 }
155
156 /**
157 * Whether the active cell is trusted.
158 */
159 get activeCellTrusted(): boolean {
160 return this._activeCellTrusted;
161 }
162
163 /**
164 * The current notebook for the model.
165 */
166 get notebook(): Notebook | null {
167 return this._notebook;
168 }
169 set notebook(model: Notebook | null) {
170 const oldNotebook = this._notebook;
171 if (oldNotebook !== null) {
172 oldNotebook.activeCellChanged.disconnect(
173 this._onActiveCellChanged,
174 this
175 );
176
177 oldNotebook.modelContentChanged.disconnect(this._onModelChanged, this);
178 }
179
180 const oldState = this._getAllState();
181 this._notebook = model;
182 if (this._notebook === null) {
183 this._trustedCells = 0;
184 this._totalCells = 0;
185 this._activeCellTrusted = false;
186 } else {
187 // Add listeners
188 this._notebook.activeCellChanged.connect(
189 this._onActiveCellChanged,
190 this
191 );
192 this._notebook.modelContentChanged.connect(this._onModelChanged, this);
193
194 // Derive values
195 if (this._notebook.activeCell) {
196 this._activeCellTrusted = this._notebook.activeCell.model.trusted;
197 } else {
198 this._activeCellTrusted = false;
199 }
200
201 const { total, trusted } = this._deriveCellTrustState(
202 this._notebook.model
203 );
204
205 this._totalCells = total;
206 this._trustedCells = trusted;
207 }
208
209 this._triggerChange(oldState, this._getAllState());
210 }
211
212 /**
213 * When the notebook model changes, update the trust state.
214 */
215 private _onModelChanged(notebook: Notebook): void {
216 const oldState = this._getAllState();
217 const { total, trusted } = this._deriveCellTrustState(notebook.model);
218
219 this._totalCells = total;
220 this._trustedCells = trusted;
221 this._triggerChange(oldState, this._getAllState());
222 }
223
224 /**
225 * When the active cell changes, update the trust state.
226 */
227 private _onActiveCellChanged(model: Notebook, cell: Cell | null): void {
228 const oldState = this._getAllState();
229 if (cell) {
230 this._activeCellTrusted = cell.model.trusted;
231 } else {
232 this._activeCellTrusted = false;
233 }
234 this._triggerChange(oldState, this._getAllState());
235 }
236
237 /**
238 * Given a notebook model, figure out how many of the code cells are trusted.
239 */
240 private _deriveCellTrustState(model: INotebookModel | null): {
241 total: number;
242 trusted: number;
243 } {
244 if (model === null) {
245 return { total: 0, trusted: 0 };
246 }
247 let total = 0;
248 let trusted = 0;
249 for (const cell of model.cells) {
250 if (cell.type !== 'code') {
251 continue;
252 }
253 total++;
254 if (cell.trusted) {
255 trusted++;
256 }
257 }
258 return { total, trusted };
259 }
260
261 /**
262 * Get the current state of the model.
263 */
264 private _getAllState(): [number, number, boolean] {
265 return [this._trustedCells, this._totalCells, this.activeCellTrusted];
266 }
267
268 /**
269 * Trigger a change in the renderer.
270 */
271 private _triggerChange(
272 oldState: [number, number, boolean],
273 newState: [number, number, boolean]
274 ) {
275 if (
276 oldState[0] !== newState[0] ||
277 oldState[1] !== newState[1] ||
278 oldState[2] !== newState[2]
279 ) {
280 this.stateChanged.emit(void 0);
281 }
282 }
283
284 private _trustedCells: number = 0;
285 private _totalCells: number = 0;
286 private _activeCellTrusted: boolean = false;
287 private _notebook: Notebook | null = null;
288 }
289}