Azpect3120 0876222f4c FEAT: Many changes! Tree is almost done
Loading indicator for loading the tree. Tree displays PK, FK, R, and U.
Still some bugs with the connections and I want to implement a
"connection manager" which the ability to change, edit, and delete
connections. PLUS right now the tree view is only supported for PSQL.
Need to use different queries for different SQL types. SOME types, like
SQLlite, might not support the tree, and I will need a display for that.
Plus errors are not handled, just bubbled and logged :|
2024-08-09 18:04:04 -07:00

109 lines
3.7 KiB
Go

package templates
import (
"fmt"
"sort"
"github.com/Azpect3120/Web-Database-Viewer/internal/model"
)
// Tree definition
const TREE_OPEN string = `<ul hx-swap-oob="outerHTML" id="database-table-tree" class="space-y-2">`
const TREE_CLOSE string = `</ul>`
const TREE_BODY_TEMPLATE string = `<li>%s</li>`
// Table definition
const TABLE_TEMPLATE string = `
<button class="w-full text-left text-gray-700 font-medium hover:bg-gray-100 p-2 rounded flex items-center">
<svg onclick="ToggleFields('%s');" id="icon-%s" class="w-4 h-4 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" transform="rotate(-90)">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 9l6 6 6-6"></path>
</svg>
<span class="hover:underline" title="Select this table" onclick="ToggleFields('%s');">%s</span>
<svg class="w-8 h-8 ml-auto p-2 rounded-full hover:bg-gray-300 transition:all duration-150" xmlns="http://www.w3.org/2000/svg" class="ionicon" viewBox="0 0 512 512" onclick="LoadTableQuery('%s');">
<path d="M464 428L339.92 303.9a160.48 160.48 0 0030.72-94.58C370.64 120.37 298.27 48 209.32 48S48 120.37 48 209.32s72.37 161.32 161.32 161.32a160.48 160.48 0 0094.58-30.72L428 464zM209.32 319.69a110.38 110.38 0 11110.37-110.37 110.5 110.5 0 01-110.37 110.37z"/>
</svg>
</button>
`
// Fields definition
const FIELDS_LIST_OPEN string = `<ul id="fields-%s" class="hidden ml-6 mt-1 space-y-1 text-gray-600">`
const FIELDS_LIST_CLOSE string = `</ul>`
const FIELD_TEMPLATE string = `
<li>
<button onclick="LoadTableQueryWithFields('%s', '%s')" class="flex items-center w-full" title="Select this field">
<svg class="w-4 h-4 mr-2" 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="M4 6h16M4 12h16m-7 6h7">
</path>
</svg>
<span>%s</span>
<span class="text-xs ml-auto">%s</span>
</button>
</li>
`
// This is not implemented yet
const PRIMARY_KEY string = `<span class="h-1.5 w-1.5 bg-yellow-500 rounded-full mx-2" title="Primary Key"></span>`
// Generate the tree based on the database tables and columns
func TableTree(tree map[string][]model.Column) string {
html := TREE_OPEN
var body string
for _, table := range getSortedKeys(tree) {
body += fmt.Sprintf(TABLE_TEMPLATE, table, table, table, table, table)
fields := fmt.Sprintf(FIELDS_LIST_OPEN, table)
body += fields + generateFields(table, tree[table]) + FIELDS_LIST_CLOSE
}
html += fmt.Sprintf(TREE_BODY_TEMPLATE, body)
return html + TREE_CLOSE
}
// Using a list of fields, generate the HTML for the fields
func generateFields(table string, fields []model.Column) string {
var html string
for _, field := range fields {
html += fmt.Sprintf(FIELD_TEMPLATE, table, field.Name, field.Name, generateType(field))
}
return html
}
// Return a list of the keys in a map, sorted alphabetically
func getSortedKeys(m map[string][]model.Column) []string {
keys := make([]string, 0, len(m))
for k := range m {
keys = append(keys, k)
}
sort.Strings(keys)
return keys
}
// Generate the string for the type of column base on the column definition
func generateType(col model.Column) string {
var str string
if col.PrimaryKey {
str = `<span class="text-yellow-500">PK</span>, `
} else if col.ForeignKey.Column != "" {
str = fmt.Sprintf(`<span class="text-blue-500">FK: %s(%s)</span>, `, col.ForeignKey.ForeignTable, col.ForeignKey.ForeignColumn)
}
if col.Nullable == "NO" {
str += `<span class="text-red-500">R</span>, `
}
if col.Unique {
str += `<span class="text-green-500">U</span>, `
}
if col.MaxLength.Valid {
str += fmt.Sprintf("%s(%d)", col.Type, col.MaxLength.Int64)
} else {
str += col.Type
}
return str
}