Skip to content

Instantly share code, notes, and snippets.

@sameh-sharaf
Created September 12, 2016 09:28
Show Gist options
  • Save sameh-sharaf/b79d3d769614da6774d0fe1ff0fb0ec9 to your computer and use it in GitHub Desktop.
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 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 }&hellip;</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>
<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