UNPKG

4.91 kBTypeScriptView Raw
1// Copyright (c) Jupyter Development Team.
2// Distributed under the terms of the Modified BSD License.
3
4import { DocumentRegistry } from '@jupyterlab/docregistry';
5import { TextItem } from '@jupyterlab/statusbar';
6import { ITranslator, nullTranslator } from '@jupyterlab/translation';
7import { VDomModel, VDomRenderer } from '@jupyterlab/ui-components';
8import { Widget } from '@lumino/widgets';
9import React from 'react';
10import { IDocumentManager } from './tokens';
11
12/**
13 * A namespace for SavingStatusComponent statics.
14 */
15namespace SavingStatusComponent {
16 /**
17 * The props for the SavingStatusComponent.
18 */
19 export interface IProps {
20 /**
21 * The current saving status, after translation.
22 */
23 fileStatus: string;
24 }
25}
26
27/**
28 * A pure functional component for a Saving status item.
29 *
30 * @param props - the props for the component.
31 *
32 * @returns a tsx component for rendering the saving state.
33 */
34function SavingStatusComponent(
35 props: SavingStatusComponent.IProps
36): React.ReactElement<SavingStatusComponent.IProps> {
37 return <TextItem source={props.fileStatus} />;
38}
39
40/**
41 * The amount of time (in ms) to retain the saving completed message
42 * before hiding the status item.
43 */
44const SAVING_COMPLETE_MESSAGE_MILLIS = 2000;
45
46/**
47 * A VDomRenderer for a saving status item.
48 */
49export class SavingStatus extends VDomRenderer<SavingStatus.Model> {
50 /**
51 * Create a new SavingStatus item.
52 */
53 constructor(opts: SavingStatus.IOptions) {
54 super(new SavingStatus.Model(opts.docManager));
55 const translator = opts.translator || nullTranslator;
56 const trans = translator.load('jupyterlab');
57 this._statusMap = {
58 completed: trans.__('Saving completed'),
59 started: trans.__('Saving started'),
60 failed: trans.__('Saving failed')
61 };
62 }
63
64 /**
65 * Render the SavingStatus item.
66 */
67 render(): JSX.Element | null {
68 if (this.model === null || this.model.status === null) {
69 return null;
70 } else {
71 return (
72 <SavingStatusComponent
73 fileStatus={this._statusMap[this.model.status]}
74 />
75 );
76 }
77 }
78
79 private _statusMap: Record<DocumentRegistry.SaveState, string>;
80}
81
82/**
83 * A namespace for SavingStatus statics.
84 */
85export namespace SavingStatus {
86 /**
87 * A VDomModel for the SavingStatus item.
88 */
89 export class Model extends VDomModel {
90 /**
91 * Create a new SavingStatus model.
92 */
93 constructor(docManager: IDocumentManager) {
94 super();
95
96 this._status = null;
97 this.widget = null;
98 this._docManager = docManager;
99 }
100
101 /**
102 * The current status of the model.
103 */
104 get status(): DocumentRegistry.SaveState | null {
105 return this._status!;
106 }
107
108 /**
109 * The current widget for the model. Any widget can be assigned,
110 * but it only has any effect if the widget is an IDocument widget
111 * known to the application document manager.
112 */
113 get widget(): Widget | null {
114 return this._widget;
115 }
116 set widget(widget: Widget | null) {
117 const oldWidget = this._widget;
118 if (oldWidget !== null) {
119 const oldContext = this._docManager.contextForWidget(oldWidget);
120 if (oldContext) {
121 oldContext.saveState.disconnect(this._onStatusChange);
122 } else if ((this._widget as any).content?.saveStateChanged) {
123 (this._widget as any).content.saveStateChanged.disconnect(
124 this._onStatusChange
125 );
126 }
127 }
128
129 this._widget = widget;
130 if (this._widget === null) {
131 this._status = null;
132 } else {
133 const widgetContext = this._docManager.contextForWidget(this._widget);
134 if (widgetContext) {
135 widgetContext.saveState.connect(this._onStatusChange);
136 } else if ((this._widget as any).content?.saveStateChanged) {
137 (this._widget as any).content.saveStateChanged.connect(
138 this._onStatusChange
139 );
140 }
141 }
142 }
143
144 /**
145 * React to a saving status change from the current document widget.
146 */
147 private _onStatusChange = (
148 _: any,
149 newStatus: DocumentRegistry.SaveState
150 ) => {
151 this._status = newStatus;
152
153 if (this._status === 'completed') {
154 setTimeout(() => {
155 this._status = null;
156 this.stateChanged.emit(void 0);
157 }, SAVING_COMPLETE_MESSAGE_MILLIS);
158 this.stateChanged.emit(void 0);
159 } else {
160 this.stateChanged.emit(void 0);
161 }
162 };
163
164 private _status: DocumentRegistry.SaveState | null = null;
165 private _widget: Widget | null = null;
166 private _docManager: IDocumentManager;
167 }
168
169 /**
170 * Options for creating a new SaveStatus item
171 */
172 export interface IOptions {
173 /**
174 * The application document manager.
175 */
176 docManager: IDocumentManager;
177
178 /**
179 * The application language translator.
180 */
181 translator?: ITranslator;
182 }
183}