FEAT: Connection manager is working
All it can do is view and delete the connections but that was the key functionality that was missing.
This commit is contained in:
parent
7e233e53dd
commit
9c8a25609e
40
internal/database/delete.go
Normal file
40
internal/database/delete.go
Normal file
@ -0,0 +1,40 @@
|
||||
package database
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/Azpect3120/Web-Database-Viewer/internal/templates"
|
||||
"github.com/gin-contrib/sessions"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func DeleteConnections(c *gin.Context) {
|
||||
session := sessions.Default(c)
|
||||
connections_bytes, ok := session.Get("connections").([]byte)
|
||||
if !ok {
|
||||
fmt.Println("No connections found")
|
||||
}
|
||||
|
||||
var connections map[string]string
|
||||
if err := json.Unmarshal(connections_bytes, &connections); err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
|
||||
for _, conn := range c.PostFormArray("connections") {
|
||||
for name, url := range connections {
|
||||
if conn == url {
|
||||
delete(connections, name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
connections_bytes, err := json.Marshal(connections)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
session.Set("connections", connections_bytes)
|
||||
session.Save()
|
||||
|
||||
c.String(200, templates.MANAGER_CLOSED)
|
||||
}
|
||||
@ -50,6 +50,7 @@ func populate(web, api *gin.RouterGroup) {
|
||||
"status": 200,
|
||||
})
|
||||
})
|
||||
api.POST("/connections/delete", database.DeleteConnections)
|
||||
web.GET("/connections", func(c *gin.Context) {
|
||||
session := sessions.Default(c)
|
||||
connections_bytes, conn_ok := session.Get("connections").([]byte)
|
||||
@ -73,7 +74,9 @@ func populate(web, api *gin.RouterGroup) {
|
||||
c.String(200, database.TableTree(c))
|
||||
})
|
||||
|
||||
// This should return an HTML template which will be used to auto or not
|
||||
// auto send the query to the server.
|
||||
web.GET("/query/auto", templates.ToggleQueryType)
|
||||
|
||||
web.GET("/manager/open", templates.OpenManager)
|
||||
web.GET("/manager/hide", templates.HideManager)
|
||||
|
||||
}
|
||||
|
||||
@ -3,7 +3,7 @@ package templates
|
||||
import "fmt"
|
||||
|
||||
// List item templates
|
||||
const LIST_OPEN string = `<select id="connected-database" name="connected-database" class="mt-1 block p-2 border border-gray-300 rounded-md shadow-sm focus:ring-blue-500 focus:border-blue-500 text-sm md:text-base">`
|
||||
const LIST_OPEN string = `<select id="connected-database" name="connected-database" class="mt-1 block p-2 border border-gray-300 rounded-md shadow-sm focus:ring-blue-500 focus:border-blue-500 text-sm md:text-base" title="Change the connection to query.">`
|
||||
const LIST_ITEM string = `<option value="%s"%s>%s</option>`
|
||||
const LIST_CLOSE string = `</select>`
|
||||
|
||||
|
||||
88
internal/templates/manager.go
Normal file
88
internal/templates/manager.go
Normal file
@ -0,0 +1,88 @@
|
||||
package templates
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/gin-contrib/sessions"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
const MANAGER string = `
|
||||
<div id="manager-modal" class="fixed inset-0 bg-gray-600 bg-opacity-50">
|
||||
<div class="flex items-center justify-center min-h-screen">
|
||||
<form hx-post="/v1/api/connections/delete" hx-swap="outerHTML" hx-target="#manager-modal" hx-trigger="submit" class="bg-white p-6 rounded-lg shadow-lg w-2/3">
|
||||
<div class="flex justify-between items-start border-b pb-2">
|
||||
<h2 class="text-xl font-bold">
|
||||
Manage Stored Connections
|
||||
<br>
|
||||
<span class="text-xs font-light">Connection data is stored in the browsers session and can be deleted here.</span>
|
||||
</h2>
|
||||
<button hx-get="/v1/web/manager/hide" hx-trigger="click" hx-swap="outerHTML" hx-target="#manager-modal" class="text-gray-500 hover:text-gray-700">
|
||||
<svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24"
|
||||
xmlns="http://www.w3.org/2000/svg">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"></path>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
<div class="mt-4 w-full max-w-full overflow-x-auto">
|
||||
<table>
|
||||
<thead class="bg-gray-50">
|
||||
<tr>
|
||||
<th scope="col" class="px-6 py-3 text-center text-xs font-medium text-gray-500 uppercase tracking-wider">Delete</th>
|
||||
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Name</th>
|
||||
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase jracking-wider">Driver</th>
|
||||
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">URL</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="w-full">
|
||||
%s
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="flex items-center space-x-4 mt-4 border-t pt-4">
|
||||
<button type="submit" class="bg-blue-500 text-white px-4 py-2 rounded-md"> Save Changes </button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
`
|
||||
|
||||
const MANAGER_ENTRY string = `
|
||||
<tr class="overflow-x-auto">
|
||||
<td class="px-6 py-4 whitespace-nowrap flex items-center justify-center">
|
||||
<input type="checkbox" name="connections" value="%s" class="w-4 h-4">
|
||||
</td>
|
||||
<td class="px-6 py-4 whitespace-nowrap">%s</td>
|
||||
<td class="px-6 py-4 whitespace-nowrap">%s</td>
|
||||
<td class="px-6 py-4 whitespace-nowrap">%s</td>
|
||||
</tr>
|
||||
`
|
||||
|
||||
const MANAGER_CLOSED string = `
|
||||
<div id="manager-modal" class="fixed inset-0 bg-gray-600 bg-opacity-50 hidden opacity-0"></div>
|
||||
`
|
||||
|
||||
func OpenManager(c *gin.Context) {
|
||||
session := sessions.Default(c)
|
||||
connections_bytes, ok := session.Get("connections").([]byte)
|
||||
if !ok {
|
||||
fmt.Println("No connections found")
|
||||
}
|
||||
|
||||
var connections map[string]string
|
||||
if err := json.Unmarshal(connections_bytes, &connections); err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
|
||||
var entries string
|
||||
for name, url := range connections {
|
||||
entries += fmt.Sprintf(MANAGER_ENTRY, url, name, "PostgreSQL", url)
|
||||
}
|
||||
|
||||
c.String(200, fmt.Sprintf(MANAGER, entries))
|
||||
}
|
||||
|
||||
func HideManager(c *gin.Context) {
|
||||
c.String(200, MANAGER_CLOSED)
|
||||
}
|
||||
@ -75,3 +75,5 @@ for (const key in input) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -710,10 +710,27 @@ video {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.w-fit {
|
||||
width: -moz-fit-content;
|
||||
width: fit-content;
|
||||
}
|
||||
|
||||
.min-w-full {
|
||||
min-width: 100%;
|
||||
}
|
||||
|
||||
.max-w-\[50\%\] {
|
||||
max-width: 50%;
|
||||
}
|
||||
|
||||
.max-w-\[50\%\%\] {
|
||||
max-width: 50%%;
|
||||
}
|
||||
|
||||
.max-w-full {
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.flex-grow {
|
||||
flex-grow: 1;
|
||||
}
|
||||
@ -738,6 +755,10 @@ video {
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.items-start {
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
.items-center {
|
||||
align-items: center;
|
||||
}
|
||||
@ -803,6 +824,10 @@ video {
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
.overflow-x-hidden {
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
.overflow-y-hidden {
|
||||
overflow-y: hidden;
|
||||
}
|
||||
@ -840,6 +865,10 @@ video {
|
||||
border-bottom-width: 1px;
|
||||
}
|
||||
|
||||
.border-t {
|
||||
border-top-width: 1px;
|
||||
}
|
||||
|
||||
.border-gray-300 {
|
||||
--tw-border-opacity: 1;
|
||||
border-color: rgb(209 213 219 / var(--tw-border-opacity));
|
||||
@ -885,6 +914,21 @@ video {
|
||||
background-color: rgb(234 179 8 / var(--tw-bg-opacity));
|
||||
}
|
||||
|
||||
.bg-red-500 {
|
||||
--tw-bg-opacity: 1;
|
||||
background-color: rgb(239 68 68 / var(--tw-bg-opacity));
|
||||
}
|
||||
|
||||
.bg-red-600 {
|
||||
--tw-bg-opacity: 1;
|
||||
background-color: rgb(220 38 38 / var(--tw-bg-opacity));
|
||||
}
|
||||
|
||||
.bg-red-300 {
|
||||
--tw-bg-opacity: 1;
|
||||
background-color: rgb(252 165 165 / var(--tw-bg-opacity));
|
||||
}
|
||||
|
||||
.bg-opacity-50 {
|
||||
--tw-bg-opacity: 0.5;
|
||||
}
|
||||
@ -940,10 +984,18 @@ video {
|
||||
padding-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.pt-4 {
|
||||
padding-top: 1rem;
|
||||
}
|
||||
|
||||
.text-left {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.text-center {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.text-2xl {
|
||||
font-size: 1.5rem;
|
||||
line-height: 2rem;
|
||||
|
||||
@ -32,6 +32,9 @@
|
||||
<button onclick="ShowModal();" class="bg-blue-500 text-white px-4 py-2 my-2 rounded-md text-sm md:text-base">
|
||||
Add Connection
|
||||
</button>
|
||||
<button hx-get="/v1/web/manager/open" hx-trigger="click" hx-target="#manager-modal" hx-swap="outerHTML" class="bg-blue-500 text-white px-4 py-2 my-2 rounded-md text-sm md:text-base">
|
||||
Manage Connections
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -71,7 +74,7 @@
|
||||
<div class="flex items-center space-x-6">
|
||||
<form class="flex items-center space-x-2" hx-get="/v1/web/query/auto" hx-swap="outerHTML" hx-target="#query-main" hx-trigger="input">
|
||||
<label for="auto-toggle" class="text-sm font-medium text-gray-700">Auto-Run</label>
|
||||
<input type="checkbox" name="toggle" class="toggle-checkbox" checked>
|
||||
<input type="checkbox" name="toggle" class="toggle-checkbox" title="Toggle auto-query functionality. Note: This will send whatever query is in the input and clear the box.">
|
||||
</form>
|
||||
|
||||
<!-- Manual Query Button -->
|
||||
@ -199,6 +202,10 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- Manage Connections Modal -->
|
||||
<div id="manager-modal" class="fixed inset-0 bg-gray-600 bg-opacity-50 hidden opacity-0"></div>
|
||||
|
||||
<!-- Scripts -->
|
||||
<script defer src="/v1/web/static/scripts/password.js"></script>
|
||||
<script defer src="/v1/web/static/scripts/modal.js"></script>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user