From 8d80cabba09dbdcbb0784c8117a8f8456bd810c1 Mon Sep 17 00:00:00 2001 From: MickaelK Date: Mon, 1 Sep 2025 18:31:09 +1000 Subject: [PATCH] fix (form): enhance form app --- .../assets/css/designsystem_formbuilder.css | 13 ++++++ public/assets/lib/form.js | 14 +----- public/assets/pages/adminpage/helper_form.js | 8 +++- public/assets/pages/adminpage/index.css | 10 ----- .../pages/viewerpage/application_form.css | 3 -- .../pages/viewerpage/application_form.js | 15 ++++++- server/plugin/plg_backend_psql/index_cat.go | 44 +++++++++++++++++-- 7 files changed, 75 insertions(+), 32 deletions(-) diff --git a/public/assets/css/designsystem_formbuilder.css b/public/assets/css/designsystem_formbuilder.css index 3c314038..8dca678a 100644 --- a/public/assets/css/designsystem_formbuilder.css +++ b/public/assets/css/designsystem_formbuilder.css @@ -6,6 +6,11 @@ line-height: 1em; text-align: justify; } +.formbuilder a { + text-decoration: underline; + text-decoration-style: wavy; + text-decoration-color: rgba(0, 0, 0, 0.3); +} .formbuilder input::placeholder, .formbuilder textarea::placeholder { opacity: 0.6; } @@ -46,3 +51,11 @@ border-bottom: 2px solid rgba(70, 99, 114, 0.1); transition: border-color 0.2s ease-out; } + +.formbuilder .banner { + background: var(--bg-color); + border: 2px solid rgba(0, 0, 0, 0.05); + border-radius: 3px; + margin-bottom: 20px; + padding: 10px; +} diff --git a/public/assets/lib/form.js b/public/assets/lib/form.js index 868bd239..4f451999 100644 --- a/public/assets/lib/form.js +++ b/public/assets/lib/form.js @@ -49,7 +49,7 @@ async function createFormNodes(node, { renderNode, renderLeaf, renderInput, path else { const currentPath = path.concat(key); const $leaf = renderLeaf({ - ...withMarkdown(node[key]), + ...node[key], path: currentPath, label: key, }); @@ -122,15 +122,3 @@ export async function createForm(node, opts) { }); return $container; } - -function withMarkdown(obj) { - if (!("description" in obj)) return obj; - obj["description"] = toMarkdown(obj["description"]); - return obj; -} - -function toMarkdown(str = "") { - str = str.replace(/\[([^\]]+)\]\(([^)]+)\)/g, "$1"); - str = str.replaceAll("\n", "
"); - return str; -} diff --git a/public/assets/pages/adminpage/helper_form.js b/public/assets/pages/adminpage/helper_form.js index 958d2f27..1dde7598 100644 --- a/public/assets/pages/adminpage/helper_form.js +++ b/public/assets/pages/adminpage/helper_form.js @@ -4,7 +4,7 @@ import rxjs from "../../lib/rx.js"; export function renderLeaf({ format, label, description, type }) { if (label === "banner") return createElement(` `); const $el = createElement(` @@ -29,6 +29,12 @@ export function renderLeaf({ format, label, description, type }) { return $el; } +function fromMarkdown(str = "") { + str = str.replace(/\[([^\]]+)\]\(([^)]+)\)/g, "$1"); + str = str.replaceAll("\n", "
"); + return str; +} + export function useForm$($inputNodeList) { return rxjs.pipe( rxjs.mergeMap(() => $inputNodeList()), diff --git a/public/assets/pages/adminpage/index.css b/public/assets/pages/adminpage/index.css index db0941cc..4aa5e86f 100644 --- a/public/assets/pages/adminpage/index.css +++ b/public/assets/pages/adminpage/index.css @@ -98,9 +98,6 @@ } .component_page_admin .page_container a { color: var(--dark); - text-decoration: underline; - text-decoration-style: wavy; - text-decoration-color: rgba(0, 0, 0, 0.3); } .component_page_admin .page_container a:hover { opacity: 0.8; @@ -181,13 +178,6 @@ .component_page_admin .formbuilder textarea::placeholder { opacity: 0.6; } -.component_page_admin .formbuilder .banner { - background: var(--bg-color); - border: 2px solid rgba(0, 0, 0, 0.05); - border-radius: 3px; - margin-bottom: 15px; - padding: 10px; -} .component_page_admin .formbuilder .banner pre { background: inherit; color: inherit; diff --git a/public/assets/pages/viewerpage/application_form.css b/public/assets/pages/viewerpage/application_form.css index c83c9a1a..7bd8b5b6 100644 --- a/public/assets/pages/viewerpage/application_form.css +++ b/public/assets/pages/viewerpage/application_form.css @@ -58,9 +58,6 @@ .component_formviewer > .formviewer_container .box .formbuilder label.no-select > div > span span.mandatory { opacity: 0.6; } -.component_formviewer > .formviewer_container .box .formbuilder label.no-select > div div.description a { - border-bottom: 1px dashed var(--color); -} .component_formviewer .formbuilder .component_input[disabled], .component_formviewer .formbuilder .component_input[readonly], diff --git a/public/assets/pages/viewerpage/application_form.js b/public/assets/pages/viewerpage/application_form.js index 7b39f7f9..e0b13c15 100644 --- a/public/assets/pages/viewerpage/application_form.js +++ b/public/assets/pages/viewerpage/application_form.js @@ -64,7 +64,12 @@ export default function(render, { acl$, getFilename, getDownloadUrl }) { } return $el; }, - renderLeaf: ({ label, format, description, required }) => createElement(` + renderLeaf: ({ label, format, description, required }) => label === "banner" + ? createElement(` + + `) : createElement(` `), @@ -170,3 +175,9 @@ function readOnlyForm(formSpec) { } return formSpec; } + +function fromMarkdown(str = "") { + str = str.replace(/\[([^\]]+)\]\(([^)]+)\)/g, "$1"); + str = str.replaceAll("\n", "
"); + return str; +} diff --git a/server/plugin/plg_backend_psql/index_cat.go b/server/plugin/plg_backend_psql/index_cat.go index 365c62aa..5466736f 100644 --- a/server/plugin/plg_backend_psql/index_cat.go +++ b/server/plugin/plg_backend_psql/index_cat.go @@ -53,21 +53,34 @@ func (this PSQL) Cat(path string) (io.ReadCloser, error) { forms := make([]FormElement, len(c)) for i, _ := range columns { forms[i] = createFormElement(col[i], columns[i]) + if columnComment := _findCommentColumn(this.ctx, this.db, l.table, columns[i].Name); columnComment != "" { + forms[i].Description = columnComment + } if slices.Contains(columns[i].Constraint, "PRIMARY KEY") && forms[i].Value != nil { forms[i].ReadOnly = true } else if slices.Contains(columns[i].Constraint, "FOREIGN KEY") { if link, err := _findRelation(this.ctx, this.db, columns[i]); err == nil { - forms[i].Description = _createDescription(columns[i], link) if len(link.values) > 0 { forms[i].Type = "select" forms[i].Opts = link.values } + if forms[i].Description == "" { + forms[i].Description = _createDescription(columns[i], link) + } } } else if values, err := _findEnumValues(this.ctx, this.db, columns[i]); err == nil && len(values) > 0 { forms[i].Type = "select" forms[i].Opts = values } - + } + if comment := _findCommentTable(this.ctx, this.db, l.table); comment != "" { + forms = append([]FormElement{ + { + Name: "banner", + Type: "hidden", + Description: comment, + }, + }, forms...) } b, err := Form{Elmnts: forms}.MarshalJSON() if err != nil { @@ -78,11 +91,36 @@ func (this PSQL) Cat(path string) (io.ReadCloser, error) { func _createDescription(el Column, link LocationColumn) string { if slices.Contains(el.Constraint, "FOREIGN KEY") { - return fmt.Sprintf("points to <%s> → <%s>", link.table, link.column) + return fmt.Sprintf("points to [<%s> → <%s>](/files/%s/)", link.table, link.column, link.table) } return "" } +func _findCommentTable(ctx context.Context, db *sql.DB, tableName string) string { + var comment string + if err := db.QueryRowContext(ctx, ` + SELECT obj_description(c.oid) + FROM pg_class c + WHERE c.relname = $1 AND c.relkind = 'r' + `, tableName).Scan(&comment); err != nil { + return "" + } + return comment +} + +func _findCommentColumn(ctx context.Context, db *sql.DB, tableName, columnName string) string { + var comment string + if err := db.QueryRowContext(ctx, ` + SELECT col_description(c.oid, a.attnum) + FROM pg_class c + JOIN pg_attribute a ON a.attrelid = c.oid + WHERE c.relname = $1 AND a.attname = $2 AND c.relkind = 'r' + `, tableName, columnName).Scan(&comment); err != nil { + return "" + } + return comment +} + func _findRelation(ctx context.Context, db *sql.DB, el Column) (LocationColumn, error) { l := LocationColumn{} rows, err := db.QueryContext(ctx, `