From 5334fc96cb6e61ee2f1c928dba457b827bd44dd3 Mon Sep 17 00:00:00 2001 From: Yi Hsiao Date: Tue, 22 May 2018 15:03:26 -0400 Subject: [PATCH 01/24] update document for dashboard --- sphinx_doc/dev_doc/dashboard.md | 327 +++++++++++++++++++++++++++++++- 1 file changed, 321 insertions(+), 6 deletions(-) diff --git a/sphinx_doc/dev_doc/dashboard.md b/sphinx_doc/dev_doc/dashboard.md index 369d33a02..9839e9fa2 100644 --- a/sphinx_doc/dev_doc/dashboard.md +++ b/sphinx_doc/dev_doc/dashboard.md @@ -396,20 +396,335 @@ email us (or phone us when the helpdesk becomes available). For example: ## Logout -- TBD --- ## Programming Structure -The Dashboard APIs to both the front end and the Apps exchanges data in JSON format. If any sender is unable to do so, server side -functions convert the incoming format to JSON before passing the data to the Dashboard. For example, the server converts -form data from the browser from HTML request to a JSON object. -- TBD +The Dashbord UI uses the bootstrap framework, and the gridstack.js, a jQuery plugin for widget layout. +This is drag-and-drop multi-column grid. It allows you to build draggable responsive bootstrap v3 friendly layouts. + +Basic usage: + +
+
+
+ +
+
+
+
+
+ + + +Options: + ++ always_show_resize_handle - if true the resizing handles are shown even the user is not hovering over the widget (default: false) + ++ animate - turns animation on (default: false) + ++ auto - if false it tells to do not initialize existing items (default: true) + ++ cell_height - one cell height (default: 60) + ++ draggable - allows to override jQuery UI draggable options. (default: {handle: '.grid-stack-item-content', scroll: true, appendTo: 'body'}) + ++ handle - draggable handle selector (default: '.grid-stack-item-content') + ++ height - maximum rows amount. Default is 0 which means no maximum rows + ++ float - enable floating widgets (default: false) + ++ item_class - widget class (default: 'grid-stack-item') + ++ min_width - minimal width. If window width is less grid will be shown in one-column mode (default: 768) + ++ placeholder_class - class for placeholder (default: 'grid-stack-placeholder') + ++ resizable - allows to override jQuery UI resizable options. (default: {autoHide: true, handles: 'se'}) + ++ vertical_margin - vertical gap size (default: 20) + ++ width - amount of columns (default: 12) + +Grid attributes: + ++ data-gs-animate - turns animation on + ++ data-gs-width - amount of columns + ++ data-gs-height - maximum rows amount. Default is 0 which means no maximum rows. + +Item attributes + ++ data-gs-x, data-gs-y - element position + ++ data-gs-width, data-gs-height - element size + ++ data-gs-max-width, data-gs-min-width, data-gs-max-height, data-gs-min-height - element constraints + ++ data-gs-no-resize - disable element resizing + ++ data-gs-no-move - disable element moving + ++ data-gs-auto-position - tells to ignore data-gs-x and data-gs-y attributes and to place element to the first available position + ++ data-gs-locked - the widget will be locked. It means another widgets could not move it during dragging or resizing. The widget is still can be dragged or resized. You need to add data-gs-no-resize and data-gs-no-move attributes to completely lock the widget. + + +Events: + ++ onchange(items) Occurs when widgets change their position/size + + var serialize_widget_map = function (items) { + console.log(items); + }; + $('.grid-stack').on('change', function (e, items) { + serialize_widget_map(items); + }); + ++ ondragstart(event, ui) + + $('.grid-stack').on('dragstart', function (event, ui) { + var grid = this; + var element = event.target; + }); + ++ ondragstop(event, ui) + + $('.grid-stack').on('dragstop', function (event, ui) { + var grid = this; + var element = event.target; + }); + ++ onresizestart(event, ui) + + $('.grid-stack').on('resizestart', function (event, ui) { + var grid = this; + var element = event.target; + }); + ++ onresizestop(event, ui) + + $('.grid-stack').on('resizestop', function (event, ui) { + var grid = this; + var element = event.target; + }); + +API: + ++ add_widget(el, x, y, width, height, auto_position) + + Creates new widget and returns it. + + Parameters: + + - el - widget to add + - x, y, width, height - widget position/dimensions (Optional) + - auto_position - if true then x, y parameters will be ignored and widget will be places on the first available position + + Widget will be always placed even if result height will be more + then grid height. You need to use will_it_fit method before call + add_widget for additional check. + + $('.grid-stack').gridstack(); + + var grid = $('.grid-stack').data('gridstack'); + grid.add_widget(el, 0, 0, 3, 2, true); + ++ batch_update() Initailizes batch updates. You will see no changes until commit method is called. + ++ cell_height() Gets current cell height. + ++ cell_height(val) + + Update current cell height. This method rebuilds an internal CSS stylesheet. + Note: You can expect performance issues if call this method too often. + + grid.cell_height(grid.cell_width() * 1.2); + ++ cell_width() Gets current cell width. + ++ commit() Finishes batch updates. Updates DOM nodes. You must call it after batch_update. + ++ disable() Disables widgets moving/resizing. This is a shortcut for: + + grid.movable('.grid-stack-item', false); + grid.resizable('.grid-stack-item', false); + ++ enable() Enables widgets moving/resizing. This is a shortcut for: + + grid.movable('.grid-stack-item', true); + grid.resizable('.grid-stack-item', true); + +get_cell_from_pixel(position) Get the position of the cell under a pixel on screen. + + Parameters : + + - position - the position of the pixel to resolve in absolute coordinates, as an object with top and leftproperties + + Returns an object with properties x and y i.e. the column and row in the grid. + ++ is_area_empty(x, y, width, height) Checks if specified area is empty. + ++ locked(el, val) Locks/unlocks widget. + + - el - widget to modify. + - val - if true widget will be locked. + ++ remove_widget(el, detach_node) Removes widget from the grid. + + Parameters: + + - el - widget to remove. + - detach_node - if false DOM node will not be removed from the tree (Optional. Default true). + ++ remove_all() Removes all widgets from the grid. + ++ resize(el, width, height) Changes widget size + + Parameters: + + - el - widget to resize + - width, height - new dimensions. If value is null or undefined it will be ignored. + + ++ move(el, x, y) Changes widget position + + Parameters: + + - el - widget to move + - x, y - new position. If value is null or undefined it will be ignored. + ++ resizable(el, val) Enables/Disables resizing. + + - el - widget to modify + - val - if true widget will be resizable. + ++ movable(el, val) Enables/Disables moving. + + - el - widget to modify + - val - if true widget will be draggable. + ++ update(el, x, y, width, height) + + Parameters: + + - el - widget to move + - x, y - new position. If value is null or undefined it will be ignored. + - width, height - new dimensions. If value is null or undefined it will be ignored. + + Updates widget position/size. + will_it_fit(x, y, width, height, auto_position) + + Returns true if the height of the grid will be less the vertical constraint. + Always returns true if grid does not have height constraint. + + if (grid.will_it_fit(new_node.x, new_node.y, new_node.width, new_node.height, true)) { + grid.add_widget(new_node.x, new_node.y, new_node.width, new_node.height, true); + } else { + alert('Not enough free space to place the widget'); + } + +Utils: + ++ GridStackUI.Utils.sort(nodes, dir, width) Sorts array of nodes + + - nodes - array to sort + - dir - 1 for asc, -1 for desc (optional) + - width - width of the grid. If undefined the width will be calculated automatically (optional). + + +Save grid to array: + +Because gridstack does not track any kind of user-defined widget id there is no reason to make serialization to be part of gridstack API. To serialize grid you can simply do something like this (let us say you store widget id inside data-custom-id attribute): + + var res = _.map($('.grid-stack .grid-stack-item:visible'), function (el) { + el = $(el); + var node = el.data('_gridstack_node'); + return { + id: el.attr('data-custom-id'), + x: node.x, + y: node.y, + width: node.width, + height: node.height + }; + }); + alert(JSON.stringify(res)); + +To run apps inside widgets use an iframe with width and height == 100%. + + + + + + +#### Touch devices support + + TBD ### Authentication Subsystem -The Authentication Subsystem provides the functionality for users to login and logout, and for the registration process to add new users and their + The Authentication Subsystem provides the functionality for users to login and logout, and for the registration process to add new users and their credentials to the site. #### Single Sign-On From 9729e1b6db4aa32a726898996d664109634cb1d5 Mon Sep 17 00:00:00 2001 From: Yi Hsiao Date: Tue, 22 May 2018 15:19:55 -0400 Subject: [PATCH 02/24] blast in dashboard --- .travis.yml | 1 + blast/admin.py | 9 + blast/models.py | 27 + blast/static/blast/scripts/blast-multi.js | 524 ++++++++++++------ blast/templates/blast/main.html | 41 +- blast/views.py | 109 +++- dashboard/static/dashboard/css/design.css | 427 ++++++++++++++ dashboard/static/dashboard/img/bg.png | Bin 0 -> 22427 bytes .../static/dashboard/img/sidebar-menu-02.png | Bin 0 -> 7102 bytes .../static/dashboard/img/sidebar-menu.png | Bin 0 -> 8167 bytes dashboard/templates/dashboard/blast_hist.html | 225 ++++++++ dashboard/templates/dashboard/index.html | 261 +++++++-- dashboard/views.py | 86 ++- i5k/settings.py | 5 - i5k/urls.py | 4 + misc/get_tag.py | 55 ++ requirements.txt | 2 +- setup.py | 5 + 18 files changed, 1496 insertions(+), 285 deletions(-) create mode 100755 dashboard/static/dashboard/css/design.css create mode 100755 dashboard/static/dashboard/img/bg.png create mode 100755 dashboard/static/dashboard/img/sidebar-menu-02.png create mode 100755 dashboard/static/dashboard/img/sidebar-menu.png create mode 100644 dashboard/templates/dashboard/blast_hist.html create mode 100644 misc/get_tag.py diff --git a/.travis.yml b/.travis.yml index 55b623907..3b896b24a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -21,6 +21,7 @@ matrix: # command to install dependencies install: + - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then sudo apt-get install enchant; fi - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew update; fi - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew install rabbitmq; fi - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew install memcached; fi diff --git a/blast/admin.py b/blast/admin.py index e5a828856..a4a7a69f2 100644 --- a/blast/admin.py +++ b/blast/admin.py @@ -136,3 +136,12 @@ def get_model_perms(self, request): admin.site.register(JbrowseSetting, JbrowseSettingAdmin) + +class BlastSearchAdmin(admin.ModelAdmin): + list_display = ('task_id', 'sequence',) + search_fields = ('task_id', 'sequence',) + actions_on_top = True + actions_on_bottom = True +admin.site.register(BlastSearch, BlastSearchAdmin) + + diff --git a/blast/models.py b/blast/models.py index 0e25764b5..833ecd95a 100755 --- a/blast/models.py +++ b/blast/models.py @@ -218,3 +218,30 @@ class JbrowseSetting(models.Model): def __unicode__(self): return self.url + +class BlastSearch(models.Model): + task_id = models.CharField(null=True, max_length=50) + search_tag = models.CharField(max_length=64) + enqueue_date = models.DateTimeField() + sequence = models.TextField(null=True) + soft_masking = models.BooleanField() + low_complexity = models.BooleanField() + penalty = models.IntegerField() + #tr_box = models.BooleanField(default=False) + #ga_box = models.BooleanField(default=False) + #pep_box = models.BooleanField(default=False) + evalue = models.DecimalField(max_digits=10, decimal_places=5) + gapopen = models.IntegerField() + strand = models.CharField(max_length=10) + gapextend = models.IntegerField() + program = models.CharField(max_length=32) + word_size = models.IntegerField() + reward = models.IntegerField() + max_target_seqs = models.IntegerField() + organisms = models.TextField(null=True) + matrix = models.CharField(max_length=10, null=True) + threshold = models.IntegerField(null=True) + + def __unicode__(self): + return self.search_tag + diff --git a/blast/static/blast/scripts/blast-multi.js b/blast/static/blast/scripts/blast-multi.js index 8e43a7423..f22584095 100644 --- a/blast/static/blast/scripts/blast-multi.js +++ b/blast/static/blast/scripts/blast-multi.js @@ -49,185 +49,199 @@ if (!Array.prototype.indexOf) { }; } $(function() { // document ready - /////////////////////////////// - // HTML STRUCTURE GENERATION // - /////////////////////////////// - - var organism_list_count = organism_list.length; - var alphabet_list_count = alphabet_list.length; - for (var i = 0; i < organism_list_count; i++) { - var organism_id = organism_list[i].toLowerCase().replace(' ', '-'); - // organism-checkbox - var $organism_checkbox = $('', { - 'organism': organism_id, - 'id': organism_id, - 'type': 'checkbox', - 'class': 'organism-checkbox ' + organism_id, - 'name': 'organism-checkbox[]', - }); - var $organism_div = $('
', { - 'organism': organism_id, - 'class': 'organism-div italic', - }).append($organism_checkbox).append(organism_list[i]); - $('
- + - + - - + + diff --git a/dashboard/templates/dashboard/hmmer_hist.html b/dashboard/templates/dashboard/hmmer_hist.html index a4e841df8..ef27739c5 100644 --- a/dashboard/templates/dashboard/hmmer_hist.html +++ b/dashboard/templates/dashboard/hmmer_hist.html @@ -17,9 +17,9 @@ - + - + @@ -36,13 +36,13 @@ + @@ -53,7 +53,7 @@ - +
- +
{% for search in search_list %} @@ -169,19 +144,19 @@

{% endfor %}

- -
-
+ + + - + - + - - + + diff --git a/dashboard/templates/dashboard/index.html b/dashboard/templates/dashboard/index.html index 5d41a58d0..e5f168861 100644 --- a/dashboard/templates/dashboard/index.html +++ b/dashboard/templates/dashboard/index.html @@ -1,3 +1,5 @@ +{% load staticfiles %} +{% load pipeline %} @@ -17,9 +19,9 @@ - - - + + + @@ -36,13 +38,13 @@ + @@ -53,7 +55,7 @@ - +
- -

Dashboard

-
-
+ +

Dashboard

+ + - + - + - - + + diff --git a/dashboard/views.py b/dashboard/views.py index 9b12d991b..f2aa637db 100644 --- a/dashboard/views.py +++ b/dashboard/views.py @@ -1,7 +1,5 @@ -''' - Dashboard views.py -''' from django.shortcuts import render, redirect +from django.core.urlresolvers import reverse from blast.models import BlastSearch from hmmer.models import HmmerSearch from clustal.models import ClustalSearch @@ -15,10 +13,15 @@ def dashboard(request): search_list = [] print 'Method: %s' % request.method - print 'Path: %s' % request.path + print 'Path: %s' % request.path # can be in two forms: /dashboard or /webapp/dashboard (also can be ended with /) + if request.path.endswith('/'): + relative_path = request.path.rstrip('/') + else: + relative_path = request.path + relative_path = relative_path.split('/')[-1] if request.method == 'GET': id_num = 0 - if request.path == '/dashboard' or request.path == '/home': + if relative_path == 'dashboard' or relative_path == 'home': print "GET: %s" % request.GET if 'search_id' in request.GET: if request.GET['app'] == 'blast': @@ -35,24 +38,24 @@ def dashboard(request): if 'searchagain' in request.GET: print 'SEARCHAGAIN' if request.GET['app'] == 'blast': - return redirect('/blast/%s' % search.task_id) + return redirect(reverse('blast:retrieve', kwargs={'task_id': search.task_id})) elif request.GET['app'] == 'hmmer': - return redirect('/hmmer/%s' % search.task_id) + return redirect(reverse('hmmer:retrieve', kwargs={'task_id': search.task_id})) elif request.GET['app'] == 'clustal': - return redirect('/clustal/%s' % search.task_id) + return redirect(reverse('clustal:retrieve', kwargs={'task_id': search.task_id})) elif 'editsearch' in request.GET: print 'EDITSEARCH' if request.GET['app'] == 'blast': - return redirect('/blast?search_id=%s' % search.search_tag) + return redirect(reverse('blast:create') + '?search_id=%s' % search.search_tag) elif request.GET['app'] == 'hmmer': - return redirect('/hmmer?search_id=%s' % search.search_tag) + return redirect(reverse('hmmer:create') + '?search_id=%s' % search.search_tag) elif request.GET['app'] == 'clustal': - return redirect('/clustal?search_id=%s' % search.search_tag) + return redirect(reverse('clustal:create') + '?search_id=%s' % search.search_tag) else: return render(request, 'dashboard/index.html') - if request.path == '/blast_hist': + elif relative_path == 'blast_hist': search_list = [] - for obj in BlastSearch.objects.filter(user=request.user): + for obj in BlastSearch.objects.filter(user=request.user.id): search_dict = {} id_num += 1 orgs = json.loads(obj.organisms) @@ -80,9 +83,9 @@ def dashboard(request): search_dict['organisms'] = orgs search_list.append(search_dict) return render(request, 'dashboard/blast_hist.html', { 'search_list': search_list}) - elif request.path == '/hmmer_hist': + elif relative_path == 'hmmer_hist': search_list = [] - for obj in HmmerSearch.objects.filter(user=request.user): + for obj in HmmerSearch.objects.filter(user=request.user.id): search_dict = {} id_num += 1 orgs = json.loads(obj.organisms) @@ -99,11 +102,10 @@ def dashboard(request): search_dict['sequence'] = seq search_dict['organisms'] = orgs search_list.append(search_dict) - pass return render(request, 'dashboard/hmmer_hist.html', { 'search_list': search_list}) - elif request.path == '/clustal_hist': + elif relative_path == 'clustal_hist': search_list = [] - for obj in ClustalSearch.objects.filter(user=request.user): + for obj in ClustalSearch.objects.filter(user=request.user.id): search_dict = {} id_num += 1 seq = (obj.sequence[:20] + '..') if len(obj.sequence) > 20 else obj.sequence @@ -116,7 +118,6 @@ def dashboard(request): search_dict['program'] = obj.program search_dict['sequence'] = obj.sequence search_list.append(search_dict) - pass return render(request, 'dashboard/clustal_hist.html', { 'search_list': search_list}) diff --git a/i5k/urls.py b/i5k/urls.py index 522ea2daa..077b2baba 100644 --- a/i5k/urls.py +++ b/i5k/urls.py @@ -23,7 +23,6 @@ url(r'blast_hist', dashboard, name='dashboard_blast'), url(r'hmmer_hist', dashboard, name='dashboard_hmmer'), url(r'clustal_hist', dashboard, name='dashboard_clustal'), - url(r'^admin/filebrowser/', include('filebrowser.urls')), # url(r'^grappelli/', include('grappelli.urls')), # Enable admin documentation: From 9cd58bc9c62d3fc777bf4846fcb908f34a119c6e Mon Sep 17 00:00:00 2001 From: Hsiao Yi Date: Thu, 11 Jan 2018 15:38:01 -0500 Subject: [PATCH 11/24] use model name as url in suit menu setting --- i5k/settings.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/i5k/settings.py b/i5k/settings.py index be5853920..47f195796 100755 --- a/i5k/settings.py +++ b/i5k/settings.py @@ -218,6 +218,8 @@ ) else: suit_menu = ( + {'app': 'app', 'label': 'Organism', 'icon':'icon-leaf', 'url': 'app.organism', 'models': ( + )}, {'app': 'blast', 'label': 'BLAST', 'icon': 'icon-leaf', 'models': ( {'model': 'blastqueryrecord'}, {'model': 'organism'}, From 78186e5f6b8b1842cd9928d7225843590ec33a9d Mon Sep 17 00:00:00 2001 From: Yi Hsiao Date: Thu, 11 Jan 2018 16:20:26 -0500 Subject: [PATCH 12/24] fix user without login can see other query result --- .../templates/dashboard/clustal_hist.html | 2 +- dashboard/templates/dashboard/hmmer_hist.html | 2 +- dashboard/views.py | 126 +++++++++--------- 3 files changed, 65 insertions(+), 65 deletions(-) diff --git a/dashboard/templates/dashboard/clustal_hist.html b/dashboard/templates/dashboard/clustal_hist.html index 3cec3efe0..2fbe948c7 100644 --- a/dashboard/templates/dashboard/clustal_hist.html +++ b/dashboard/templates/dashboard/clustal_hist.html @@ -1,7 +1,7 @@ - BLAST History + Clustal History diff --git a/dashboard/templates/dashboard/hmmer_hist.html b/dashboard/templates/dashboard/hmmer_hist.html index ef27739c5..b730b10a2 100644 --- a/dashboard/templates/dashboard/hmmer_hist.html +++ b/dashboard/templates/dashboard/hmmer_hist.html @@ -1,7 +1,7 @@ - BLAST History + HMMER History diff --git a/dashboard/views.py b/dashboard/views.py index f2aa637db..a9b0c607b 100644 --- a/dashboard/views.py +++ b/dashboard/views.py @@ -55,72 +55,72 @@ def dashboard(request): return render(request, 'dashboard/index.html') elif relative_path == 'blast_hist': search_list = [] - for obj in BlastSearch.objects.filter(user=request.user.id): - search_dict = {} - id_num += 1 - orgs = json.loads(obj.organisms) - orglist = orgs.split() - forgs = orglist[0] - seq = (obj.sequence[:20] + '..') if len(obj.sequence) > 20 else obj.sequence - date_str = obj.enqueue_date.strftime('%b %d %H:%M:%S') - search_dict['search_head'] = '%s - %s - %s - %s' % (obj.search_tag, date_str, obj.program, forgs) - search_dict['id_str'] = 'collapsible' + str(id_num) - search_dict['task_id'] = obj.task_id - search_dict['search_tag'] = obj.search_tag - search_dict['soft_masking'] = obj.soft_masking - search_dict['enqueue_date'] = obj.enqueue_date - search_dict['low_complexity'] = obj.low_complexity - search_dict['penalty'] = obj.penalty - search_dict['evalue'] = obj.evalue - search_dict['gapopen'] = obj.gapopen - search_dict['strand'] = obj.strand - search_dict['program'] = obj.program - search_dict['reward'] = obj.reward - search_dict['gapextend'] = obj.gapextend - search_dict['word_size'] = obj.word_size - search_dict['max_target_seqs'] = obj.max_target_seqs - search_dict['sequence'] = seq - search_dict['organisms'] = orgs - search_list.append(search_dict) + if request.user.is_authenticated(): + for obj in BlastSearch.objects.filter(user=request.user.id): + search_dict = {} + id_num += 1 + orgs = json.loads(obj.organisms) + orglist = orgs.split() + forgs = orglist[0] + seq = (obj.sequence[:20] + '..') if len(obj.sequence) > 20 else obj.sequence + date_str = obj.enqueue_date.strftime('%b %d %H:%M:%S') + search_dict['search_head'] = '%s - %s - %s - %s' % (obj.search_tag, date_str, obj.program, forgs) + search_dict['id_str'] = 'collapsible' + str(id_num) + search_dict['task_id'] = obj.task_id + search_dict['search_tag'] = obj.search_tag + search_dict['soft_masking'] = obj.soft_masking + search_dict['enqueue_date'] = obj.enqueue_date + search_dict['low_complexity'] = obj.low_complexity + search_dict['penalty'] = obj.penalty + search_dict['evalue'] = obj.evalue + search_dict['gapopen'] = obj.gapopen + search_dict['strand'] = obj.strand + search_dict['program'] = obj.program + search_dict['reward'] = obj.reward + search_dict['gapextend'] = obj.gapextend + search_dict['word_size'] = obj.word_size + search_dict['max_target_seqs'] = obj.max_target_seqs + search_dict['sequence'] = seq + search_dict['organisms'] = orgs + search_list.append(search_dict) return render(request, 'dashboard/blast_hist.html', { 'search_list': search_list}) elif relative_path == 'hmmer_hist': - search_list = [] - for obj in HmmerSearch.objects.filter(user=request.user.id): - search_dict = {} - id_num += 1 - orgs = json.loads(obj.organisms) - orglist = orgs.split() - forgs = orglist[0] - seq = (obj.sequence[:20] + '..') if len(obj.sequence) > 20 else obj.sequence - date_str = obj.enqueue_date.strftime('%b %d %H:%M:%S') - search_dict['search_head'] = '%s - %s - %s - %s' % (obj.search_tag, date_str, obj.program, forgs) - search_dict['id_str'] = 'collapsible' + str(id_num) - search_dict['task_id'] = obj.task_id - search_dict['search_tag'] = obj.search_tag - search_dict['enqueue_date'] = obj.enqueue_date - search_dict['program'] = obj.program - search_dict['sequence'] = seq - search_dict['organisms'] = orgs - search_list.append(search_dict) - return render(request, 'dashboard/hmmer_hist.html', { 'search_list': search_list}) + if request.user.is_authenticated(): + for obj in HmmerSearch.objects.filter(user=request.user.id): + search_dict = {} + id_num += 1 + orgs = json.loads(obj.organisms) + orglist = orgs.split() + forgs = orglist[0] + seq = (obj.sequence[:20] + '..') if len(obj.sequence) > 20 else obj.sequence + date_str = obj.enqueue_date.strftime('%b %d %H:%M:%S') + search_dict['search_head'] = '%s - %s - %s - %s' % (obj.search_tag, date_str, obj.program, forgs) + search_dict['id_str'] = 'collapsible' + str(id_num) + search_dict['task_id'] = obj.task_id + search_dict['search_tag'] = obj.search_tag + search_dict['enqueue_date'] = obj.enqueue_date + search_dict['program'] = obj.program + search_dict['sequence'] = seq + search_dict['organisms'] = orgs + search_list.append(search_dict) + return render(request, 'dashboard/hmmer_hist.html', { 'search_list': search_list}) elif relative_path == 'clustal_hist': - search_list = [] - for obj in ClustalSearch.objects.filter(user=request.user.id): - search_dict = {} - id_num += 1 - seq = (obj.sequence[:20] + '..') if len(obj.sequence) > 20 else obj.sequence - date_str = obj.enqueue_date.strftime('%b %d %H:%M:%S') - search_dict['search_head'] = '%s - %s - %s' % (obj.search_tag, date_str, obj.program) - search_dict['id_str'] = 'collapsible' + str(id_num) - search_dict['task_id'] = obj.task_id - search_dict['search_tag'] = obj.search_tag - search_dict['enqueue_date'] = obj.enqueue_date - search_dict['program'] = obj.program - search_dict['sequence'] = obj.sequence - search_list.append(search_dict) - return render(request, 'dashboard/clustal_hist.html', { 'search_list': search_list}) - - + search_list = [] + if not request.user.is_authenticated(): + for obj in ClustalSearch.objects.filter(user=request.user.id): + search_dict = {} + id_num += 1 + seq = (obj.sequence[:20] + '..') if len(obj.sequence) > 20 else obj.sequence + date_str = obj.enqueue_date.strftime('%b %d %H:%M:%S') + search_dict['search_head'] = '%s - %s - %s' % (obj.search_tag, date_str, obj.program) + search_dict['id_str'] = 'collapsible' + str(id_num) + search_dict['task_id'] = obj.task_id + search_dict['search_tag'] = obj.search_tag + search_dict['enqueue_date'] = obj.enqueue_date + search_dict['program'] = obj.program + search_dict['sequence'] = obj.sequence + search_list.append(search_dict) + return render(request, 'dashboard/clustal_hist.html', { 'search_list': search_list}) elif request.method == 'POST': return render(request, 'dashboard/index.html', { 'year': datetime.now().year, 'title': 'Dashboard', }) From 0359b8e9401f4fb71eb132c732a247ff327b8e48 Mon Sep 17 00:00:00 2001 From: Yi Hsiao Date: Thu, 11 Jan 2018 16:39:52 -0500 Subject: [PATCH 13/24] fix a if conditional in dashboard.views --- dashboard/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dashboard/views.py b/dashboard/views.py index a9b0c607b..fd828b2ce 100644 --- a/dashboard/views.py +++ b/dashboard/views.py @@ -106,7 +106,7 @@ def dashboard(request): return render(request, 'dashboard/hmmer_hist.html', { 'search_list': search_list}) elif relative_path == 'clustal_hist': search_list = [] - if not request.user.is_authenticated(): + if request.user.is_authenticated(): for obj in ClustalSearch.objects.filter(user=request.user.id): search_dict = {} id_num += 1 From 3f81dc018bf87da7e06ae231c7b080af187827f1 Mon Sep 17 00:00:00 2001 From: Yi Hsiao Date: Tue, 16 Jan 2018 09:50:01 -0500 Subject: [PATCH 14/24] fix dashboard views.py logic --- dashboard/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dashboard/views.py b/dashboard/views.py index fd828b2ce..76d93df69 100644 --- a/dashboard/views.py +++ b/dashboard/views.py @@ -21,7 +21,7 @@ def dashboard(request): relative_path = relative_path.split('/')[-1] if request.method == 'GET': id_num = 0 - if relative_path == 'dashboard' or relative_path == 'home': + if relative_path.startswith('dashboard') or relative_path.startswith('home'): print "GET: %s" % request.GET if 'search_id' in request.GET: if request.GET['app'] == 'blast': From c7b672f059ad31127eb0af7671de83d7a60ba14f Mon Sep 17 00:00:00 2001 From: Yi Hsiao Date: Tue, 16 Jan 2018 10:41:19 -0500 Subject: [PATCH 15/24] fix form in dashboard templates --- dashboard/templates/dashboard/blast_hist.html | 2 +- dashboard/templates/dashboard/clustal_hist.html | 2 +- dashboard/templates/dashboard/hmmer_hist.html | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/dashboard/templates/dashboard/blast_hist.html b/dashboard/templates/dashboard/blast_hist.html index 40db8ed2a..31c3fa829 100644 --- a/dashboard/templates/dashboard/blast_hist.html +++ b/dashboard/templates/dashboard/blast_hist.html @@ -115,7 +115,7 @@

-
+
diff --git a/dashboard/templates/dashboard/clustal_hist.html b/dashboard/templates/dashboard/clustal_hist.html index 2fbe948c7..d3b4463f4 100644 --- a/dashboard/templates/dashboard/clustal_hist.html +++ b/dashboard/templates/dashboard/clustal_hist.html @@ -115,7 +115,7 @@

- +

Search Tag: {{ search.search_tag }}
diff --git a/dashboard/templates/dashboard/hmmer_hist.html b/dashboard/templates/dashboard/hmmer_hist.html index b730b10a2..32b244dc8 100644 --- a/dashboard/templates/dashboard/hmmer_hist.html +++ b/dashboard/templates/dashboard/hmmer_hist.html @@ -115,7 +115,7 @@

- +

Search Tag: {{ search.search_tag }}
From 73b474a15d4426963b3c0056973819edcc2dee69 Mon Sep 17 00:00:00 2001 From: Yi Hsiao Date: Tue, 16 Jan 2018 15:21:49 -0500 Subject: [PATCH 16/24] handle database file name with multiple dot when recovering the search from dashboard --- blast/static/blast/scripts/blast-multi.js | 4 ++-- blast/templates/blast/main.html | 26 +++++++++++------------ hmmer/static/hmmer/scripts/hmmer-multi.js | 2 +- 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/blast/static/blast/scripts/blast-multi.js b/blast/static/blast/scripts/blast-multi.js index 87d62c8d9..627476f30 100644 --- a/blast/static/blast/scripts/blast-multi.js +++ b/blast/static/blast/scripts/blast-multi.js @@ -674,7 +674,7 @@ $(function() { // document ready hist_checkbox = $("#hist_checkbox").val(); hist_check_array = hist_checkbox.split(','); for(var i = 0; i < hist_check_array.length; i++) { - name = hist_check_array[i].replace('.','\\.'); + name = hist_check_array[i].split('.').join('\\.'); if(name == ''){ break; } @@ -814,7 +814,7 @@ $(function() { // document ready hist_checkbox = $("#hist_checkbox").val(); hist_check_array = hist_checkbox.split(','); for(var i = 0; i < hist_check_array.length; i++){ - c = '#' + hist_check_array[i].split(".")[0] + c = '#' + hist_check_array[i].split('.').join('\\.'); $(c).prop("checked", true); $('#'+$(c).attr('organism')).prop("checked", true); }; diff --git a/blast/templates/blast/main.html b/blast/templates/blast/main.html index cce014ae6..b31cec93d 100755 --- a/blast/templates/blast/main.html +++ b/blast/templates/blast/main.html @@ -60,19 +60,19 @@
All organisms
- {% if blastdb_type_counts.genome_assembly or blastdb_type_counts.transcript %} -
- Nucleotide - {% if blastdb_type_counts.genome_assembly %}
{% endif %} - {% if blastdb_type_counts.transcript %}
{% endif %} -
- {% endif %} - {% if blastdb_type_counts.protein %} -
- Peptide -
-
- {% endif %} + {% if blastdb_type_counts.genome_assembly or blastdb_type_counts.transcript %} +
+ Nucleotide + {% if blastdb_type_counts.genome_assembly %}
{% endif %} + {% if blastdb_type_counts.transcript %}
{% endif %} +
+ {% endif %} + {% if blastdb_type_counts.protein %} +
+ Peptide +
+
+ {% endif %}
diff --git a/hmmer/static/hmmer/scripts/hmmer-multi.js b/hmmer/static/hmmer/scripts/hmmer-multi.js index 91211d335..643980bc0 100644 --- a/hmmer/static/hmmer/scripts/hmmer-multi.js +++ b/hmmer/static/hmmer/scripts/hmmer-multi.js @@ -646,7 +646,7 @@ OFAS004738-PA:polypeptide, AGGAGSCGQQNGNNFSQQSRGPTVEEVD-----\n\ hist_checkbox = $("#hist_checkbox").val(); hist_check_array = hist_checkbox.split(','); for(var i = 0; i < hist_check_array.length; i++) { - name = hist_check_array[i].replace('.','\\.'); + name = hist_check_array[i].split('.').join('\\.'); if(name == ''){ break; } From 9000d672db55ad17e9af680252b11bda236178e7 Mon Sep 17 00:00:00 2001 From: ifish Date: Sun, 28 Jan 2018 23:13:23 -0500 Subject: [PATCH 17/24] add navbar and template inheritance --- dashboard/static/dashboard/css/design.css | 9 +- dashboard/templates/dashboard/blast_hist.html | 148 ++++++----------- .../templates/dashboard/clustal_hist.html | 152 ++++++----------- dashboard/templates/dashboard/hmmer_hist.html | 154 +++++++----------- dashboard/templates/dashboard/index.html | 146 ++++++----------- 5 files changed, 213 insertions(+), 396 deletions(-) diff --git a/dashboard/static/dashboard/css/design.css b/dashboard/static/dashboard/css/design.css index 3a5813251..2f6191188 100755 --- a/dashboard/static/dashboard/css/design.css +++ b/dashboard/static/dashboard/css/design.css @@ -420,8 +420,7 @@ margin-left: 20%; } - - - - - +.container_dash{ + padding-right: 200px; + padding-left: 15px; +} diff --git a/dashboard/templates/dashboard/blast_hist.html b/dashboard/templates/dashboard/blast_hist.html index 31c3fa829..aa4adbd78 100644 --- a/dashboard/templates/dashboard/blast_hist.html +++ b/dashboard/templates/dashboard/blast_hist.html @@ -1,53 +1,55 @@ - - - - BLAST History - - - - - - - - - - - - +{% extends "app/layout.html" %} +{% load staticfiles %} +{% load pipeline %} +{% load jsonify %} +{% block head-scripts %} - - + - - - -
- - - -
+{% endblock %} + +{% block scripts %} + + + + + +{% endblock %} + + +{% block content %}
@@ -98,13 +100,10 @@

- + -
-
- -
+
{% for search in search_list %}
@@ -151,50 +150,5 @@

{% endfor %}

- -
-
-
- - - - - - - - - - - - +{% endblock %} diff --git a/dashboard/templates/dashboard/clustal_hist.html b/dashboard/templates/dashboard/clustal_hist.html index d3b4463f4..d1032efa6 100644 --- a/dashboard/templates/dashboard/clustal_hist.html +++ b/dashboard/templates/dashboard/clustal_hist.html @@ -1,53 +1,55 @@ - - - - Clustal History - - - - - - - - - - - - +{% extends "app/layout.html" %} +{% load staticfiles %} +{% load pipeline %} +{% load jsonify %} +{% block head-scripts %} - - + - - - -
- - - -
+{% endblock %} + +{% block scripts %} + + + + + +{% endblock %} + + +{% block content %}
@@ -86,7 +88,7 @@

@@ -98,13 +100,10 @@

- +
-
-
- -
+
{% for search in search_list %}
@@ -130,7 +129,7 @@

- +


@@ -138,54 +137,11 @@

+
{% endfor %}
- -
- - - - - - - - - - - - - +{% endblock %} diff --git a/dashboard/templates/dashboard/hmmer_hist.html b/dashboard/templates/dashboard/hmmer_hist.html index 32b244dc8..f2745e519 100644 --- a/dashboard/templates/dashboard/hmmer_hist.html +++ b/dashboard/templates/dashboard/hmmer_hist.html @@ -1,53 +1,55 @@ - - - - HMMER History - - - - - - - - - - - - +{% extends "app/layout.html" %} +{% load staticfiles %} +{% load pipeline %} +{% load jsonify %} +{% block head-scripts %} - - + - - - -
- - - -
+{% endblock %} + +{% block scripts %} + + + + + +{% endblock %} + + +{% block content %}
@@ -86,8 +88,8 @@

@@ -98,13 +100,10 @@

- + -
-
- -
+
{% for search in search_list %}
@@ -132,7 +131,7 @@

- +


@@ -140,54 +139,11 @@

+
{% endfor %}
- -
- - - - - - - - - - - - - +{% endblock %} diff --git a/dashboard/templates/dashboard/index.html b/dashboard/templates/dashboard/index.html index e5f168861..b12a9c789 100644 --- a/dashboard/templates/dashboard/index.html +++ b/dashboard/templates/dashboard/index.html @@ -1,55 +1,55 @@ +{% extends "app/layout.html" %} {% load staticfiles %} {% load pipeline %} - - - - I5K Dashboard - - - - - - - - - - - - +{% load jsonify %} +{% block head-scripts %} - - + - - - -
- - - -
+{% endblock %} + +{% block scripts %} + + + + + +{% endblock %} + + +{% block content %}
@@ -88,12 +88,12 @@

- + @@ -103,56 +103,8 @@

-
-
- -

Dashboard

-
-
- - - - - - - - - - +{% endblock %} From 72e0eccb74d8cf7365ab2396f71854f174cd8edd Mon Sep 17 00:00:00 2001 From: ifish Date: Tue, 30 Jan 2018 10:49:58 -0500 Subject: [PATCH 18/24] fix issues in PR --- dashboard/templates/dashboard/blast_hist.html | 9 ++------- dashboard/templates/dashboard/clustal_hist.html | 9 ++------- dashboard/templates/dashboard/hmmer_hist.html | 9 ++------- 3 files changed, 6 insertions(+), 21 deletions(-) diff --git a/dashboard/templates/dashboard/blast_hist.html b/dashboard/templates/dashboard/blast_hist.html index aa4adbd78..e080c43fa 100644 --- a/dashboard/templates/dashboard/blast_hist.html +++ b/dashboard/templates/dashboard/blast_hist.html @@ -6,7 +6,7 @@ {% block head-scripts %} - + {% endblock %} @@ -17,11 +17,6 @@

Search Tag: {{ search.search_tag }}