sqlite_dashboard 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/LICENSE +21 -0
- data/README.md +361 -0
- data/Rakefile +60 -0
- data/app/controllers/sqlite_dashboard/application_controller.rb +6 -0
- data/app/controllers/sqlite_dashboard/databases_controller.rb +247 -0
- data/app/javascript/controllers/query_executor_controller.js +97 -0
- data/app/javascript/controllers/table_selector_controller.js +35 -0
- data/app/javascript/sqlite_dashboard/application.js +9 -0
- data/app/views/layouts/sqlite_dashboard/application.html.erb +1274 -0
- data/app/views/sqlite_dashboard/databases/_error.html.erb +5 -0
- data/app/views/sqlite_dashboard/databases/execute_query.turbo_stream.erb +37 -0
- data/app/views/sqlite_dashboard/databases/index.html.erb +97 -0
- data/app/views/sqlite_dashboard/databases/show.html.erb +60 -0
- data/config/importmap.rb +2 -0
- data/config/routes.rb +13 -0
- data/lib/generators/sqlite_dashboard/install_generator.rb +58 -0
- data/lib/generators/sqlite_dashboard/templates/README +51 -0
- data/lib/generators/sqlite_dashboard/templates/initializer.rb +28 -0
- data/lib/sqlite_dashboard/configuration.rb +89 -0
- data/lib/sqlite_dashboard/engine.rb +16 -0
- data/lib/sqlite_dashboard/version.rb +3 -0
- data/lib/sqlite_dashboard.rb +17 -0
- data/sqlite_dashboard.gemspec +55 -0
- metadata +203 -0
@@ -0,0 +1,97 @@
|
|
1
|
+
import { Controller } from "@hotwired/stimulus"
|
2
|
+
|
3
|
+
export default class extends Controller {
|
4
|
+
static targets = ["queryInput"]
|
5
|
+
|
6
|
+
execute(event) {
|
7
|
+
event.preventDefault()
|
8
|
+
|
9
|
+
const form = event.target
|
10
|
+
const formData = new FormData(form)
|
11
|
+
const csrfToken = document.querySelector('meta[name="csrf-token"]')?.content
|
12
|
+
|
13
|
+
fetch(form.action, {
|
14
|
+
method: form.method || 'POST',
|
15
|
+
body: formData,
|
16
|
+
headers: {
|
17
|
+
'X-CSRF-Token': csrfToken,
|
18
|
+
'Accept': 'application/json'
|
19
|
+
}
|
20
|
+
})
|
21
|
+
.then(response => response.json())
|
22
|
+
.then(data => {
|
23
|
+
console.log("Query response:", data)
|
24
|
+
this.displayResults(data)
|
25
|
+
})
|
26
|
+
.catch(error => {
|
27
|
+
console.error("Query error:", error)
|
28
|
+
this.displayError(error.message || "An error occurred")
|
29
|
+
})
|
30
|
+
}
|
31
|
+
|
32
|
+
displayResults(data) {
|
33
|
+
const resultsDiv = document.getElementById("query-results")
|
34
|
+
|
35
|
+
if (data.error) {
|
36
|
+
this.displayError(data.error)
|
37
|
+
return
|
38
|
+
}
|
39
|
+
|
40
|
+
if (data.columns && data.columns.length > 0) {
|
41
|
+
let html = `
|
42
|
+
<div class="table-wrapper">
|
43
|
+
<table class="table table-striped table-hover table-bordered">
|
44
|
+
<thead class="table-dark">
|
45
|
+
<tr>
|
46
|
+
${data.columns.map(col => `<th>${this.escapeHtml(col)}</th>`).join('')}
|
47
|
+
</tr>
|
48
|
+
</thead>
|
49
|
+
<tbody>
|
50
|
+
${data.rows.map(row =>
|
51
|
+
`<tr>${row.map(val => `<td>${this.escapeHtml(String(val || ''))}</td>`).join('')}</tr>`
|
52
|
+
).join('')}
|
53
|
+
</tbody>
|
54
|
+
</table>
|
55
|
+
</div>
|
56
|
+
<div class="mt-3">
|
57
|
+
<small class="text-muted">
|
58
|
+
${data.rows.length} row${data.rows.length !== 1 ? 's' : ''} returned
|
59
|
+
</small>
|
60
|
+
</div>
|
61
|
+
`
|
62
|
+
resultsDiv.innerHTML = html
|
63
|
+
} else if (data.message) {
|
64
|
+
resultsDiv.innerHTML = `
|
65
|
+
<div class="success-message">
|
66
|
+
<i class="fas fa-check-circle"></i> ${this.escapeHtml(data.message)}
|
67
|
+
</div>
|
68
|
+
`
|
69
|
+
} else {
|
70
|
+
resultsDiv.innerHTML = `
|
71
|
+
<div class="text-muted text-center py-5">
|
72
|
+
<p>No results returned</p>
|
73
|
+
</div>
|
74
|
+
`
|
75
|
+
}
|
76
|
+
}
|
77
|
+
|
78
|
+
displayError(error) {
|
79
|
+
const resultsDiv = document.getElementById("query-results")
|
80
|
+
resultsDiv.innerHTML = `
|
81
|
+
<div class="error-message">
|
82
|
+
<i class="fas fa-exclamation-circle"></i> <strong>Error:</strong> ${this.escapeHtml(error)}
|
83
|
+
</div>
|
84
|
+
`
|
85
|
+
}
|
86
|
+
|
87
|
+
escapeHtml(text) {
|
88
|
+
const div = document.createElement('div')
|
89
|
+
div.textContent = text
|
90
|
+
return div.innerHTML
|
91
|
+
}
|
92
|
+
|
93
|
+
clear() {
|
94
|
+
this.queryInputTarget.value = ""
|
95
|
+
this.queryInputTarget.focus()
|
96
|
+
}
|
97
|
+
}
|
@@ -0,0 +1,35 @@
|
|
1
|
+
import { Controller } from "@hotwired/stimulus"
|
2
|
+
|
3
|
+
export default class extends Controller {
|
4
|
+
static targets = ["tableItem"]
|
5
|
+
|
6
|
+
selectTable(event) {
|
7
|
+
const tableName = event.currentTarget.dataset.tableName
|
8
|
+
|
9
|
+
// Remove active class from all items
|
10
|
+
this.tableItemTargets.forEach(item => {
|
11
|
+
item.classList.remove("active")
|
12
|
+
})
|
13
|
+
|
14
|
+
// Add active class to clicked item
|
15
|
+
event.currentTarget.classList.add("active")
|
16
|
+
|
17
|
+
// Update query input with SELECT statement for this table
|
18
|
+
const queryInput = document.getElementById("query")
|
19
|
+
if (queryInput) {
|
20
|
+
queryInput.value = `SELECT * FROM ${tableName} LIMIT 100;`
|
21
|
+
|
22
|
+
// Trigger the query execution using Turbo
|
23
|
+
const form = queryInput.closest("form")
|
24
|
+
if (form) {
|
25
|
+
// Create a submit button click to ensure proper Turbo form submission
|
26
|
+
const submitButton = form.querySelector('button[type="submit"]')
|
27
|
+
if (submitButton) {
|
28
|
+
submitButton.click()
|
29
|
+
} else {
|
30
|
+
form.requestSubmit()
|
31
|
+
}
|
32
|
+
}
|
33
|
+
}
|
34
|
+
}
|
35
|
+
}
|
@@ -0,0 +1,9 @@
|
|
1
|
+
import "@hotwired/turbo-rails"
|
2
|
+
import { Application } from "@hotwired/stimulus"
|
3
|
+
|
4
|
+
import QueryExecutorController from "controllers/query_executor_controller"
|
5
|
+
import TableSelectorController from "controllers/table_selector_controller"
|
6
|
+
|
7
|
+
window.Stimulus = Application.start()
|
8
|
+
Stimulus.register("query-executor", QueryExecutorController)
|
9
|
+
Stimulus.register("table-selector", TableSelectorController)
|