1
+
2
+ import { Widget } from '@lumino/widgets' ;
3
+ import { RequestHandler } from '@elyra/application' ;
4
+
5
+ import checkSVGstr from '../style/check.svg' ;
6
+ import { showMessage } from './ConfirmMessage' ;
7
+
8
+ import { Dialog , showDialog } from '@jupyterlab/apputils' ;
9
+
10
+ import { Contents } from '@jupyterlab/services' ;
11
+
12
+ import { JSONObject } from '@lumino/coreutils' ;
13
+
14
+ import { ICodeSnippet } from './CodeSnippetService'
15
+
16
+ import { IDocumentManager } from '@jupyterlab/docmanager' ;
17
+ import { CodeSnippetWidget } from './CodeSnippetWidget' ;
18
+
19
+ /**
20
+ * The class name added to file dialogs.
21
+ */
22
+ const FILE_DIALOG_CLASS = 'jp-FileDialog' ;
23
+
24
+ /**
25
+ * The class name added for the new name label in the rename dialog
26
+ */
27
+ const INPUT_NEWNAME_TITLE_CLASS = 'jp-new-name-title' ;
28
+
29
+ /**
30
+ * A stripped-down interface for a file container.
31
+ */
32
+ export interface IFileContainer extends JSONObject {
33
+ /**
34
+ * The list of item names in the current working directory.
35
+ */
36
+ items : string [ ] ;
37
+ /**
38
+ * The current working directory of the file container.
39
+ */
40
+ path : string ;
41
+ }
42
+
43
+ /**
44
+ * Save an input with a dialog. This is what actually displays everything.
45
+ * Result.value is the value retrieved from .getValue(). ---> .getValue() returns an array of inputs.
46
+ */
47
+ export function inputDialog (
48
+ codeSnippet : CodeSnippetWidget ,
49
+ url : string ,
50
+ inputCode : string
51
+ ) : Promise < Contents . IModel | null > {
52
+ return showDialog ( {
53
+ title : 'Save Code Snippet' ,
54
+ body : new InputHandler ( ) ,
55
+ focusNodeSelector : 'input' ,
56
+ buttons : [ Dialog . cancelButton ( ) , Dialog . okButton ( { label : 'Save' } ) ]
57
+ } ) . then ( result => {
58
+ console . log ( result . value ) ;
59
+ if ( ! result . value ) {
60
+ return null ;
61
+ }
62
+ else {
63
+ /* TODO: if name is already there call shouldOverwrite and change to a put request*/
64
+ // Workaround: make a get request with result.value[0] to check... but could be slow
65
+ RequestHandler . makePostRequest ( //If i use their handler then I can't interrupt any error messages without editing their stuff.
66
+ url ,
67
+ JSON . stringify ( {
68
+ display_name : result . value [ 0 ] ,
69
+ metadata : {
70
+ code : [
71
+ inputCode
72
+ ] ,
73
+ description : result . value [ 1 ] ,
74
+ language : result . value [ 2 ] ,
75
+ } ,
76
+ name : result . value [ 0 ] . replace ( ' ' , '' ) . toLowerCase ( ) ,
77
+ schema_name : "code-snippet" ,
78
+ } ) ,
79
+ false
80
+ ) ;
81
+ codeSnippet . fetchData ( ) . then ( ( codeSnippets : ICodeSnippet [ ] ) => {
82
+ console . log ( "HELLLO" ) ;
83
+ codeSnippet . renderCodeSnippetsSignal . emit ( codeSnippets ) } ) ;
84
+ showMessage ( {
85
+ body : /*"Saved as Snippet"*/ new MessageHandler ( )
86
+ } ) ;
87
+ }
88
+ // if (!isValidFileName(result.value)) {
89
+ // void showErrorMessage(
90
+ // 'Rename Error',
91
+ // Error(
92
+ // `"${result.value}" is not a valid name for a file. ` +
93
+ // `Names must have nonzero length, ` +
94
+ // `and cannot include "/", "\\", or ":"`
95
+ // )
96
+ // );
97
+ // return null;
98
+ // }
99
+ //const basePath = PathExt.dirname(oldPath);
100
+ //const newPath = PathExt.join(basePath, result.value);
101
+ } ) ;
102
+ }
103
+
104
+ /**
105
+ * Rename a file, asking for confirmation if it is overwriting another.
106
+ */
107
+ export function renameFile (
108
+ manager : IDocumentManager ,
109
+ oldPath : string ,
110
+ newPath : string
111
+ ) : Promise < Contents . IModel | null > {
112
+ return manager . rename ( oldPath , newPath ) . catch ( error => {
113
+ if ( error . message . indexOf ( '409' ) === - 1 ) {
114
+ throw error ;
115
+ }
116
+ return shouldOverwrite ( newPath ) . then ( value => {
117
+ if ( value ) {
118
+ return manager . overwrite ( oldPath , newPath ) ;
119
+ }
120
+ return Promise . reject ( 'File not renamed' ) ;
121
+ } ) ;
122
+ } ) ;
123
+ }
124
+
125
+ /**
126
+ * Ask the user whether to overwrite a file.
127
+ */
128
+ export function shouldOverwrite ( path : string ) : Promise < boolean > {
129
+ const options = {
130
+ title : 'Overwrite file?' ,
131
+ body : `"${ path } " already exists, overwrite?` ,
132
+ buttons : [ Dialog . cancelButton ( ) , Dialog . warnButton ( { label : 'Overwrite' } ) ]
133
+ } ;
134
+ return showDialog ( options ) . then ( result => {
135
+ return Promise . resolve ( result . button . accept ) ;
136
+ } ) ;
137
+ }
138
+
139
+ /**
140
+ * Test whether a name is a valid file name
141
+ *
142
+ * Disallows "/", "\", and ":" in file names, as well as names with zero length.
143
+ */
144
+ export function isValidFileName ( name : string ) : boolean {
145
+ const validNameExp = / [ \/ \\ : ] / ;
146
+ return name . length > 0 && ! validNameExp . test ( name ) ;
147
+ }
148
+
149
+ /**
150
+ * A widget used to get input data.
151
+ */
152
+ class InputHandler extends Widget {
153
+ /**
154
+ * Construct a new "rename" dialog.
155
+ * readonly inputNode: HTMLInputElement; <--- in Widget class
156
+ */
157
+ constructor ( ) {
158
+ super ( { node : Private . createInputNode ( ) } ) ;
159
+ this . addClass ( FILE_DIALOG_CLASS ) ;
160
+ }
161
+
162
+ getValue ( ) : string [ ] {
163
+ let inputs = [ ] ;
164
+ inputs . push ( ( this . node . getElementsByTagName ( 'input' ) [ 0 ] as HTMLInputElement ) . value ,
165
+ ( this . node . getElementsByTagName ( 'input' ) [ 1 ] as HTMLInputElement ) . value ,
166
+ ( this . node . getElementsByTagName ( 'input' ) [ 2 ] as HTMLInputElement ) . value ) ;
167
+ return inputs ;
168
+ }
169
+ }
170
+
171
+
172
+ class MessageHandler extends Widget {
173
+ constructor ( ) {
174
+ super ( { node : Private . createConfirmMessageNode ( ) } ) ;
175
+ }
176
+ }
177
+
178
+ /**
179
+ * A namespace for private data.
180
+ */
181
+ namespace Private {
182
+ /**
183
+ * Create the node for a rename handler. This is what's creating all of the elements to be displayed.
184
+ */
185
+ export function createInputNode ( ) : HTMLElement {
186
+ const body = document . createElement ( 'div' ) ;
187
+
188
+ const nameTitle = document . createElement ( 'label' ) ;
189
+ nameTitle . textContent = 'Snippet Name*' ;
190
+ nameTitle . className = INPUT_NEWNAME_TITLE_CLASS ;
191
+ const name = document . createElement ( 'input' ) ;
192
+
193
+ const descriptionTitle = document . createElement ( 'label' ) ;
194
+ descriptionTitle . textContent = 'Description*' ;
195
+ descriptionTitle . className = INPUT_NEWNAME_TITLE_CLASS ;
196
+ const description = document . createElement ( 'input' ) ;
197
+
198
+ const languageTitle = document . createElement ( 'label' ) ;
199
+ languageTitle . textContent = 'Language*' ;
200
+ languageTitle . className = INPUT_NEWNAME_TITLE_CLASS ;
201
+ const language = document . createElement ( 'input' ) ;
202
+
203
+ body . appendChild ( nameTitle ) ;
204
+ body . appendChild ( name ) ;
205
+ body . appendChild ( descriptionTitle ) ;
206
+ body . appendChild ( description ) ;
207
+ body . appendChild ( languageTitle ) ;
208
+ body . appendChild ( language ) ;
209
+ return body ;
210
+ }
211
+
212
+ export function createConfirmMessageNode ( ) : HTMLElement {
213
+ const body = document . createElement ( 'div' ) ;
214
+ body . innerHTML = checkSVGstr ;
215
+
216
+ const messageContainer = document . createElement ( 'div' ) ;
217
+ messageContainer . className = 'jp-confirm-text' ;
218
+ const message = document . createElement ( 'text' ) ;
219
+ message . textContent = 'Saved as Snippet!' ;
220
+ messageContainer . appendChild ( message )
221
+ body . append ( messageContainer ) ;
222
+ return body ;
223
+ }
224
+ }
0 commit comments