Created
September 12, 2016 09:28
-
-
Save sameh-sharaf/b79d3d769614da6774d0fe1ff0fb0ec9 to your computer and use it in GitHub Desktop.
This page shows a form using Semantic UI library. The form is used to upload reports SQL scripts to system in order to show report content in reports/view page. The form uses codemirror library which is a code-supported text area. It is used by <text-codemirror>, a tag created in a separate file (text-codemirror.tag)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!-- | |
This page shows a form using Semantic UI library. | |
The form is used to upload reports SQL scripts to system in order to show | |
report content in reports/view page. | |
The form uses codemirror library which is a code-supported text area. It is | |
used by <text-codemirror>, a tag created in a separate file (text-codemirror.tag) | |
--> | |
<reports-form> | |
<form class="ui form segment grid"> | |
<div class="sixteen wide column"> | |
<h3 class="ui horizontal header divider"> Report editor </h3> | |
<div class="two fields"> | |
<div class="required field"> | |
<label>Name</label> | |
<input type="text" name="title" value={ report.title } onchange={ updateValue.bind(this, 'title') }/> | |
</div> | |
<div class="required field"> | |
<label>Type</label> | |
<select class="ui fluid search dropdown type" name="type"> | |
<option value="">Choose a type</option> | |
<option each={ opts.types } value={ type }>{ type }</option> | |
</select> | |
</div> | |
</div> | |
<div class="required field"> | |
<label>Readable roles</label> | |
<input class="hide" placeholder="Readable roles" type="text" name="readRoles" id="readRoles" value={ report.readRoles }> | |
<div class="tags"> | |
<div class="ui label" each={ role in report.readRoles }> | |
{role} <i class="delete icon" onclick={ parent.removeTag }></i> | |
</div> | |
</div> | |
<select class="ui reportRoles fluid search dropdown" name="selectRole" id="selectRole"> | |
<option value="">Choose a role</option> | |
<option each={ role in roles } value={ role.value }>{ role.name }</option> | |
</select> | |
</div> | |
<div class={ field: 1, required: report.type == 'custom' } show={ report.type == 'custom' }> | |
<label>URL</label> | |
<input type="text" name="url" value={ report.url } onchange={ updateValue.bind(this, 'url') } /> | |
</div> | |
<div class={ field: 1, required: report.type != 'custom' }> | |
<label>SQL</label> | |
<text-codemirror class="codemirror-sql" id="codemirror-sql" name="sql" mode="text/x-pgsql" value="{ report.sql }"></text-codemirror> | |
</div> | |
<!-- Table displaying report columns and description --> | |
<div class={ui: 1, inverted: 1, dimmer: 1, active: loading }> | |
<div class="ui indeterminate text loader"> | |
<span>{ overview.section }…</span> | |
</div> | |
</div> | |
<table class="ui table" if={ !loading }> | |
<thead> | |
<tr> | |
<th class="column">Column</th> | |
<th class="description">Description</th> | |
</tr> | |
</thead> | |
<tbody if={ report.columnDescription }> | |
<tr each={ column, description in report.columnDescription }> | |
<td>{ column }</td> | |
<td><input type="text" name="description" value={ description } data-column="{ column }" onchange={ parent.updateValue.bind(this, 'columnDescription') } placeholder="Column description"/></td> | |
</tr> | |
</tbody> | |
<tbody if={ !report.columnDescription } class="empty"> | |
<tr> | |
<td colspan="2"> | |
<div class="ui yellow message fluid"> | |
There are no column descriptions | |
</div> | |
</td> | |
</tr> | |
</tbody> | |
</table> | |
</div> | |
</form> | |
<script> | |
let tag = this; | |
tag.report = {}; | |
tag.roles = [].concat(AppTag.opts.roles); | |
tag.loading = false; | |
tag.overview = {}; | |
tag.on("mount", () => { | |
AppTag.prepareTag(tag); | |
tag.report = tag.opts.report; | |
// Dropdown menu setup | |
$(tag.root).find(".ui.type.dropdown").dropdown({ | |
fullTextSearch: true, | |
onChange: function (value) { | |
tag.report.type = value; | |
tag.trigger("dropdownchange", [this, value]); | |
tag.update(); | |
} | |
}); | |
tag.$tag.find(".ui.reportRoles.dropdown").dropdown({ | |
sortSelect: true, | |
fullTextSearch: true, | |
onChange: () => { | |
tag.selectRoles(); | |
tag.update(); | |
} | |
}); | |
}); | |
tag.on("update", () => { | |
tag.report = tag.opts.report; | |
if (tag.report.type) { | |
$(tag.root).find(".ui.dropdown.type").dropdown("set selected", tag.report.type); | |
} | |
if (tag.report.sql) { | |
if (!tag.report.columnDescription) { | |
tag.prepareColumnHeaders(); | |
} | |
} | |
tag.removeSelectedRoles(); | |
}); | |
tag.on("get-values", (cb) => { | |
if (tag.report.columnDescription) { | |
tag.report.columnDescription = JSON.stringify(tag.report.columnDescription); | |
} | |
// Get SQL query from code mirror text area | |
tag.report.sql = tag.tags.sql.editor.getDoc().getValue(); | |
// Remove semicolon from end of query if exists | |
let q = tag.report.sql; | |
if (q[q.length-1] == ";") { | |
tag.report.sql = q.substring(0, q.length-1); | |
} | |
cb(tag.report); | |
}); | |
tag.removeTag = (ev) => { | |
let t = $(ev.target).closest(".ui .label").text().trim(); | |
$(ev.target).closest(".ui .label").remove(); | |
if (tag.report && tag.report.readRoles) { | |
let index = tag.report.readRoles.indexOf(t); | |
if (index > -1) { | |
tag.report.readRoles.splice(index, 1); | |
} | |
} | |
tag.removeSelectedRoles(); | |
}; | |
tag.updateValue = (key, ev) => { | |
switch (key) { | |
case "columnDescription": | |
tag.report[key][ev.target.dataset.column] = ev.target.value; | |
break | |
case "sql": | |
if (tag[key]) { | |
tag.report[key] = tag[key].value; | |
} | |
if (!tag[key].value) { | |
tag.report.columnDescription = ""; | |
return | |
} | |
tag.prepareColumnHeaders(); | |
break | |
default: | |
if (tag[key]) { | |
tag.report[key] = tag[key].value; | |
} | |
} | |
}; | |
tag.prepareColumnHeaders = () => { | |
let limitRegex = /(\s+\n*LIMIT \d+);?|(\;)$/im; | |
let columnHeadersQuery = tag.report.sql.trim(); | |
columnHeadersQuery = tag.report.sql + " LIMIT 1;"; | |
if (tag.report.sql.match(limitRegex) && tag.report.sql.match(limitRegex)[0]) { | |
columnHeadersQuery = tag.report.sql.replace(limitRegex, " LIMIT 1;"); | |
} | |
tag.loading = true; | |
tag.overview.section = "Preparing column headers"; | |
tag.update(); | |
request.get("/query/sql") | |
.query({ | |
q: columnHeadersQuery, | |
timeout: "30", | |
format: "json", | |
}).end((res) => { | |
if (res.error) { | |
alert("Invalid SQL query"); | |
tag.report.columnDescription = {}; | |
tag.loading = false; | |
tag.update(); | |
return; | |
} | |
if (res.body.length && !tag.report.columnDescription) { | |
let columns = res.body[0]; | |
tag.report.columnDescription = {}; | |
for (let column in columns) { | |
tag.report.columnDescription[column] = ""; | |
} | |
} | |
if (res.body.length && tag.report.columnDescription) { | |
let columns = res.body[0]; | |
console.log("columns", columns); | |
console.log("columnDescription", tag.report.columnDescription); | |
for (let column in tag.report.columnDescription) { | |
if(!columns.hasOwnProperty(column)){ | |
console.log(column + " does not exists!"); | |
delete tag.report.columnDescription[column]; | |
} | |
} | |
for (let column in columns) { | |
tag.report.columnDescription[column] = tag.report.columnDescription[column] || ""; | |
} | |
} | |
tag.loading = false; | |
tag.update(); | |
}); | |
}; | |
tag.selectRoles = () => { | |
let role = tag.selectRole.value; | |
if (!tag.report.readRoles) { | |
tag.report.readRoles = []; | |
} | |
tag.report.readRoles.push(role); | |
tag.removeSelectedRoles(); | |
}; | |
tag.removeSelectedRoles = () => { | |
tag.roles = [].concat(AppTag.opts.roles); | |
let selectedRoles = tag.report.readRoles || []; | |
selectedRoles.forEach((selectedRole) => { | |
tag.roles.every((r, index) => { | |
if (r.value === selectedRole) { | |
tag.roles.splice(index, 1); | |
return false; | |
} | |
return true; | |
}); | |
}); | |
tag.update(); | |
}; | |
</script> | |
</reports-form> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<text-codemirror> | |
<textarea class={ opts.class } id={ opts.id } name={ opts.name } spellcheck="false">{ opts.value }</textarea> | |
<script> | |
let tag = this; | |
tag.on("mount", () => { | |
AppTag.prepareTag(tag); | |
let itemClass = "." + tag.opts.class; | |
console.log("mode:", tag.opts.mode); | |
let code = $(tag.root).find(itemClass)[0]; | |
tag.editor = CodeMirror.fromTextArea(code, { | |
mode: tag.opts.mode, | |
lineNumbers: true, | |
lineWrapping: false, | |
indentWithTabs: true, | |
smartIndent: true, | |
matchBrackets : true, | |
autofocus: true, | |
extraKeys: {"Ctrl-Space": "autocomplete"}, | |
theme: "neat" | |
}); | |
}); | |
tag.on("update", () => { | |
if (tag.editor && tag.opts.value) { | |
tag.editor.getDoc().setValue(tag.opts.value); | |
tag.editor.refresh(); | |
} | |
}); | |
</script> | |
</text-codemirror> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment