aboutsummaryrefslogtreecommitdiff
path: root/gn2/wqflask
diff options
context:
space:
mode:
Diffstat (limited to 'gn2/wqflask')
-rw-r--r--gn2/wqflask/templates/generif.html101
-rw-r--r--gn2/wqflask/templates/gn_editor.html238
-rw-r--r--gn2/wqflask/templates/gn_editor_commit.html55
-rw-r--r--gn2/wqflask/templates/gn_editor_results_page.html46
-rw-r--r--gn2/wqflask/templates/gn_editor_settings.html195
-rw-r--r--gn2/wqflask/templates/wiki/edit_wiki.html93
-rw-r--r--gn2/wqflask/templates/wiki/genewiki.html31
-rw-r--r--gn2/wqflask/views.py109
8 files changed, 756 insertions, 112 deletions
diff --git a/gn2/wqflask/templates/generif.html b/gn2/wqflask/templates/generif.html
deleted file mode 100644
index ac815b43..00000000
--- a/gn2/wqflask/templates/generif.html
+++ /dev/null
@@ -1,101 +0,0 @@
-{% extends "base.html" %}
-
-{% block title %}
-GeneWiki Entry for {{ symbol }}
-{% endblock %}
-
-{% block css %}
-<style>
-
- .badge {
- vertical-align: top;
- background-color: #336699;
- }
-
- .list-group {
- counter-reset: gnentries;
- }
-
- summary::before {
- counter-increment: gnentries;
- content: counter(gnentries) "." " ";
- }
-
- summary:hover {
- cursor: zoom-in;
- }
-</style>
-
-{% endblock %}
-{% block content %}
-
-
-<div class="container">
- <h1 class="page-header">GeneWiki For {{ symbol }}</h1>
- <p class="well"><strong>GeneWiki</strong> enables you to enrich the annotation of genes and transcripts.</p>
-
- <h3>
- <strong>GeneNetwork</strong>
- <span class="badge">
- {{ entries.gn_entries|length if entries.gn_entries[0] else 0 }}
- </span>:
- </h3>
- {% if entries.gn_entries[0] %}
- <ul class="list-group">
- {% for entry in entries.gn_entries %}
- <li class="list-group-item">
- <details>
- <summary>
- {{ entry["entry"]["value"] }}
- {% if entry.get("weburl") %}
- <sup><small><a href="{{ entry.weburl.value }}" target="_blank"><span class="glyphicon glyphicon-globe" aria-hidden="true"></span> web</a></small></sup>
- {% endif %}
- </summary>
- <dl class="dl-horizontal">
- <dt>Author:</dt>
- <dd>{{ entry["author"]["value"] }}</dd>
-
- {% if entry.get("geneCategory") %}
- <dt>Category:</dt>
- <dd>{{ entry["geneCategory"]["value"]}}</dd>
- {% endif %}
-
- <dt>Add Time:</dt>
- <dd>{{ entry["created"]["value"]}}</dd>
- </dl>
- </details>
- </li>
- {% endfor %}
- </ul>
-
- {% else %}
-
- <p class="well"><u>There are no GeneNetwork entries for <b>{{ symbol }}.</b></u></p>
-
- {% endif %}
-
- <h3>
- <strong>GeneRIF from NCBI</strong>
- <span class="badge">
- {{ entries.ncbi_entries|length if entries.ncbi_entries[0] else 0 }}
- </span>:
- </h3>
- {% if entries.ncbi_entries[0] %}
- <ol>
- {% for entry in entries.ncbi_entries %}
- <li>
- {{ entry.entry.value }}
- (<a href="{{ entry['generif']['value'] }}" target="_blank">{{ entry["speciesBinomialName"]["value"] }}</a>)
- {% if entry.PubMedId.value != "" %}
- {% set pmids = entry.PubMedId.value.split(",") %}
- (PubMed: {% for id in pmids %} <a href="http://rdf.ncbi.nlm.nih.gov/pubmed/{{ id }}" target="_blank">{{ id }}</a>{% endfor %})
- <sup><small><em>{{ entry.createdOn.value }}</em></small></sup>
- {% endif %}
- </li>
- {% endfor %}
- </ol>
- {% else %}
- <p class="well"><u>There are no NCBI entries for <b>{{ symbol }}.</b></u></p>
- {% endif %}
-</div>
-{% endblock %}
diff --git a/gn2/wqflask/templates/gn_editor.html b/gn2/wqflask/templates/gn_editor.html
new file mode 100644
index 00000000..e5c649d1
--- /dev/null
+++ b/gn2/wqflask/templates/gn_editor.html
@@ -0,0 +1,238 @@
+{% extends "base.html" %}
+{% block title %}Genenetwork Files Editor{% endblock %}
+{% block css %}
+ <style>
+ #diffBtn {
+ cursor:pointer
+ }
+ </style>
+ <link rel="stylesheet"
+ type="text/css"
+ href="{{ url_for('css', filename='diff2html/diff2html.min.css') }}" />
+ <link rel="stylesheet"
+ type="text/css"
+ href="{{ url_for('css', filename='highlight/default.min.css') }}" />
+{% endblock %}
+{% block search %}{% endblock %}
+{% block content %}
+ <section class="container-fluid">
+ <header class="row">
+ <nav class="navbar" style="background-color:#ccc">
+ <div class="container-fluid">
+ <div class="navbar-header">
+ <a class="navbar-brand" href="#"><strong>GN Editor</strong></a>
+ </div>
+ <div style="padding-right:3.6rem">
+ <ul class="nav navbar-nav navbar-right">
+ <li>
+ <a href="#"
+ hx-get="/editor/commit"
+ hx-target="#output"
+ hx-trigger="click"
+ hx-swap="innerHTML">Commit</a>
+ </li>
+ <li>
+ <a hx-trigger="click" id="diffBtn" hx-swap="innerHTML">Diff</a>
+ </li>
+ <li>
+ <a href="#"
+ hx-get="/editor/settings"
+ hx-target="#output"
+ hx-trigger="click"
+ hx-swap="innerHTML">Settings</a>
+ </li>
+ </ul>
+ </div>
+ </div>
+ </nav>
+ </header>
+ <div>
+ <div class="row" id="gn-editor">
+ <section class="col-sm-6" id="editor" style="height:100vh">
+ <textarea name="ckcontent" id="ckcontent" style='display:none'>
+ </textarea>
+ </section>
+ <section class="col-sm-6">
+ <div class="row">
+ <section class="col-sm-10 col-sm-offset-1"
+ id="output"
+ style="height:100vh;
+ overflow-y:scroll;
+ padding-top:2.5rem"
+ id="swap">
+ </section>
+ </div>
+ </section>
+ </div>
+ </div>
+ </section>
+{% endblock %}
+{% block js %}
+ <script src="{{ url_for('js', filename='jquery/jquery.min.js') }}"
+ type="text/javascript"></script>
+ <script language="javascript"
+ type="text/javascript"
+ src="{{ url_for('js', filename='diff2html/diff2html.min.js') }}"></script>
+ <script language="javascript"
+ type="text/javascript"
+ src="{{ url_for('js', filename='jquery-ui/jquery-ui.min.js') }}"></script>
+ <script language="javascript"
+ type="text/javascript"
+ src="{{ url_for('js', filename='htmx.min.js') }}"></script>
+ <script language="javascript"
+ type="text/javascript"
+ src="{{ url_for('js', filename='jsdiff/diff.min.js') }}"></script>
+ <script language="javascript"
+ type="text/javascript"
+ src="{{ url_for('js', filename='ace/ace.js') }}"></script>
+ <script language="javascript"
+ type="text/javascript"
+ src="{{ url_for('js', filename='marked/marked.min.js') }}"></script>
+ <script language="javascript"
+ type="text/javascript"
+ src="{{ url_for('js', filename='marked/marked-highlight.js') }}"></script>
+ <script language="javascript"
+ type="text/javascript"
+ src="{{ url_for('js', filename='highlight/highlight.min.js') }}"></script>
+ <script language="javascript"
+ type="text/javascript"
+ src="{{ url_for('js', filename='ckeditor/ckeditor.js') }}"></script>
+ <script type="text/javascript">
+ document.addEventListener('DOMContentLoaded', function() {
+ $('footer').hide()
+ var editor_configurations = {
+ selectionStyle: 'line',// "line"|"text"
+ highlightActiveLine: true, // boolean
+ highlightSelectedWord: true, // boolean
+ readOnly: false, // boolean: true if read only
+ cursorStyle: 'ace', // "ace"|"slim"|"smooth"|"wide"
+ mergeUndoDeltas: true, // false|true|"always"
+ behavioursEnabled: true, // boolean: true if enable custom behaviours
+ wrapBehavioursEnabled: true, // boolean
+ autoScrollEditorIntoView: undefined, // boolean: this is needed if editor is inside scrollable
+ keyboardHandler: null,
+
+ // renderer options
+ animatedScroll: false, // boolean: true if scroll should be animated
+ displayIndentGuides: false, // boolean: true if the indent should be shown. See 'showInvisibles'
+ showInvisibles: false, // boolean -> displayIndentGuides: true if show the invisible tabs/spaces in indents
+ showPrintMargin: true, // boolean: true if show the vertical print margin
+ printMarginColumn: 80, // number: number of columns for vertical print margin
+ printMargin: undefined, // boolean | number: showPrintMargin | printMarginColumn
+ showGutter: true, // boolean: true if show line gutter
+ fadeFoldWidgets: false, // boolean: true if the fold lines should be faded
+ showFoldWidgets: true, // boolean: true if the fold lines should be shown ?
+ showLineNumbers: true,
+ highlightGutterLine: false, // boolean: true if the gutter line should be highlighted
+ hScrollBarAlwaysVisible: false, // boolean: true if the horizontal scroll bar should be shown regardless
+ vScrollBarAlwaysVisible: false, // boolean: true if the vertical scroll bar should be shown regardless
+ fontSize: 16, // number | string: set the font size to this many pixels
+ fontFamily: undefined, // string: set the font-family css value
+ maxLines: undefined, // number: set the maximum lines possible. This will make the editor height changes
+ minLines: undefined, // number: set the minimum lines possible. This will make the editor height changes
+ maxPixelHeight: 0, // number -> maxLines: set the maximum height in pixel, when 'maxLines' is defined.
+ scrollPastEnd: 0, // number -> !maxLines: if positive, user can scroll pass the last line and go n * editorHeight more distance
+ fixedWidthGutter: false, // boolean: true if the gutter should be fixed width
+ theme: "ace/theme/textmate", // theme string from ace/theme or custom?
+ scrollSpeed: 2, // number: the scroll speed index
+ dragDelay: 0,
+ dragEnabled: true, // boolean: enable dragging
+ focusTimout: 0, // number: the focus delay before focus starts.
+ tooltipFollowsMouse: true, // boolean: true if the gutter tooltip should follow mouse
+ // session options
+ firstLineNumber: 1, // number: the line number in first line
+ overwrite: false, // boolean
+ newLineMode: 'auto', // "auto" | "unix" | "windows"
+ useWorker: true, // boolean: true if use web worker for loading scripts
+ useSoftTabs: true, // boolean: true if we want to use spaces than tabs
+ tabSize: 4, // number
+ wrap: true, // boolean | string | number: true/'free' means wrap instead of horizontal scroll, false/'off' means horizontal scroll instead of wrap, and number means number of column before wrap. -1 means wrap at print margin
+ indentedSoftWrap: true, // boolean
+ foldStyle: 'markbegin', // enum: 'manual'/'markbegin'/'markbeginend'.
+ mode: 'ace/mode/markdown'
+
+ }
+ let hash = {{ hash|tojson }}
+ let filePath = {{ file_path|tojson }}
+ let fileExt = (filePath.substring(filePath.lastIndexOf('.')+1, filePath.length) || "md").toLowerCase();
+ let data = {{ content|tojson }}
+
+ localStorage.setItem("gn_editor_sha" ,hash)
+ htmx.on("#output", "commitEvent", function(event){
+ htmx.ajax("POST", "/editor/commit", {target: "#output", swap:"innerHTML",values: {'msg':event.detail.payload, 'content': editor.getValue(), "hash": localStorage.getItem("gn_editor_sha"), "file_path": filePath}})
+ })
+
+ htmx.on("#output", "diffEvent", function(event){
+ var fileName = "{{ file_path }}"
+ var diffContent = Diff.createTwoFilesPatch(fileName,fileName, data, editor.getValue())
+ var diffHtml = Diff2Html.html(diffContent, {
+ drawFileList: true,
+ matching: 'lines',
+ outputFormat: 'line-by-line',
+ });
+ htmx.find("#output").innerHTML = diffHtml
+ })
+
+ htmx.on("#output", "updateEditor", function(event){
+ if (fileExt != 'rtf'){
+ editor.setOptions({
+ ...editor_configurations,
+ ...event.detail.payload
+ })
+ editor.renderer.updateFull();
+ }
+
+ })
+
+ htmx.on("#diffBtn","click",function(event){
+ //dispatch your event here
+ console.log("Clicked diff btn here")
+ htmx.find("#output").dispatchEvent(
+ new CustomEvent("diffEvent", {
+ bubbles: true,
+ detail: {},
+ }),
+ );
+ })
+ function updatePreview(){
+ const {markedHighlight} = globalThis.markedHighlight;
+
+ let new_marked = new marked.Marked(
+ markedHighlight({
+ langPrefix: 'hljs language-',
+ highlight(code, lang) {
+ const language = hljs.getLanguage(lang) ? lang : 'plaintext';
+ return hljs.highlight(code, { language }).value;
+ }}));
+ new_marked.use({
+ pedantic: false,
+ gfm: true,
+ });
+ previewContent = document.querySelector("#output");
+ var markdownContent = editor.getValue();
+ var htmlContent = new_marked.parse(markdownContent) //work on error handling for invalid markdown
+ previewContent.innerHTML = htmlContent;
+ }
+
+ if (fileExt == "rtf"){
+ var editor = CKEDITOR.replace('ckcontent', {
+ height: '100vh',
+ });
+ editor.setData(data)
+ editor.getValue = editor.getData
+ }
+ else {
+ var editor = ace.edit("editor");
+ editor.setOptions(editor_configurations);
+ editor.container.style.resize = "horizontal";
+ editor.getSession().on("change", function(e){
+ updatePreview()
+ })
+ editor.setValue(data, -1);
+ }
+
+ });
+
+
+ </script>
+{% endblock %}
diff --git a/gn2/wqflask/templates/gn_editor_commit.html b/gn2/wqflask/templates/gn_editor_commit.html
new file mode 100644
index 00000000..84ebd818
--- /dev/null
+++ b/gn2/wqflask/templates/gn_editor_commit.html
@@ -0,0 +1,55 @@
+<section classs="row commit-content" style="padding-top:25px">
+ <div class="col-sm-10 col-sm-offset-1">
+ <div>
+ <div>
+ <h2>
+ <i>Commit your Changes</i>
+ </h2>
+ </div>
+ </div>
+ <br>
+ <div>
+ <div class="row">
+ <label class="col-sm-8" for="message">
+ <i>*Commit Message*</i>
+ </label>
+ </div>
+ <br>
+ <div class="row">
+ <textarea style="white-space: normal" rows="12" class="col-sm-12" name="message" required id="commit-message">
+ </textarea>
+ </div>
+ </div>
+ <br>
+ <br>
+ <div class="row">
+ <button id="btn-commit" class="btn btn-primary col-lg-3 col-lg-offset-1 col-sm-4 col-sm-offset-1">Commit</button>
+ <button id="btn-diff" class="btn col-lg-3 col-lg-offset-1 col-sm-4 col-sm-offset-1">Show Diff</button>
+ </div>
+ <br>
+ <div id="diff_page"></div>
+ </div>
+</section>
+{% block js %}
+ <script>
+ htmx.on("#btn-commit", "click", function(event){
+ let msg = htmx.find("#commit-message").value.trim()
+ if (msg != ""){
+ htmx.find("#output").dispatchEvent(
+ new CustomEvent("commitEvent", {
+ bubbles: true,
+ detail: {action: 'didInitialize', payload: msg},
+ }),
+ );
+ }
+ })
+ htmx.on("#btn-diff", "click", function(event){
+ htmx.find("#output").dispatchEvent(
+ new CustomEvent("diffEvent", {
+ bubbles: true,
+ detail: {},
+ }),
+ );
+ })
+ </script>
+{% endblock %}
diff --git a/gn2/wqflask/templates/gn_editor_results_page.html b/gn2/wqflask/templates/gn_editor_results_page.html
new file mode 100644
index 00000000..666bd432
--- /dev/null
+++ b/gn2/wqflask/templates/gn_editor_results_page.html
@@ -0,0 +1,46 @@
+<section classs="row commit-content" style="padding-top:25px">
+ <div class="col-sm-10 col-sm-offset-1">
+ <div>
+ <div>
+ <h2>
+ <i>Results status - {{ status }}</i>
+ </h2>
+ </div>
+ </div>
+ <br>
+ {% if error %}
+ <h1>
+ Error-type: <mark style="font-family: 'Linux Libertine','Georgia','Times','Source Serif Pro',serif"><b><i>{{ error }}</i></b></mark>
+ </h1>
+ <h3>
+ Error-message:
+ <mark style="font-family: 'Linux Libertine','Georgia','Times','Source Serif Pro',serif"><b><i>{{ msg }}</i></b></mark>
+ </h3>
+ {% else %}
+ <div>
+ <h3>
+ New Commit Sha: <span class="lead">
+ <mark style="font-family: 'Linux Libertine','Georgia','Times','Source Serif Pro',serif"><b><i>{{ commit_sha }}</i></b></mark>
+ </span>
+ </h3>
+ <br />
+ <div class="lead">
+ <h3>
+ Commit Message:
+ <mark style="font-family: 'Linux Libertine','Georgia','Times','Source Serif Pro',serif"><b><i>{{ message }}</i></b></mark>
+ </h3>
+ </div>
+ </div>
+ {% endif %}
+ <br>
+</div>
+</section>
+{% block js %}
+ <script>
+ var commitSha = "{{ commit_sha }}";
+ if (commitSha !="" && commitSha!= undefined){
+ localStorage.setItem("gn_editor_sha", commitSha)
+ }
+
+ </script>
+{% endblock %}
diff --git a/gn2/wqflask/templates/gn_editor_settings.html b/gn2/wqflask/templates/gn_editor_settings.html
new file mode 100644
index 00000000..1e2cae10
--- /dev/null
+++ b/gn2/wqflask/templates/gn_editor_settings.html
@@ -0,0 +1,195 @@
+<section>
+ <h4>
+ <i>Select a theme</i>
+ </h4>
+ <form>
+ <div class="form-check">
+ <input class="form-check-input"
+ type="radio"
+ name="theme"
+ id="twilightTheme"
+ value="twilight"
+ checked>
+ <label class="form-check-label" for="twilight">twilight</label>
+ </div>
+ <div class="form-check">
+ <input class="form-check-input"
+ type="radio"
+ name="theme"
+ id="draculaTheme"
+ value="dracula">
+ <label class="form-check-label" for="draculaTheme">dracula</label>
+ </div>
+ <div class="form-check">
+ <input class="form-check-input"
+ type="radio"
+ name="theme"
+ id="normalTheme"
+ value="textmate"
+ checked>
+ <label class="form-check-label" for="normalTheme">Text</label>
+ </div>
+ <div class="form-check">
+ <input class="form-check-input"
+ type="radio"
+ name="theme"
+ id="monokaiTheme"
+ value="monokai">
+ <label class="form-check-label" for="monokaiTheme">Monokai</label>
+ </div>
+ <div class="form-check">
+ <input class="form-check-input"
+ type="radio"
+ name="theme"
+ id="customTheme"
+ value="xcode">
+ <label class="form-check-label" for="customTheme">xcode</label>
+ </div>
+ <br>
+ <div class="form-group" style="padding-top:10px">
+ <h4>
+ <i>Select Font Size</i>
+ </h4>
+ <input type="range"
+ class="form-control-range"
+ id="fontSizeRange"
+ name="fontSizeRange"
+ min="10"
+ max="36"
+ step="1"
+ value="16">
+ <em><span id="fontSizeValue">16</span> px</em>
+ </div>
+ <br>
+ <div>
+ <h4>
+ <i>Select Wrap Option:</i>
+ </h4>
+ <div class="form-check">
+ <input class="form-check-input"
+ type="radio"
+ name="wrap"
+ id="normalTheme"
+ value="true"
+ checked>
+ <label class="form-check-label" for="normalTheme">True</label>
+ </div>
+ <div class="form-check">
+ <input class="form-check-input"
+ type="radio"
+ name="wrap"
+ id="monokaiTheme"
+ value="false">
+ <label class="form-check-label" for="monokaiTheme">False</label>
+ </div>
+ </div>
+ <div>
+ <h4>
+ <i>Cursor Styles:</i>
+ </h4>
+ <div class="form-check">
+ <input class="form-check-input"
+ type="radio"
+ name="cursor"
+ id="aceCursor"
+ value="ace"
+ checked>
+ <label class="form-check-label" for="aceCursor">ace</label>
+ </div>
+ <div class="form-check">
+ <input class="form-check-input"
+ type="radio"
+ name="cursor"
+ id="slimCursor"
+ value="slim">
+ <label class="form-check-label" for="slimCursor">slim</label>
+ </div>
+ <div class="form-check">
+ <input class="form-check-input"
+ type="radio"
+ name="cursor"
+ id="smoothCursor"
+ value="smooth">
+ <label class="form-check-label" for="smoothCursor">smooth</label>
+ </div>
+ <div class="form-check">
+ <input class="form-check-input"
+ type="radio"
+ name="cursor"
+ id="wideCursor"
+ value="wide">
+ <label class="form-check-label" for="wideCursor">wide</label>
+ </div>
+ </div>
+ </form>
+ <br>
+ <h4>
+ <i>Choose KeyBoard Binding:</i>
+ </h4>
+ <div class="form-check">
+ <input class="form-check-input"
+ type="radio"
+ name="keyboard"
+ id="default"
+ value="default"
+ checked>
+ <label class="form-check-label" for="default">Default</label>
+ </div>
+ <div class="form-check">
+ <input class="form-check-input"
+ type="radio"
+ name="keyboard"
+ id="vscode"
+ value="vscode">
+ <label class="form-check-label" for="vscode">Vscode</label>
+ </div>
+ <div class="form-check">
+ <input class="form-check-input"
+ type="radio"
+ name="keyboard"
+ id="emacs"
+ value="emacs">
+ <label class="form-check-label" for="emacs">Emacs</label>
+ </div>
+ <div class="form-check">
+ <input class="form-check-input"
+ type="radio"
+ name="keyboard"
+ id="vim"
+ value="vim">
+ <label class="form-check-label" for="vim">Vim</label>
+ </div>
+ <br>
+ <div class="row">
+ <div class="col-sm-offset-1">
+ <button class="btn btn-primary" id="settingBtn">Save Settings</button>
+ </div>
+ </div>
+</section>
+{% block js %}
+ <script>
+ $('#fontSizeRange').on('input', function () {
+ var fontSize = $(this).val();
+ $('#fontSizeValue').text(fontSize);
+ });
+
+ htmx.on("#settingBtn", "click", function () {
+ var formData = {
+ theme: `ace/theme/${$('input[name="theme"]:checked').val()}`,
+ fontSize: parseInt($("#fontSizeRange").val()),
+ wrap:$('input[name="wrap"]:checked').val()== "false" ? false : true,
+ cursorStyle: $('input[name="cursor"]:checked').val(),
+ keyboardHandler:($('input[name="keyboard"]:checked').val() == "default"?
+ null: `ace/keyboard/${$('input[name="keyboard"]:checked').val()}`
+ )
+
+ }
+ htmx.find("#output").dispatchEvent(
+ new CustomEvent("updateEditor", {
+ bubbles: true,
+ detail: {action: 'didInitialize', payload: formData},
+ }),
+ );
+ })
+ </script>
+{% endblock %}
diff --git a/gn2/wqflask/templates/wiki/edit_wiki.html b/gn2/wqflask/templates/wiki/edit_wiki.html
new file mode 100644
index 00000000..242456c4
--- /dev/null
+++ b/gn2/wqflask/templates/wiki/edit_wiki.html
@@ -0,0 +1,93 @@
+{% extends "base.html" %}
+
+{% block css %}
+<style>
+ .panel {
+ width: 90%;
+ margin: 2em;
+ }
+ .container {
+ align-content: center;
+ }
+</style>
+{% endblock %}
+
+{% block content %}
+
+{{ flash_me() }}
+<section class="container center-block">
+ <div class="row">
+ <div class="col-md-3"></div>
+ <div class="col-md-9">
+ <h2>Edit Wiki</h2>
+ <br>
+ <form class="form-horizontal" method="POST">
+ <input type="hidden" name="symbol" value="{{ content["symbol"] }}">
+ <div class="form-group">
+ <label for="reason" class="col-sm-2">Reason for Modification: </label>
+ <input type="text" name="reason" size=45 maxlength=100 required>
+ </div>
+ <div class="form-group">
+ <label for="species" class="col-sm-2">Species: </label>
+ <select name="species" id="species">
+ {% for name, species_name in species_dict.items() %}
+ {% if name == content["species"] %}
+ <option selected="selected" value="{{ name }}">{{ species_name }}</option>
+ {% else %}
+ <option value="{{ name }}">{{ species_name }}</option>
+ {% endif %}
+ {% endfor %}
+ </select>
+ </div>
+ <div class="form-group">
+ <label for="pubmed_ids" class="col-sm-2">PubMed IDS: </label>
+ <input type="text" name="pubmed_ids" size=25 maxlength=25 value="{{ " ".join(content["pubmed_ids"]) }}">
+ (optional, separate by blank space only)
+ </div>
+ <div class="form-group">
+ <label for="web_url" class="col-sm-2">Web resource URL: </label>
+ {% if content["weburl"] %}
+ <input type="text" name="web_url" value="{{ content["weburl"] }}" size=50 maxlength=255>
+ {% else %}
+ <input type="text" name="web_url" value="http://" size=50 maxlength=255>
+ {% endif %}
+ (optional)
+ </div>
+ <div class="form-group">
+ <label for="comment" class="col-sm-2">Text: </label>
+ <textarea name="comment" rows=5 cols=60 required>{{ content["comment"] }}</textarea>
+ </div>
+ <div class="form-group">
+ <label for="email" class="col-sm-2">Email: </label>
+ <input type="text" name="email" value="" required>
+ </div>
+ <div class="form-group">
+ <label for="usercode" class="col-sm-2">User Code: </label>
+ <input type="text" name="initial" value="{{ content["initial"] }}"/>
+ (optional user or project code or your initials)
+ </div>
+ <div class="form-group">
+ <label class="col-sm-2">Category of Gene<br>(Please select one or <br>many categories): </label>
+ <div class="col-sm-10">
+ {% for group in grouped_categories %}
+ <div class="row">
+ {% for cat in group %}
+ <label class="checkbox-inline col-sm-3">
+ {% if cat in content["categories"] %}
+ <input checked type="checkbox" name="genecategory" value="{{ cat }}"> {{ cat }}
+ {% else %}
+ <input type="checkbox" name="genecategory" value="{{ cat }} "> {{ cat }}
+ {% endif %}
+ </label>
+ {% endfor %}
+ </div>
+ {% endfor %}
+ </div>
+ <div class="form-group">
+ <button type="submit" name="submit" class="btn btn-primary">Update GeneWiki Entry</button>
+ <button type="reset" name="rest" class="btn btn-secondary" onClick="window.location.reload();">Reset</button>
+ </div>
+ </form>
+ </div>
+ </div>
+{% endblock %}
diff --git a/gn2/wqflask/templates/wiki/genewiki.html b/gn2/wqflask/templates/wiki/genewiki.html
new file mode 100644
index 00000000..496f5e28
--- /dev/null
+++ b/gn2/wqflask/templates/wiki/genewiki.html
@@ -0,0 +1,31 @@
+{% extends "base.html" %}
+{% block title %}GeneWiki Entry for {{ symbol }}{% endblock %}
+{% block content %}
+ {{ flash_me() }}
+ <div class = "container">
+ <h1 class = "page-header">GeneWiki Entries</h1>
+ <p>
+ GeneWiki enables you to enrich the annotation of genes and transcripts. Please submit or edit a GeneWiki note (500 characters max) related to a gene, its transcripts, or proteins. When possible include PubMed identifiers or web resource links (URL addresses). Please ensure that the additions will have widespread use. For additional information, check the GeneWiki <a href="https://gn1.genenetwork.org/GeneWikihelp.html" target="_blank">help document</a>.
+ </p>
+ <h3>GeneWiki For {{ symbol }}:</h3>
+ <h5>
+ <strong>GeneNetwork:</strong>
+ </h5>
+ {% if wiki %}
+ <ol>
+ {% for entry in wiki %}
+ <li>
+ {{ entry.get("comment") }}
+ {% if entry.get("web_url") %}
+ <sup> <small> <a href = "{{ entry.web_url }}" target = "_blank"> <span class = "glyphicon glyphicon-globe" aria-hidden = "true"></span>web</a></small></sup>
+ {% endif %}
+ </li>
+ {% endfor %}
+ </ol>
+ {% else %}
+ <p class = "well">
+ <u> There are no GeneNetwork entries for <b> {{ symbol }}.</b></u>
+ </p>
+ {% endif %}
+ </div>
+{% endblock %}
diff --git a/gn2/wqflask/views.py b/gn2/wqflask/views.py
index 993c6f0c..4421011b 100644
--- a/gn2/wqflask/views.py
+++ b/gn2/wqflask/views.py
@@ -1,4 +1,5 @@
"""Main routing table for GN2"""
+
import array
import base64
import csv
@@ -44,6 +45,7 @@ from flask import flash
from gn2.wqflask import search_results
from gn2.wqflask import server_side
+
# Used by YAML in marker_regression
from gn2.base.data_set import create_dataset
from gn2.base.trait import fetch_symbols
@@ -288,6 +290,38 @@ def gnqna():
return render_template("gnqa.html")
+@app.route("/editor/edit", methods=["GET"])
+@require_oauth2
+def edit_gn_doc_file():
+ file_path = request.args.get("file-path", "")
+ response = requests.get(f"http://localhost:8091/edit?file_path={file_path}")
+ response.raise_for_status()
+ return render_template("gn_editor.html", **response.json())
+
+
+@app.route("/editor/settings", methods=["GET"])
+@require_oauth2
+def configure_gn_editor():
+ return render_template("gn_editor_settings.html")
+
+
+@app.route("/editor/commit", methods=["GET", "POST"])
+@require_oauth2
+def commit_gn_doc():
+ # TODO add env variable for gn-guile web server
+ if request.method == "GET":
+ return render_template("gn_editor_commit.html")
+ results = requests.post("http://localhost:8091/commit", json={
+ "content": request.form.get("content"),
+ "filename": request.form.get("file_path"),
+ "username": session_info()["user"]["name"],
+ "email": session_info()["user"]["email"],
+ "commit_message": request.form.get("msg"),
+ "prev_commit": request.form.get("hash")})
+ data = results.json()
+ data["filename"] = request.form.get("file_path")
+ return render_template("gn_editor_results_page.html", **data)
+
@app.route("/gnqna/hist", methods=["GET", "DELETE"])
@require_oauth2
@@ -1039,7 +1073,8 @@ def corr_compute_page():
with Redis.from_url(REDIS_URL, decode_responses=True) as rconn:
if request.method == "POST":
request_received = datetime.datetime.utcnow()
- filename = hmac.hmac_creation(f"request_form_{request_received.isoformat()}")
+ filename = hmac.hmac_creation(
+ f"request_form_{request_received.isoformat()}")
filepath = f"{TMPDIR}{filename}"
with open(filepath, "wb") as pfile:
pickle.dump(request.form, pfile,
@@ -1201,19 +1236,25 @@ def display_diffs_users():
files=files)
-@app.route("/genewiki/<symbol>")
-def display_generif_page(symbol):
+@app.route("/genewiki/<string:symbol>")
+def display_genewiki_page(symbol: str):
"""Fetch GeneRIF metadata from GN3 and display it"""
- entries = requests.get(
- urljoin(
- GN3_LOCAL_URL,
- f"/api/metadata/genewiki/{symbol}"
+ wiki = {}
+ try:
+ wiki = requests.get(
+ urljoin(
+ GN3_LOCAL_URL,
+ f"/api/metadata/wiki/{symbol}"
+ )
)
- ).json()
+ wiki.raise_for_status()
+ wiki = wiki.json()
+ except requests.RequestException as excp:
+ flash(excp, "alert-warning")
return render_template(
- "generif.html",
+ "wiki/genewiki.html",
symbol=symbol,
- entries=entries
+ wiki=wiki
)
@@ -1346,7 +1387,8 @@ def edit_case_attributes(inbredset_id: int) -> Response:
def flash_success(resp):
def __succ__(remote_resp):
- flash(f"Success: {remote_resp.json()['message']}", "alert-success")
+ flash(
+ f"Success: {remote_resp.json()['message']}", "alert-success")
return resp
return __succ__
return monad_requests.post(
@@ -1472,3 +1514,48 @@ def approve_reject_diff() -> Response:
return redirect(url_for("view_diff",
inbredset_id=inbredset_id,
diff_id=form["diff_id"]))
+
+
+@app.route("/metadata/wiki/<int:comment_id>/edit", methods=["GET", "POST"])
+def edit_wiki(comment_id: int):
+ """fetch generif metadata from gn3 and display it"""
+ # FIXME: better error handling
+ if request.method == "GET":
+ last_wiki_resp = requests.get(urljoin(GN3_LOCAL_URL, f"/api/metadata/wiki/{comment_id}"))
+ last_wiki_resp.raise_for_status()
+ last_wiki_content = last_wiki_resp.json()
+
+ species_dict_resp = requests.get(urljoin(GN3_LOCAL_URL, "/api/metadata/wiki/species"))
+ species_dict_resp.raise_for_status()
+ species_dict = species_dict_resp.json()
+
+ categories_resp = requests.get(urljoin(GN3_LOCAL_URL, "/api/metadata/wiki/categories"))
+ categories_resp.raise_for_status()
+ categories = list(categories_resp.json().keys())
+ grouped_categories = [categories[i : i + 3] for i in range(0, len(categories), 3)]
+
+ return render_template(
+ "wiki/edit_wiki.html",
+ content=last_wiki_content,
+ species_dict=species_dict,
+ grouped_categories=grouped_categories,
+ )
+ if request.method == "POST":
+ post_data = request.form
+ payload = {
+ "symbol": post_data["symbol"],
+ "pubmed_ids": [x.strip() for x in post_data["pubmed_ids"].split()],
+ "species": post_data["species"],
+ "comment": post_data["comment"],
+ "email": post_data["email"],
+ "web_url": post_data["web_url"],
+ "initial": post_data["initial"],
+ "categories": post_data.getlist("genecategory"),
+ "reason": post_data["reason"],
+ }
+ post_response = requests.post(urljoin(GN3_LOCAL_URL, f"api/metadata/wiki/{comment_id}/edit"), json=payload)
+ post_response.raise_for_status()
+ post_res = post_response.json()
+
+ flash(f"Success: {post_res}", "alert-success")
+ return redirect(url_for("edit_wiki", comment_id=comment_id))