@@ -11,30 +11,27 @@ import { ISettingRegistry } from '@jupyterlab/settingregistry';
1111import { runIcon } from '@jupyterlab/ui-components' ;
1212
1313import { requestAPI } from './handler' ;
14- import { METADATA_SQL_FORMAT , SqlWidget } from './widget' ;
14+ import { CommandIDs , METADATA_SQL_FORMAT , SqlCell } from './common' ;
15+ import { SqlWidget } from './widget' ;
1516
1617/**
17- * Initialization data for the @jupyter/sql- cell extension .
18+ * Load the commands and the cell toolbar buttons (from settings) .
1819 */
1920const plugin : JupyterFrontEndPlugin < void > = {
2021 id : '@jupyter/sql-cell:plugin' ,
21- description : 'A JupyterLab extension to run SQL in notebook dedicated cells ' ,
22+ description : 'Add the commands to the registry. ' ,
2223 autoStart : true ,
23- requires : [ INotebookTracker , IToolbarWidgetRegistry ] ,
24- optional : [ ICommandPalette , IDefaultFileBrowser , ISettingRegistry ] ,
24+ requires : [ INotebookTracker ] ,
25+ optional : [ ICommandPalette , IDefaultFileBrowser ] ,
2526 activate : (
2627 app : JupyterFrontEnd ,
2728 tracker : INotebookTracker ,
28- toolbarRegistry : IToolbarWidgetRegistry ,
29- commandPalette : ICommandPalette | null ,
30- fileBrowser : IDefaultFileBrowser | null ,
31- settingRegistry : ISettingRegistry | null
29+ commandPalette : ICommandPalette ,
30+ fileBrowser : IDefaultFileBrowser | null
3231 ) => {
3332 const { commands } = app ;
3433
35- const commandID = 'jupyter-sql-cell:execute' ;
36-
37- commands . addCommand ( commandID , {
34+ commands . addCommand ( CommandIDs . run , {
3835 label : 'Run SQL' ,
3936 caption : 'Run SQL' ,
4037 icon : runIcon ,
@@ -53,7 +50,7 @@ const plugin: JupyterFrontEndPlugin<void> = {
5350 body : JSON . stringify ( { query : source } )
5451 } )
5552 . then ( data => {
56- saveData ( path , data . data , date , fileBrowser )
53+ Private . saveData ( path , data . data , date , fileBrowser )
5754 . then ( dataPath => console . log ( `Data saved ${ dataPath } ` ) )
5855 . catch ( undefined ) ;
5956 } )
@@ -63,20 +60,65 @@ const plugin: JupyterFrontEndPlugin<void> = {
6360 ) ;
6461 } ) ;
6562 } ,
66- isEnabled : ( ) => {
63+ isEnabled : ( ) => SqlCell . isSqlCell ( tracker . activeCell ?. model ) ,
64+ isVisible : ( ) => SqlCell . isRaw ( tracker . activeCell ?. model )
65+ } ) ;
66+
67+ commands . addCommand ( CommandIDs . switchSQL , {
68+ label : 'SQL' ,
69+ caption : ( ) => {
6770 const model = tracker . activeCell ?. model ;
68- if ( ! model ) {
69- return false ;
71+ return SqlCell . isRaw ( model )
72+ ? SqlCell . isSqlCell ( model )
73+ ? 'Switch to Raw'
74+ : 'Switch to SQL'
75+ : 'Not available' ;
76+ } ,
77+ execute : async ( ) => {
78+ const model = tracker . activeCell ?. model ;
79+ if ( ! model || model . type !== 'raw' ) {
80+ return ;
7081 }
71- return (
72- model . type === 'raw' &&
73- model . getMetadata ( 'format' ) === METADATA_SQL_FORMAT
74- ) ;
75- }
82+ if ( model . getMetadata ( 'format' ) !== METADATA_SQL_FORMAT ) {
83+ model . setMetadata ( 'format' , METADATA_SQL_FORMAT ) ;
84+ } else if ( model . getMetadata ( 'format' ) === METADATA_SQL_FORMAT ) {
85+ model . deleteMetadata ( 'format' ) ;
86+ }
87+ app . commands . notifyCommandChanged ( CommandIDs . switchSQL ) ;
88+ app . commands . notifyCommandChanged ( CommandIDs . run ) ;
89+ } ,
90+ isVisible : ( ) => SqlCell . isRaw ( tracker . activeCell ?. model ) ,
91+ isToggled : ( ) => SqlCell . isSqlCell ( tracker . activeCell ?. model )
7692 } ) ;
7793
94+ if ( commandPalette ) {
95+ commandPalette . addItem ( {
96+ command : CommandIDs . run ,
97+ category : 'SQL'
98+ } ) ;
99+ }
100+ }
101+ } ;
102+
103+ /**
104+ * The notebook toolbar widget.
105+ */
106+ const notebookToolbarWidget : JupyterFrontEndPlugin < void > = {
107+ id : '@jupyter/sql-cell:notebook-toolbar' ,
108+ description : 'A JupyterLab extension to run SQL in notebook dedicated cells' ,
109+ autoStart : true ,
110+ requires : [ INotebookTracker , IToolbarWidgetRegistry ] ,
111+ optional : [ ISettingRegistry ] ,
112+ activate : (
113+ app : JupyterFrontEnd ,
114+ tracker : INotebookTracker ,
115+ toolbarRegistry : IToolbarWidgetRegistry ,
116+ settingRegistry : ISettingRegistry | null
117+ ) => {
118+ const { commands } = app ;
119+
78120 const toolbarFactory = ( panel : NotebookPanel ) => {
79- return new SqlWidget ( { commands, commandID, tracker } ) ;
121+ return new SqlWidget ( { commands, commandID : CommandIDs . run , tracker } ) ;
80122 } ;
81123
82124 toolbarRegistry . addFactory < NotebookPanel > (
@@ -87,7 +129,7 @@ const plugin: JupyterFrontEndPlugin<void> = {
87129
88130 if ( settingRegistry ) {
89131 settingRegistry
90- . load ( plugin . id )
132+ . load ( notebookToolbarWidget . id )
91133 . then ( settings => {
92134 console . log ( '@jupyter/sql-cell settings loaded:' , settings . composite ) ;
93135 } )
@@ -98,70 +140,65 @@ const plugin: JupyterFrontEndPlugin<void> = {
98140 ) ;
99141 } ) ;
100142 }
101-
102- if ( commandPalette ) {
103- commandPalette . addItem ( {
104- command : commandID ,
105- category : 'SQL'
106- } ) ;
107- }
108-
109- console . log ( 'JupyterLab extension @jupyter/sql-cell is activated!' ) ;
110143 }
111144} ;
112145
113- export default plugin ;
146+ export default [ notebookToolbarWidget , plugin ] ;
147+
148+ namespace Private {
149+ /**
150+ * Save data in a CSV file.
151+ *
152+ * @param path - the path to the directory where to save data.
153+ * @param data - the data to parse as CSV.
154+ * @param date - the query date.
155+ */
156+ export async function saveData (
157+ path : string ,
158+ data : any ,
159+ date : Date ,
160+ fileBrowser : IDefaultFileBrowser | null
161+ ) : Promise < string | undefined > {
162+ const contentsManager = new ContentsManager ( ) ;
163+ const parser = new Parser ( ) ;
164+ const csv = parser . parse ( data ) ;
165+
166+ const dateText = date
167+ . toLocaleString ( )
168+ . replace ( / [ / : ] / g, '-' )
169+ . replace ( / \s / g, '' )
170+ . replace ( ',' , '_' ) ;
171+
172+ let currentPath = '' ;
173+ if ( ! path . startsWith ( '/' ) ) {
174+ currentPath = `${ fileBrowser ?. model . path } /` || '' ;
175+ }
114176
115- /**
116- * Save data in a CSV file.
117- *
118- * @param path - the path to the directory where to save data.
119- * @param data - the data to parse as CSV.
120- * @param date - the query date.
121- */
122- async function saveData (
123- path : string ,
124- data : any ,
125- date : Date ,
126- fileBrowser : IDefaultFileBrowser | null
127- ) : Promise < string | undefined > {
128- const contentsManager = new ContentsManager ( ) ;
129- const parser = new Parser ( ) ;
130- const csv = parser . parse ( data ) ;
131-
132- const dateText = date
133- . toLocaleString ( )
134- . replace ( / [ / : ] / g, '-' )
135- . replace ( / \s / g, '' )
136- . replace ( ',' , '_' ) ;
137-
138- let currentPath = '' ;
139- if ( ! path . startsWith ( '/' ) ) {
140- currentPath = `${ fileBrowser ?. model . path } /` || '' ;
141- }
177+ for ( const directory of path . split ( '/' ) ) {
178+ currentPath = `${ currentPath } ${ directory } /` ;
179+ await contentsManager
180+ . get ( currentPath , { content : false } )
181+ . catch ( error =>
182+ contentsManager . save ( currentPath , { type : 'directory' } )
183+ ) ;
184+ }
142185
143- for ( const directory of path . split ( '/' ) ) {
144- currentPath = `${ currentPath } ${ directory } /` ;
145- await contentsManager
146- . get ( currentPath , { content : false } )
147- . catch ( ( ) => contentsManager . save ( currentPath , { type : 'directory' } ) ) ;
148- }
186+ const filename = `${ dateText } .csv` ;
187+ const fileModel = {
188+ name : filename ,
189+ path : `${ currentPath } /${ filename } ` ,
190+ format : 'text' as Contents . FileFormat ,
191+ content : csv
192+ } ;
149193
150- const filename = `${ dateText } .csv` ;
151- const fileModel = {
152- name : filename ,
153- path : `${ currentPath } /${ filename } ` ,
154- format : 'text' as Contents . FileFormat ,
155- content : csv
156- } ;
157-
158- return contentsManager
159- . save ( fileModel . path , fileModel )
160- . then ( ( ) => {
161- return fileModel . path ;
162- } )
163- . catch ( e => {
164- console . error ( e ) ;
165- return undefined ;
166- } ) ;
194+ return contentsManager
195+ . save ( fileModel . path , fileModel )
196+ . then ( ( ) => {
197+ return fileModel . path ;
198+ } )
199+ . catch ( e => {
200+ console . error ( e ) ;
201+ return undefined ;
202+ } ) ;
203+ }
167204}
0 commit comments