mirror of
				https://github.com/TriliumNext/Notes.git
				synced 2025-10-31 13:01:31 +08:00 
			
		
		
		
	refactoring of sql console into separate widgets
This commit is contained in:
		
							parent
							
								
									1d64129572
								
							
						
					
					
						commit
						02d9752abf
					
				
							
								
								
									
										32
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										32
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							| @ -1792,9 +1792,9 @@ | ||||
|       "dev": true | ||||
|     }, | ||||
|     "caniuse-lite": { | ||||
|       "version": "1.0.30001168", | ||||
|       "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001168.tgz", | ||||
|       "integrity": "sha512-P2zmX7swIXKu+GMMR01TWa4csIKELTNnZKc+f1CjebmZJQtTAEXmpQSoKVJVVcvPGAA0TEYTOUp3VehavZSFPQ==", | ||||
|       "version": "1.0.30001170", | ||||
|       "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001170.tgz", | ||||
|       "integrity": "sha512-Dd4d/+0tsK0UNLrZs3CvNukqalnVTRrxb5mcQm8rHL49t7V5ZaTygwXkrq+FB+dVDf++4ri8eJnFEJAB8332PA==", | ||||
|       "dev": true | ||||
|     }, | ||||
|     "caseless": { | ||||
| @ -3209,9 +3209,9 @@ | ||||
|       } | ||||
|     }, | ||||
|     "electron-to-chromium": { | ||||
|       "version": "1.3.629", | ||||
|       "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.629.tgz", | ||||
|       "integrity": "sha512-iSPPJtPvHrMAvYOt+9cdbDmTasPqwnwz4lkP8Dn200gDNUBQOLQ96xUsWXBwXslAo5XxdoXAoQQ3RAy4uao9IQ==", | ||||
|       "version": "1.3.633", | ||||
|       "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.633.tgz", | ||||
|       "integrity": "sha512-bsVCsONiVX1abkWdH7KtpuDAhsQ3N3bjPYhROSAXE78roJKet0Y5wznA14JE9pzbwSZmSMAW6KiKYf1RvbTJkA==", | ||||
|       "dev": true | ||||
|     }, | ||||
|     "electron-window-state": { | ||||
| @ -3250,13 +3250,13 @@ | ||||
|       } | ||||
|     }, | ||||
|     "enhanced-resolve": { | ||||
|       "version": "5.4.0", | ||||
|       "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.4.0.tgz", | ||||
|       "integrity": "sha512-ZmqfWURB2lConOBM1JdCVfPyMRv5RdKWktLXO6123p97ovVm2CLBgw9t5MBj3jJWA6eHyOeIws9iJQoGFR4euQ==", | ||||
|       "version": "5.4.1", | ||||
|       "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.4.1.tgz", | ||||
|       "integrity": "sha512-4GbyIMzYktTFoRSmkbgZ1LU+RXwf4AQ8Z+rSuuh1dC8plp0PPeaWvx6+G4hh4KnUJ48VoxKbNyA1QQQIUpXjYA==", | ||||
|       "dev": true, | ||||
|       "requires": { | ||||
|         "graceful-fs": "^4.2.4", | ||||
|         "tapable": "^2.0.0" | ||||
|         "tapable": "^2.2.0" | ||||
|       }, | ||||
|       "dependencies": { | ||||
|         "graceful-fs": { | ||||
| @ -4142,9 +4142,9 @@ | ||||
|       "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==" | ||||
|     }, | ||||
|     "helmet": { | ||||
|       "version": "4.2.0", | ||||
|       "resolved": "https://registry.npmjs.org/helmet/-/helmet-4.2.0.tgz", | ||||
|       "integrity": "sha512-aoiSxXMd0ks1ojYpSCFoCRzgv4rY/uB9jKStaw8PkXwsdLYa/Gq+Nc5l0soH0cwBIsLAlujPnx4HLQs+LaXCrQ==" | ||||
|       "version": "4.3.1", | ||||
|       "resolved": "https://registry.npmjs.org/helmet/-/helmet-4.3.1.tgz", | ||||
|       "integrity": "sha512-WsafDyKsIexB0+pUNkq3rL1rB5GVAghR68TP8ssM9DPEMzfBiluEQlVzJ/FEj6Vq2Ag3CNuxf7aYMjXrN0X49Q==" | ||||
|     }, | ||||
|     "hosted-git-info": { | ||||
|       "version": "2.8.5", | ||||
| @ -7597,9 +7597,9 @@ | ||||
|       "integrity": "sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w==" | ||||
|     }, | ||||
|     "webpack": { | ||||
|       "version": "5.11.0", | ||||
|       "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.11.0.tgz", | ||||
|       "integrity": "sha512-ubWv7iP54RqAC/VjixgpnLLogCFbAfSOREcSWnnOlZEU8GICC5eKmJSu6YEnph2N2amKqY9rvxSwgyHxVqpaRw==", | ||||
|       "version": "5.11.1", | ||||
|       "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.11.1.tgz", | ||||
|       "integrity": "sha512-tNUIdAmYJv+nupRs/U/gqmADm6fgrf5xE+rSlSsf2PgsGO7j2WG7ccU6AWNlOJlHFl+HnmXlBmHIkiLf+XA9mQ==", | ||||
|       "dev": true, | ||||
|       "requires": { | ||||
|         "@types/eslint-scope": "^3.7.0", | ||||
|  | ||||
| @ -41,7 +41,7 @@ | ||||
|     "express": "4.17.1", | ||||
|     "express-session": "1.17.1", | ||||
|     "fs-extra": "9.0.1", | ||||
|     "helmet": "4.2.0", | ||||
|     "helmet": "4.3.1", | ||||
|     "html": "1.0.0", | ||||
|     "html2plaintext": "2.1.2", | ||||
|     "http-proxy-agent": "4.0.1", | ||||
| @ -86,7 +86,7 @@ | ||||
|     "jsdoc": "3.6.6", | ||||
|     "lorem-ipsum": "2.0.3", | ||||
|     "rcedit": "3.0.0", | ||||
|     "webpack": "5.11.0", | ||||
|     "webpack": "5.11.1", | ||||
|     "webpack-cli": "4.3.0" | ||||
|   }, | ||||
|   "optionalDependencies": { | ||||
|  | ||||
| @ -5,7 +5,6 @@ import TitleBarButtonsWidget from "../widgets/title_bar_buttons.js"; | ||||
| import NoteTreeWidget from "../widgets/note_tree.js"; | ||||
| import TabCachingWidget from "../widgets/tab_caching_widget.js"; | ||||
| import NoteTitleWidget from "../widgets/note_title.js"; | ||||
| import RunScriptButtonsWidget from "../widgets/run_script_buttons.js"; | ||||
| import NoteTypeWidget from "../widgets/note_type.js"; | ||||
| import NoteActionsWidget from "../widgets/note_actions.js"; | ||||
| import NoteDetailWidget from "../widgets/note_detail.js"; | ||||
| @ -35,7 +34,6 @@ export default class DesktopExtraWindowLayout { | ||||
|                         .overflowing() | ||||
|                         .cssBlock('.title-row > * { margin: 5px 5px 0 5px; }') | ||||
|                         .child(new NoteTitleWidget()) | ||||
|                         .child(new RunScriptButtonsWidget().hideInZenMode()) | ||||
|                         .child(new NoteTypeWidget().hideInZenMode()) | ||||
|                         .child(new NoteActionsWidget().hideInZenMode()) | ||||
|                     ) | ||||
|  | ||||
| @ -9,7 +9,6 @@ import TabCachingWidget from "../widgets/tab_caching_widget.js"; | ||||
| import NotePathsWidget from "../widgets/note_paths.js"; | ||||
| import NoteTitleWidget from "../widgets/note_title.js"; | ||||
| import OwnedAttributeListWidget from "../widgets/attribute_widgets/owned_attribute_list.js"; | ||||
| import RunScriptButtonsWidget from "../widgets/run_script_buttons.js"; | ||||
| import NoteTypeWidget from "../widgets/note_type.js"; | ||||
| import NoteActionsWidget from "../widgets/note_actions.js"; | ||||
| import NoteDetailWidget from "../widgets/note_detail.js"; | ||||
| @ -27,6 +26,8 @@ import InheritedAttributesWidget from "../widgets/inherited_attribute_list.js"; | ||||
| import NoteListWidget from "../widgets/note_list.js"; | ||||
| import SearchDefinitionWidget from "../widgets/search_definition.js"; | ||||
| import Container from "../widgets/container.js"; | ||||
| import SqlResultWidget from "../widgets/sql_result.js"; | ||||
| import SqlTableSchemasWidget from "../widgets/sql_table_schemas.js"; | ||||
| 
 | ||||
| const RIGHT_PANE_CSS = ` | ||||
| <style> | ||||
| @ -149,7 +150,6 @@ export default class DesktopMainWindowLayout { | ||||
|                         .cssBlock('.title-row > * { margin: 5px 5px 0 5px; }') | ||||
|                         .overflowing() | ||||
|                         .child(new NoteTitleWidget()) | ||||
|                         .child(new RunScriptButtonsWidget().hideInZenMode()) | ||||
|                         .child(new NoteTypeWidget().hideInZenMode()) | ||||
|                         .child(new NoteActionsWidget().hideInZenMode()) | ||||
|                     ) | ||||
| @ -163,8 +163,10 @@ export default class DesktopMainWindowLayout { | ||||
|                     ) | ||||
|                     .child(new Container() | ||||
|                         .css('height: 100%; overflow: auto;') | ||||
|                         .child(new TabCachingWidget(() => new SqlTableSchemasWidget())) | ||||
|                         .child(new TabCachingWidget(() => new NoteDetailWidget())) | ||||
|                         .child(new TabCachingWidget(() => new NoteListWidget())) | ||||
|                         .child(new TabCachingWidget(() => new SqlResultWidget())) | ||||
|                     ) | ||||
|                     .child(new TabCachingWidget(() => new SimilarNotesWidget())) | ||||
|                     .child(...this.customWidgets.get('center-pane')) | ||||
|  | ||||
| @ -211,10 +211,12 @@ export default class Entrypoints extends Component { | ||||
| 
 | ||||
|         if (note.mime.endsWith("env=frontend")) { | ||||
|             await bundleService.getAndExecuteBundle(note.noteId); | ||||
|         } | ||||
| 
 | ||||
|         if (note.mime.endsWith("env=backend")) { | ||||
|         } else if (note.mime.endsWith("env=backend")) { | ||||
|             await server.post('script/run/' + note.noteId); | ||||
|         } else if (note.mime === 'text/x-sqlite;schema=trilium') { | ||||
|             const result = await server.post("sql/execute/" + note.noteId); | ||||
| 
 | ||||
|             this.triggerEvent('sqlQueryResults', {results: result.results}); | ||||
|         } | ||||
| 
 | ||||
|         toastService.showMessage("Note executed"); | ||||
|  | ||||
| @ -22,8 +22,10 @@ const TPL = ` | ||||
| 
 | ||||
| export default class NoteListWidget extends TabAwareWidget { | ||||
|     isEnabled() { | ||||
|         return super.isEnabled() && ( | ||||
|             ['book', 'search'].includes(this.note.type) | ||||
|         return super.isEnabled() | ||||
|             && this.note.mime !== 'text/x-sqlite;schema=trilium' | ||||
|             && ( | ||||
|                 ['book', 'search', 'code'].includes(this.note.type) | ||||
|                 || (this.note.type === 'text' && this.note.hasChildren()) | ||||
|             ); | ||||
|     } | ||||
| @ -46,10 +48,6 @@ export default class NoteListWidget extends TabAwareWidget { | ||||
|     } | ||||
| 
 | ||||
|     checkRenderStatus() { | ||||
|         console.log("this.isIntersecting", this.isIntersecting); | ||||
|         console.log("this.noteIdRefreshed === this.noteId", this.noteIdRefreshed === this.noteId); | ||||
|         console.log("this.shownNoteId !== this.noteId", this.shownNoteId !== this.noteId); | ||||
| 
 | ||||
|         if (this.isIntersecting | ||||
|             && this.noteIdRefreshed === this.noteId | ||||
|             && this.shownNoteId !== this.noteId) { | ||||
|  | ||||
| @ -1,33 +0,0 @@ | ||||
| import TabAwareWidget from "./tab_aware_widget.js"; | ||||
| 
 | ||||
| const TPL = ` | ||||
| <div style="display: inline-flex;"> | ||||
|     <button class="btn btn-sm icon-button bx bx-play-circle render-button" | ||||
|             data-trigger-command="renderActiveNote" | ||||
|             title="Render"></button> | ||||
|      | ||||
|     <button class="btn btn-sm icon-button bx bx-play-circle execute-script-button" | ||||
|             data-trigger-command="runActiveNote" | ||||
|             title="Execute"></button> | ||||
| </div>`; | ||||
| 
 | ||||
| export default class RunScriptButtonsWidget extends TabAwareWidget { | ||||
|     doRender() { | ||||
|         this.$widget = $(TPL); | ||||
|         this.contentSized(); | ||||
| 
 | ||||
|         this.$renderButton = this.$widget.find('.render-button'); | ||||
|         this.$executeScriptButton = this.$widget.find('.execute-script-button'); | ||||
|     } | ||||
| 
 | ||||
|     refreshWithNote(note) { | ||||
|         this.$renderButton.toggle(note.type === 'render'); | ||||
|         this.$executeScriptButton.toggle(note.type === 'code' && note.mime.startsWith('application/javascript')); | ||||
|     } | ||||
| 
 | ||||
|     async entitiesReloadedEvent({loadResults}) { | ||||
|         if (loadResults.isNoteReloaded(this.noteId)) { | ||||
|             this.refresh(); | ||||
|         } | ||||
|     } | ||||
| } | ||||
							
								
								
									
										64
									
								
								src/public/app/widgets/sql_result.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										64
									
								
								src/public/app/widgets/sql_result.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,64 @@ | ||||
| import TabAwareWidget from "./tab_aware_widget.js"; | ||||
| import treeService from "../services/tree.js"; | ||||
| import linkService from "../services/link.js"; | ||||
| import hoistedNoteService from "../services/hoisted_note.js"; | ||||
| import server from "../services/server.js"; | ||||
| import toastService from "../services/toast.js"; | ||||
| 
 | ||||
| const TPL = ` | ||||
| <div class="sql-result-widget"> | ||||
|     <style> | ||||
|     .sql-result-widget { | ||||
|         padding: 15px; | ||||
|     } | ||||
|     </style> | ||||
|     | ||||
|     <div class="sql-console-result-container"></div> | ||||
| </div>`; | ||||
| 
 | ||||
| export default class SqlResultWidget extends TabAwareWidget { | ||||
|     isEnabled() { | ||||
|         return this.note | ||||
|             && this.note.mime === 'text/x-sqlite;schema=trilium' | ||||
|             && super.isEnabled(); | ||||
|     } | ||||
| 
 | ||||
|     doRender() { | ||||
|         this.$widget = $(TPL); | ||||
|         this.overflowing(); | ||||
| 
 | ||||
|         this.$sqlConsoleResultContainer = this.$widget.find('.sql-console-result-container'); | ||||
|     } | ||||
| 
 | ||||
|     async sqlQueryResultsEvent({results}) { | ||||
|         this.$sqlConsoleResultContainer.empty(); | ||||
| 
 | ||||
|         for (const rows of results) { | ||||
|             if (rows.length === 0) { | ||||
|                 continue; | ||||
|             } | ||||
| 
 | ||||
|             const $table = $('<table class="table table-striped">'); | ||||
|             this.$sqlConsoleResultContainer.append($table); | ||||
| 
 | ||||
|             const result = rows[0]; | ||||
|             const $row = $("<tr>"); | ||||
| 
 | ||||
|             for (const key in result) { | ||||
|                 $row.append($("<th>").html(key)); | ||||
|             } | ||||
| 
 | ||||
|             $table.append($row); | ||||
| 
 | ||||
|             for (const result of rows) { | ||||
|                 const $row = $("<tr>"); | ||||
| 
 | ||||
|                 for (const key in result) { | ||||
|                     $row.append($("<td>").html(result[key])); | ||||
|                 } | ||||
| 
 | ||||
|                 $table.append($row); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
							
								
								
									
										83
									
								
								src/public/app/widgets/sql_table_schemas.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										83
									
								
								src/public/app/widgets/sql_table_schemas.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,83 @@ | ||||
| import TabAwareWidget from "./tab_aware_widget.js"; | ||||
| import treeService from "../services/tree.js"; | ||||
| import linkService from "../services/link.js"; | ||||
| import hoistedNoteService from "../services/hoisted_note.js"; | ||||
| import server from "../services/server.js"; | ||||
| import toastService from "../services/toast.js"; | ||||
| 
 | ||||
| const TPL = ` | ||||
| <div class="sql-table-schemas-widget"> | ||||
|     <style> | ||||
|     .sql-table-schemas button { | ||||
|         padding: 0.25rem 0.4rem; | ||||
|         font-size: 0.875rem; | ||||
|         line-height: 0.5; | ||||
|         border-radius: 0.2rem; | ||||
|     } | ||||
|      | ||||
|     .sql-console-result-container { | ||||
|         width: 100%;  | ||||
|         font-size: smaller;  | ||||
|         margin-top: 10px; | ||||
|         flex-grow: 1; | ||||
|         overflow: auto; | ||||
|         min-height: 0; | ||||
|     } | ||||
|      | ||||
|     .table-schema td { | ||||
|         padding: 5px; | ||||
|     } | ||||
|     </style> | ||||
|      | ||||
|     Tables: | ||||
|     <span class="sql-table-schemas"></span> | ||||
| </div>`; | ||||
| 
 | ||||
| export default class SqlTableSchemasWidget extends TabAwareWidget { | ||||
|     isEnabled() { | ||||
|         return this.note | ||||
|             && this.note.mime === 'text/x-sqlite;schema=trilium' | ||||
|             && super.isEnabled(); | ||||
|     } | ||||
| 
 | ||||
|     doRender() { | ||||
|         this.$widget = $(TPL); | ||||
|         this.overflowing(); | ||||
| 
 | ||||
|         this.$sqlConsoleTableSchemas = this.$widget.find('.sql-table-schemas'); | ||||
|     } | ||||
| 
 | ||||
|     async refreshWithNote(note) { | ||||
|         if (this.tableSchemasShown) { | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
|         this.tableSchemasShown = true; | ||||
| 
 | ||||
|         const tableSchema = await server.get('sql/schema'); | ||||
| 
 | ||||
|         for (const table of tableSchema) { | ||||
|             const $tableLink = $('<button class="btn">').text(table.name); | ||||
| 
 | ||||
|             const $table = $('<table class="table-schema">'); | ||||
| 
 | ||||
|             for (const column of table.columns) { | ||||
|                 $table.append( | ||||
|                     $("<tr>") | ||||
|                         .append($("<td>").text(column.name)) | ||||
|                         .append($("<td>").text(column.type)) | ||||
|                 ); | ||||
|             } | ||||
| 
 | ||||
|             this.$sqlConsoleTableSchemas.append($tableLink).append(" "); | ||||
| 
 | ||||
|             $tableLink.tooltip({ | ||||
|                 html: true, | ||||
|                 placement: 'bottom', | ||||
|                 boundary: 'window', | ||||
|                 title: $table[0].outerHTML, | ||||
|                 sanitize: false | ||||
|             }); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @ -9,65 +9,24 @@ const TPL = ` | ||||
| <div class="note-detail-code note-detail-printable"> | ||||
|     <style> | ||||
|     .note-detail-code { | ||||
|         overflow: auto; | ||||
|         height: 100%; | ||||
|         display: flex; | ||||
|         flex-direction: column; | ||||
|     } | ||||
|      | ||||
|     .note-detail-code-editor { | ||||
|         flex-basis: 200px; | ||||
|         min-height: 200px; | ||||
|         flex-grow: 1; | ||||
|         overflow: auto; | ||||
|     } | ||||
|      | ||||
|     .sql-console-table-schemas button { | ||||
|         padding: 0.25rem 0.4rem; | ||||
|         font-size: 0.875rem; | ||||
|         line-height: 0.5; | ||||
|         border-radius: 0.2rem; | ||||
|     } | ||||
|      | ||||
|     .sql-console-result-wrapper { | ||||
|         flex-grow: 100; | ||||
|         display: flex; | ||||
|         flex-direction: column; | ||||
|         min-height: 0; | ||||
|     } | ||||
|      | ||||
|     .sql-console-result-container { | ||||
|         width: 100%;  | ||||
|         font-size: smaller;  | ||||
|         margin-top: 10px; | ||||
|         flex-grow: 1; | ||||
|         overflow: auto; | ||||
|         min-height: 0; | ||||
|     } | ||||
|      | ||||
|     .table-schema td { | ||||
|         padding: 5px; | ||||
|         min-height: 300px; | ||||
|     } | ||||
|     </style> | ||||
| 
 | ||||
|     <div class="sql-console-area"> | ||||
|         Tables: | ||||
|         <span class="sql-console-table-schemas"></span> | ||||
|     </div> | ||||
|     <button data-trigger-command="runActiveNote" | ||||
|             class="no-print execute-button btn btn-sm" | ||||
|             style="position: absolute; top: 0px; right: 10px; z-index: 1000;"> | ||||
|         Execute | ||||
|     </button> | ||||
| 
 | ||||
|     <div class="note-detail-code-editor"></div> | ||||
|      | ||||
|     <div class="sql-console-area sql-console-result-wrapper"> | ||||
|         <div style="text-align: center"> | ||||
|             <button class="btn btn-danger sql-console-execute">Execute query <kbd>Ctrl+Enter</kbd></button> | ||||
|         </div> | ||||
| 
 | ||||
|         <div class="sql-console-result-container"></div> | ||||
|     </div> | ||||
| </div>`; | ||||
| 
 | ||||
| let TABLE_SCHEMA; | ||||
| 
 | ||||
| export default class EditableCodeTypeWidget extends TypeWidget { | ||||
|     static getType() { return "editable-code"; } | ||||
| 
 | ||||
| @ -75,17 +34,10 @@ export default class EditableCodeTypeWidget extends TypeWidget { | ||||
|         this.$widget = $(TPL); | ||||
|         this.contentSized(); | ||||
|         this.$editor = this.$widget.find('.note-detail-code-editor'); | ||||
|         this.$sqlConsoleArea = this.$widget.find('.sql-console-area'); | ||||
|         this.$sqlConsoleTableSchemas = this.$widget.find('.sql-console-table-schemas'); | ||||
|         this.$sqlConsoleExecuteButton = this.$widget.find('.sql-console-execute'); | ||||
|         this.$sqlConsoleResultContainer = this.$widget.find('.sql-console-result-container'); | ||||
|         this.$executeButton = this.$widget.find('.execute-button'); | ||||
| 
 | ||||
|         keyboardActionService.setupActionsForElement('code-detail', this.$widget, this); | ||||
| 
 | ||||
|         utils.bindElShortcut(this.$editor, 'ctrl+return', () => this.execute()); | ||||
| 
 | ||||
|         this.$sqlConsoleExecuteButton.on('click', () => this.execute()); | ||||
| 
 | ||||
|         this.initialized = this.initEditor(); | ||||
|     } | ||||
| 
 | ||||
| @ -122,6 +74,11 @@ export default class EditableCodeTypeWidget extends TypeWidget { | ||||
|     } | ||||
| 
 | ||||
|     async doRefresh(note) { | ||||
|         this.$executeButton.toggle( | ||||
|             note.mime.startsWith('application/javascript') | ||||
|             || note.mime === 'text/x-sqlite;schema=trilium' | ||||
|         ); | ||||
| 
 | ||||
|         const noteComplement = await this.tabContext.getNoteComplement(); | ||||
| 
 | ||||
|         await this.spacedUpdate.allowUpdateWithoutChange(() => { | ||||
| @ -138,104 +95,9 @@ export default class EditableCodeTypeWidget extends TypeWidget { | ||||
|             } | ||||
|         }); | ||||
| 
 | ||||
|         const isSqlConsole = note.mime === 'text/x-sqlite;schema=trilium'; | ||||
| 
 | ||||
|         this.$sqlConsoleArea.toggle(isSqlConsole); | ||||
| 
 | ||||
|         if (isSqlConsole) { | ||||
|             await this.showTableSchemas(); | ||||
|         } | ||||
| 
 | ||||
|         this.show(); | ||||
|     } | ||||
| 
 | ||||
|     async showTableSchemas() { | ||||
|         if (!TABLE_SCHEMA) { | ||||
|             TABLE_SCHEMA = await server.get('sql/schema'); | ||||
|         } | ||||
| 
 | ||||
|         this.$sqlConsoleTableSchemas.empty(); | ||||
| 
 | ||||
|         for (const table of TABLE_SCHEMA) { | ||||
|             const $tableLink = $('<button class="btn">').text(table.name); | ||||
| 
 | ||||
|             const $table = $('<table class="table-schema">'); | ||||
| 
 | ||||
|             for (const column of table.columns) { | ||||
|                 $table.append( | ||||
|                     $("<tr>") | ||||
|                         .append($("<td>").text(column.name)) | ||||
|                         .append($("<td>").text(column.type)) | ||||
|                 ); | ||||
|             } | ||||
| 
 | ||||
|             this.$sqlConsoleTableSchemas.append($tableLink).append(" "); | ||||
| 
 | ||||
|             $tableLink | ||||
|                 .tooltip({ | ||||
|                     html: true, | ||||
|                     placement: 'bottom', | ||||
|                     boundary: 'window', | ||||
|                     title: $table[0].outerHTML, | ||||
|                     sanitize: false | ||||
|                 }) | ||||
|                 .on('click', () => this.codeEditor.setValue("SELECT * FROM " + table.name + " LIMIT 100")); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     async execute() { | ||||
|         // execute the selected text or the whole content if there's no selection
 | ||||
|         let sqlQuery = this.codeEditor.getSelection(); | ||||
| 
 | ||||
|         if (!sqlQuery) { | ||||
|             sqlQuery = this.codeEditor.getValue(); | ||||
|         } | ||||
| 
 | ||||
|         const result = await server.post("sql/execute", { | ||||
|             query: sqlQuery | ||||
|         }); | ||||
| 
 | ||||
|         if (!result.success) { | ||||
|             toastService.showError(result.error); | ||||
|             return; | ||||
|         } | ||||
|         else { | ||||
|             toastService.showMessage("Query was executed successfully."); | ||||
|         } | ||||
| 
 | ||||
|         const results = result.results; | ||||
| 
 | ||||
|         this.$sqlConsoleResultContainer.empty(); | ||||
| 
 | ||||
|         for (const rows of results) { | ||||
|             if (rows.length === 0) { | ||||
|                 continue; | ||||
|             } | ||||
| 
 | ||||
|             const $table = $('<table class="table table-striped">'); | ||||
|             this.$sqlConsoleResultContainer.append($table); | ||||
| 
 | ||||
|             const result = rows[0]; | ||||
|             const $row = $("<tr>"); | ||||
| 
 | ||||
|             for (const key in result) { | ||||
|                 $row.append($("<th>").html(key)); | ||||
|             } | ||||
| 
 | ||||
|             $table.append($row); | ||||
| 
 | ||||
|             for (const result of rows) { | ||||
|                 const $row = $("<tr>"); | ||||
| 
 | ||||
|                 for (const key in result) { | ||||
|                     $row.append($("<td>").html(result[key])); | ||||
|                 } | ||||
| 
 | ||||
|                 $table.append($row); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     show() { | ||||
|         this.$widget.show(); | ||||
| 
 | ||||
|  | ||||
| @ -1,6 +1,7 @@ | ||||
| "use strict"; | ||||
| 
 | ||||
| const sql = require('../../services/sql'); | ||||
| const repository = require('../../services/repository'); | ||||
| 
 | ||||
| function getSchema() { | ||||
|     const tableNames = sql.getColumn(`SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%' ORDER BY name`); | ||||
| @ -17,7 +18,13 @@ function getSchema() { | ||||
| } | ||||
| 
 | ||||
| function execute(req) { | ||||
|     const queries = req.body.query.split("\n---"); | ||||
|     const note = repository.getNote(req.params.noteId); | ||||
| 
 | ||||
|     if (!note) { | ||||
|         return [404, `Note ${req.params.noteId} was not found.`]; | ||||
|     } | ||||
| 
 | ||||
|     const queries = note.getContent().split("\n---"); | ||||
| 
 | ||||
|     try { | ||||
|         const results = []; | ||||
|  | ||||
| @ -232,7 +232,7 @@ function register(app) { | ||||
|     route(POST, '/api/setup/sync-seed', [auth.checkAppNotInitialized], setupApiRoute.saveSyncSeed, apiResultHandler, false); | ||||
| 
 | ||||
|     apiRoute(GET, '/api/sql/schema', sqlRoute.getSchema); | ||||
|     apiRoute(POST, '/api/sql/execute', sqlRoute.execute); | ||||
|     apiRoute(POST, '/api/sql/execute/:noteId', sqlRoute.execute); | ||||
|     route(POST, '/api/database/anonymize', [auth.checkApiAuthOrElectron, csrfMiddleware], databaseRoute.anonymize, apiResultHandler, false); | ||||
| 
 | ||||
|     // backup requires execution outside of transaction
 | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 zadam
						zadam