From 5a40dbe074a307538769ae873e446323d6a75f39 Mon Sep 17 00:00:00 2001 From: Ciro Scognamiglio <ciro.scognamiglio@cslash.net> Date: Thu, 27 Mar 2014 11:51:08 +0100 Subject: [PATCH] changed template paths in settings (takes into account the theme) --- myslice/settings.py | 9 + {portal => myslice}/theme.py | 0 portal/about.py | 2 +- portal/accountview.py | 2 +- portal/actions.py | 2 +- portal/contactview.py | 2 +- portal/dashboardview.py | 2 +- portal/django_passresetview.py | 2 +- portal/documentationview.py | 2 +- portal/homeview.py | 2 +- portal/institution.py | 2 +- portal/joinview.py | 2 +- portal/manageuserview.py | 2 +- portal/platformsview.py | 2 +- portal/platformview.py | 2 +- portal/registrationview.py | 2 +- portal/resourceview.py | 2 +- portal/slicerequestview.py | 2 +- portal/sliceresourceview.py | 2 +- portal/slicetabexperiment.py | 2 +- portal/slicetabinfo.py | 2 +- portal/slicetabtestbeds.py | 2 +- portal/slicetabusers.py | 2 +- portal/sliceview.py | 2 +- portal/sliceviewold.py | 2 +- portal/static/css/fantaastic.css | 480 ++++++++++++++++++ portal/static/img/fantaastic-s.png | Bin 0 -> 14113 bytes portal/static/img/ict_logo-s.png | Bin 0 -> 6864 bytes portal/static/js/myslice.js | 64 +-- portal/supportview.py | 2 +- ...dget-topmenu.html => _widget-topmenu.html} | 0 {ui => portal}/templates/base.html | 4 +- .../fantaastic/fantaastic_widget-topmenu.html | 76 +++ ...menu.html => fed4fire_widget-topmenu.html} | 0 portal/templates/home-view.html | 99 +++- portal/templates/institution-tab-info.html | 0 .../onelab/onelab_widget-topmenu.html | 76 +++ portal/templates/slice-resource-view.html | 3 +- portal/templates/slice-tab-info.html | 2 +- portal/templates/slice-view.html | 3 +- portal/templatetags/__init__.py | 0 portal/templatetags/portal_filters.py | 40 ++ portal/usersview.py | 2 +- portal/validationview.py | 2 +- 44 files changed, 820 insertions(+), 88 deletions(-) rename {portal => myslice}/theme.py (100%) create mode 100644 portal/static/css/fantaastic.css create mode 100644 portal/static/img/fantaastic-s.png create mode 100644 portal/static/img/ict_logo-s.png rename portal/templates/{onelab/onelab__widget-topmenu.html => _widget-topmenu.html} (100%) rename {ui => portal}/templates/base.html (93%) create mode 100644 portal/templates/fantaastic/fantaastic_widget-topmenu.html rename portal/templates/fed4fire/{fed4fire__widget-topmenu.html => fed4fire_widget-topmenu.html} (100%) create mode 100644 portal/templates/institution-tab-info.html create mode 100644 portal/templates/onelab/onelab_widget-topmenu.html create mode 100644 portal/templatetags/__init__.py create mode 100644 portal/templatetags/portal_filters.py diff --git a/myslice/settings.py b/myslice/settings.py index 21c28978..ccf94ddb 100644 --- a/myslice/settings.py +++ b/myslice/settings.py @@ -2,6 +2,7 @@ import os.path + DEBUG = True TEMPLATE_DEBUG = DEBUG @@ -19,6 +20,12 @@ except: import traceback traceback.print_exc() +# themes +from myslice.configengine import ConfigEngine +configEngine = ConfigEngine() +if configEngine.myslice.theme : + theme = configEngine.myslice.theme + # find out HTTPROOT, which is different from ROOT # when deployed from a package # this code is run by collectstatic too, so we cannot @@ -186,6 +193,8 @@ TEMPLATE_DIRS = ( # Put strings here, like "/home/html/django_templates" or "C:/www/django/templates". # Always use forward slashes, even on Windows. # Don't forget to use absolute paths, not relative paths. + os.path.join(HTTPROOT,"portal/templates", theme), + os.path.join(HTTPROOT,"portal/templates"), os.path.join(HTTPROOT,"templates"), ) diff --git a/portal/theme.py b/myslice/theme.py similarity index 100% rename from portal/theme.py rename to myslice/theme.py diff --git a/portal/about.py b/portal/about.py index 49a890bb..5080601f 100644 --- a/portal/about.py +++ b/portal/about.py @@ -12,7 +12,7 @@ from manifoldapi.manifoldresult import ManifoldResult from ui.topmenu import topmenu_items, the_user from myslice.configengine import ConfigEngine -from theme import ThemeView +from myslice.theme import ThemeView class AboutView (FreeAccessView, ThemeView): template_name = 'about.html' diff --git a/portal/accountview.py b/portal/accountview.py index 9b0c4666..8243e392 100644 --- a/portal/accountview.py +++ b/portal/accountview.py @@ -11,7 +11,7 @@ from django.http import HttpResponse, HttpResponseRedirec from django.contrib import messages from django.contrib.auth.decorators import login_required -from theme import ThemeView +from myslice.theme import ThemeView # import json, os, re, itertools diff --git a/portal/actions.py b/portal/actions.py index 399cae64..c612b096 100644 --- a/portal/actions.py +++ b/portal/actions.py @@ -8,7 +8,7 @@ from django.contrib.auth.models import User from django.template.loader import render_to_string from django.core.mail import EmailMultiAlternatives -from theme import ThemeView +from myslice.theme import ThemeView theme = ThemeView() diff --git a/portal/contactview.py b/portal/contactview.py index 13450dfd..b89aa753 100644 --- a/portal/contactview.py +++ b/portal/contactview.py @@ -7,7 +7,7 @@ from ui.topmenu import topmenu_items, the_user from portal.forms import ContactForm -from theme import ThemeView +from myslice.theme import ThemeView # splitting the 2 functions done here # GET is for displaying the empty form diff --git a/portal/dashboardview.py b/portal/dashboardview.py index 2b0ab828..06f02f83 100644 --- a/portal/dashboardview.py +++ b/portal/dashboardview.py @@ -11,7 +11,7 @@ from unfold.loginrequired import LoginRequiredAutoLogoutView from ui.topmenu import topmenu_items_live, the_user -from theme import ThemeView +from myslice.theme import ThemeView #This view requires login class DashboardView (LoginRequiredAutoLogoutView, ThemeView): diff --git a/portal/django_passresetview.py b/portal/django_passresetview.py index 7d7f52e9..a0018b0f 100644 --- a/portal/django_passresetview.py +++ b/portal/django_passresetview.py @@ -87,7 +87,7 @@ from portal.actions import manifold_update_user from portal.forms import PassResetForm from portal.actions import manifold_update_user -from theme import ThemeView +from myslice.theme import ThemeView # 4 views for password reset: # - password_reset sends the mail diff --git a/portal/documentationview.py b/portal/documentationview.py index 6a75a629..ccd42fa1 100644 --- a/portal/documentationview.py +++ b/portal/documentationview.py @@ -12,7 +12,7 @@ from manifoldapi.manifoldresult import ManifoldResult from ui.topmenu import topmenu_items, the_user from myslice.configengine import ConfigEngine -from theme import ThemeView +from myslice.theme import ThemeView class DocumentationView (FreeAccessView, ThemeView): template_name = 'documentationview.html' diff --git a/portal/homeview.py b/portal/homeview.py index 14487c96..7c47d99c 100644 --- a/portal/homeview.py +++ b/portal/homeview.py @@ -12,7 +12,7 @@ from manifoldapi.manifoldresult import ManifoldResult from ui.topmenu import topmenu_items, the_user from myslice.configengine import ConfigEngine -from theme import ThemeView +from myslice.theme import ThemeView class HomeView (FreeAccessView, ThemeView): template_name = 'home-view.html' diff --git a/portal/institution.py b/portal/institution.py index 6c55517d..4ee9016b 100644 --- a/portal/institution.py +++ b/portal/institution.py @@ -13,7 +13,7 @@ from manifoldapi.manifoldresult import ManifoldResult from ui.topmenu import topmenu_items, the_user from myslice.configengine import ConfigEngine -from theme import ThemeView +from myslice.theme import ThemeView import json class InstitutionView (FreeAccessView, ThemeView): diff --git a/portal/joinview.py b/portal/joinview.py index abe73f39..a2b8b7d9 100644 --- a/portal/joinview.py +++ b/portal/joinview.py @@ -19,7 +19,7 @@ from manifold.core.query import Query from portal.models import PendingUser,PendingAuthority from portal.actions import authority_get_pi_emails, manifold_add_user,manifold_add_account -from theme import ThemeView +from myslice.theme import ThemeView # since we inherit from FreeAccessView we cannot redefine 'dispatch' # so let's override 'get' and 'post' instead diff --git a/portal/manageuserview.py b/portal/manageuserview.py index 369d6e95..7687d341 100644 --- a/portal/manageuserview.py +++ b/portal/manageuserview.py @@ -10,7 +10,7 @@ from ui.topmenu import topmenu_items_live, the_user from django.http import HttpResponse, HttpResponseRedirect from django.contrib import messages from django.contrib.auth.decorators import login_required -from theme import ThemeView +from myslice.theme import ThemeView # import json, os, re, itertools diff --git a/portal/platformsview.py b/portal/platformsview.py index eef773a3..c31cd174 100644 --- a/portal/platformsview.py +++ b/portal/platformsview.py @@ -5,7 +5,7 @@ from unfold.loginrequired import FreeAccessView from ui.topmenu import topmenu_items_live, the_user from plugins.querytable import QueryTable -from theme import ThemeView +from myslice.theme import ThemeView # View for platforms class PlatformsView(FreeAccessView, ThemeView): diff --git a/portal/platformview.py b/portal/platformview.py index d70c99b5..b0fc3ec7 100644 --- a/portal/platformview.py +++ b/portal/platformview.py @@ -15,7 +15,7 @@ from ui.topmenu import topmenu_items_live, the_user from plugins.querytable import QueryTable from myslice.configengine import ConfigEngine -from theme import ThemeView +from myslice.theme import ThemeView # View for 1 platform and its details class PlatformView(FreeAccessView, ThemeView): diff --git a/portal/registrationview.py b/portal/registrationview.py index 9f5f39f4..396d357b 100644 --- a/portal/registrationview.py +++ b/portal/registrationview.py @@ -17,7 +17,7 @@ from manifold.core.query import Query from portal.models import PendingUser from portal.actions import create_pending_user -from theme import ThemeView +from myslice.theme import ThemeView # since we inherit from FreeAccessView we cannot redefine 'dispatch' # so let's override 'get' and 'post' instead diff --git a/portal/resourceview.py b/portal/resourceview.py index a407725a..d670645b 100644 --- a/portal/resourceview.py +++ b/portal/resourceview.py @@ -10,7 +10,7 @@ from plugins.lists.simplelist import SimpleList from plugins.slicestat import SliceStat from myslice.configengine import ConfigEngine -from theme import ThemeView +from myslice.theme import ThemeView # View for 1 platform and its details class ResourceView(FreeAccessView, ThemeView): diff --git a/portal/slicerequestview.py b/portal/slicerequestview.py index dfa46585..fc093d12 100644 --- a/portal/slicerequestview.py +++ b/portal/slicerequestview.py @@ -10,7 +10,7 @@ from portal.forms import SliceRequestForm from unfold.loginrequired import LoginRequiredAutoLogoutView from ui.topmenu import topmenu_items_live, the_user -from theme import ThemeView +from myslice.theme import ThemeView import json, time diff --git a/portal/sliceresourceview.py b/portal/sliceresourceview.py index afd95312..bdffa3fe 100644 --- a/portal/sliceresourceview.py +++ b/portal/sliceresourceview.py @@ -18,7 +18,7 @@ from plugins.googlemap import GoogleMap from plugins.queryupdater import QueryUpdater from plugins.testbeds import TestbedsPlugin -from theme import ThemeView +from myslice.theme import ThemeView class SliceResourceView (LoginRequiredView, ThemeView): template_name = "slice-resource-view.html" diff --git a/portal/slicetabexperiment.py b/portal/slicetabexperiment.py index cd1d6adb..cca8afbd 100644 --- a/portal/slicetabexperiment.py +++ b/portal/slicetabexperiment.py @@ -12,7 +12,7 @@ from manifoldapi.manifoldresult import ManifoldResult from ui.topmenu import topmenu_items, the_user from myslice.configengine import ConfigEngine -from theme import ThemeView +from myslice.theme import ThemeView class ExperimentView (FreeAccessView, ThemeView): template_name = 'slice-tab-experiment.html' diff --git a/portal/slicetabinfo.py b/portal/slicetabinfo.py index 7e7b78ea..fc7fa291 100644 --- a/portal/slicetabinfo.py +++ b/portal/slicetabinfo.py @@ -14,7 +14,7 @@ from unfold.page import Page from manifold.core.query import Query, AnalyzedQuery from manifoldapi.manifoldapi import execute_query -from theme import ThemeView +from myslice.theme import ThemeView class SliceInfoView (LoginRequiredView, ThemeView): template_name = "slice-tab-info.html" diff --git a/portal/slicetabtestbeds.py b/portal/slicetabtestbeds.py index a93f6787..abd6ce65 100644 --- a/portal/slicetabtestbeds.py +++ b/portal/slicetabtestbeds.py @@ -3,7 +3,7 @@ from django.shortcuts import render_to_response from unfold.loginrequired import LoginRequiredView -from theme import ThemeView +from myslice.theme import ThemeView class SliceTabTestbeds (LoginRequiredView, ThemeView): template_name = "slice-tab-testbeds.html" diff --git a/portal/slicetabusers.py b/portal/slicetabusers.py index e1a1742f..861b0cbe 100644 --- a/portal/slicetabusers.py +++ b/portal/slicetabusers.py @@ -14,7 +14,7 @@ from unfold.page import Page from manifold.core.query import Query, AnalyzedQuery from manifoldapi.manifoldapi import execute_query -from theme import ThemeView +from myslice.theme import ThemeView class SliceUserView (LoginRequiredView, ThemeView): template_name = "slice-tab-users-view.html" diff --git a/portal/sliceview.py b/portal/sliceview.py index 008222c1..10cab7cd 100644 --- a/portal/sliceview.py +++ b/portal/sliceview.py @@ -14,7 +14,7 @@ from unfold.page import Page from manifold.core.query import Query, AnalyzedQuery from manifoldapi.manifoldapi import execute_query -from theme import ThemeView +from myslice.theme import ThemeView class SliceView (LoginRequiredView, ThemeView): template_name = "slice-view.html" diff --git a/portal/sliceviewold.py b/portal/sliceviewold.py index e7991537..7cf80f93 100644 --- a/portal/sliceviewold.py +++ b/portal/sliceviewold.py @@ -31,7 +31,7 @@ from plugins.slicestat import SliceStat from myslice.configengine import ConfigEngine -from theme import ThemeView +from myslice.theme import ThemeView tmp_default_slice='ple.upmc.myslicedemo' diff --git a/portal/static/css/fantaastic.css b/portal/static/css/fantaastic.css new file mode 100644 index 00000000..07a77eb6 --- /dev/null +++ b/portal/static/css/fantaastic.css @@ -0,0 +1,480 @@ +html { height: 100% } + +body { + background-color:white; + color:black; + margin:0; + padding:0; + height: 100%; +} +a, a:active, a:focus { + outline: 0; +} + +h1 { + border-bottom:1px solid #DDDDDD; + padding:0 0 0 0; + margin:0 0 0 0; + font-size:18pt; +} +h1 img { + vertical-align:middle; + margin-bottom:6px; +} +h2 { + font-size:14pt; + color:#333333; +} +h3 { + font-size:13pt; + color:#201E62; +} + +div.wrapper { + width:980px; + margin:0 auto; + position:relative; +} +div.container { + width:980px; + margin:25px auto; +} +div.wide { + margin:25px auto; + padding:0 25px; +} + +span.label { + font-size:11pt; + color:gray; + font-weight:normal; + padding:0; +} +/***** Notifications *****/ +.warning { + border: 1px solid red; + margin: 20px 60px; + padding: 10px 20px; + color: red; + background-color: #f2dbdb; + text-align: center; +} +/* HEADER */ +div#header { + height:100px; + background-color:white; +} + +div#secondary { + +} + +div#secondary ul { + position:absolute; + top:20px; + right:0; +} + +div#secondary li { + font-size:10pt; + float:left; + list-style:none; + margin-right:30px; +} +div#secondary li a { + color:black; +} +div#secondary li a:hover { + color:#270A5A; + text-decoration:none; +} +div#secondary li:last-child { + margin-right:0; +} + +div#navigation { + background-color:black; + width:100%; + height:40px; +} +div#navigation div.wrapper { + text-align:center; +} +div#navigation ul { + margin:0; + padding:0; + display: inline-block; + list-style-type: none; + white-space: nowrap; +} + +div#navigation li { + color:white; + font-family:helvetica, sans-serif; + font-size:10pt ; + font-weight:normal; + line-height:0.8em; + letter-spacing:0.6pt; + list-style:none; + float:left; + padding:0; + margin:15px 50px 0 0; +} +div#navigation li a { + color:white; +} +div#navigation li a:hover { + text-decoration:none; + color:#B8B2FF; +} +div#navigation li:last-child { + margin-right:0; +} + +div#navigation li.active { + padding:5px; + padding-top: 15px; + min-height: 40px; + margin-top: 0px; + background-color:gray; + color:#FF0000; +} +div#navigation li.slices { + position:relative; + cursor:pointer; +} +div#navigation .dropdown-menu { + color:white; + padding:0 15px 15px 15px; + margin-top:5px; + margin-left:-16px; + background-color:black; +} +div#navigation .dropdown-menu a { + color:white; +} + +div#menu-slice-list{ + display:none; + position:absolute; + background-color:black; + padding:15px; + left:-15px; + z-index:10; +} + +div#navigation .dropdown-menu li:first-child { + border-bottom:1px solid white; + padding-bottom:5px; + +} +/* HOME DASHBOARD */ +div#home-dashboard { + color:black; + margin:0 auto 25px auto; +} +div#home-dashboard table { + margin:25px; + width:100%; +} +div#home-dashboard table td { + text-align:center; + padding:15px 0; + width:33%; +} +div#home-dashboard table tr:first-child td { + font-size:12pt; + font-weight:bold; + color:#270A5A; +} +div#home-dashboard table tr:last-child td { + vertical-align:top; + padding:25px 0; +} +div#home-dashboard table tr:last-child td.logged-in { + border-right:1px solid #DDDDDD; + padding:25px; +} +div#home-dashboard table tr:last-child td.support { + border-left:1px solid #DDDDDD; + padding:25px; +} +div#home-dashboard table tr:last-child td:first-child { +} +div#home-dashboard table tr:last-child td:last-child { + border-right:0; +} +div#home-dashboard table tr:last-child td.logged-in div { + text-align:left; + padding:25px 0; +} +div#home-dashboard table tr:last-child td.support div { + text-align:left; + padding:25px 0; +} +div#home-dashboard div.login-widget { + padding:20px; +} +div#home-dashboard table td.support { +} +div#home-dashboard table td.support a { +} +div#home-dashboard table td.support a:hover { + text-decoration:none; +} + +div#home-dashboard div#manager { + display:none; +} + +div#home-dashboard div#home-slice-list { + margin:25px 0; + padding:0 25px; + text-align:left; +} +div#home-dashboard div#home-slice-list ul { + list-style: none; + padding:0; + margin:0; +} +div#home-dashboard div#home-slice-list li { + +} + +.login-submit { + vertical-align:middle; + padding:0; +} +.lost-password { + font-size:10pt; + color:#CCCCCC; + text-align:right; + padding:0px; +} +.lost-password a { +} +.login-signup { + border-top:1px solid #CCCCCC; + text-align:center; + margin-top:15px; + padding:5px 0 0 0; +} +/**/ + +/**/ +/* WELL */ +div.well { +} +/**/ +/* BUTTON */ +.btn.btn-default { + font-weight: bold; +} + +.btn.btn-default:hover { + font-weight: bold; +} +/**/ +/* TABLE */ +table.table { + margin:0; +} +table.table thead { + padding:0; +} +table.table tbody { + padding:0; +} +table.table tr { + padding:0; +} +table.table td { + padding:0; +} +/* INSTITUTION */ +div#institution { + color:black; +} +.form-hint { + font-size:11pt; + font-style:italic; + color:gray; +} + + +.form-hint { + font-size:11pt; + font-style:italic; + color:gray; +} + + + +/* TICKET REQUEST */ +div#ticket-request { + color:black; +} +.form-hint { + font-size:11pt; + font-style:italic; + color:gray; +} +div#ticket-request p { + margin:20px 0; +} + +ul.nav-tabs {} +ul.nav-tabs ul {} +ul.nav-tabs li {} + +ul.nav-section li a { + border-bottom:0; +} +ul.nav-section li:first-child { + padding:0; +} +ul.nav-section li:first-child a { + font-weight:bold; + padding:6px 15px 4px 15px; +} +ul.nav-section li:first-child.active a { + padding:6px 15px 3px 15px; +} +ul.nav-section li:first-child img { + margin:0 4px 1px 0; + padding:0; +} + +ul.nav-resources { + margin:15px 0; +} +ul.nav-resources a { + padding: 4px 10px 5px 10px; +} + + +/* SLICE VIEW */ + + +div#slice-view { + margin:0; +} +div.list-group-item { + border:0; + background-color:white; + font-weight:bold; + padding-left:0; +} +a.list-group-item { + border:0; + background-color:white; + padding:3px 0 3px 10px; + border-left:2pt white solid; +} +a.list-group-item.active, a.list-group-item.active:hover { + font-weight: bold; + color:black; + background-color:transparent; + border-left:2pt blue solid; +} +a.list-group-item.active:hover { + background-color:#dddddd; +} +a.list-group-item:hover { + border-left:2pt blue solid; +} +a.list-group-item p.list-group-item-text { + font-size:9pt; + font-style:italic; + font-weight: normal; + color: black !important; +} + +div#slice-info { + margin-top:25px; +} +div#slice-info table { + width:100%; + margin:0 auto; +} +div#slice-info table td:first-child { + text-align:right; + font-weight:bold; + padding-right:15px; +} +div#slice-info td { + padding:5px; +} + +/* SLICE VIEW sections */ +.slice-sections, .slice-pending { + margin:0; + padding:0; +} +.slice-sections ul, .slice-pending ul { + margin:0; + padding:0; +} +.slice-pending ul { + width:400px; + margin:0 auto 15px auto; +} +.slice-sections li { + text-align:left; + margin:0; + padding:0; +} +.slice-pending li { + padding-right:15px; +} +.slice-sections li a, .slice-pending li a { + font-size:14px; + color:black; + padding:0; +} +.slice-sections li.active a, .slice-pending li.active a { + color:#201E62; + background-color:#EFEFEF; + text-decoration:underline; + padding:0; +} +.slice-sections ul.nav-pills li a:hover, .slice-pending ul.nav-pills li a:hover { + text-decoration:underline; + background-color:#EFEFEF; + color:black; +} +.slice-sections ul.nav-pills li.active, .slice-pending ul.nav-pills li.active { + +} +.slice-sections li:first-child, .slice-sections li:first-child a { + color:#201E62; + font-weight:bold; +} +.slice-experiment { + text-align:right; + padding:0; +} +.slice-experiment button { + margin:3px 0 0 0; + background-color:#CC4125; + color:white; +} + +.slice-pending { +} +.slice-pending button { + font-size:9pt; + margin:-2px 0 0 0; + padding:3px 5px; +} +.slice-pending button.apply { +} +.slice-pending button.clear { +} +tr.active, tr.active td { + background-color:#FFFFCC !important; +} +div.dataTables_filter label{ + float:left; + width:400px; +} diff --git a/portal/static/img/fantaastic-s.png b/portal/static/img/fantaastic-s.png new file mode 100644 index 0000000000000000000000000000000000000000..ea33949ddbb1f82183d87ef41bcfd77e91705742 GIT binary patch literal 14113 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 ZQnAu<q2sK(^4EXIG7<{nwW3Br{|DU^YcBu* literal 0 HcmV?d00001 diff --git a/portal/static/img/ict_logo-s.png b/portal/static/img/ict_logo-s.png new file mode 100644 index 0000000000000000000000000000000000000000..78183ee307c0660dca96205b4233bba4ae30a38e GIT binary patch literal 6864 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 literal 0 HcmV?d00001 diff --git a/portal/static/js/myslice.js b/portal/static/js/myslice.js index 7038e53e..c7c32d20 100644 --- a/portal/static/js/myslice.js +++ b/portal/static/js/myslice.js @@ -6,24 +6,6 @@ function list() { this.elements = []; } -list.prototype.save = function() { - for (var prop in this) { - if (typeof this[prop] != 'function') { - console.log("prop: " + prop); - } else { - console.log("func: " + prop); - } - } - //localStorage.setItem(name, JSON.stringify(value)); -}; - -list.prototype.load = function(name) { - this.pending = JSON.parse(localStorage.getItem(name)); - if (!this.pending) { - this.pending = []; - } -}; - list.prototype.add = function(element) { if (!this.has(element)) { this.elements.push(element); @@ -60,14 +42,14 @@ function resources() { }; }; -function users() { +function leases() { this.pending = { toremove: new list(), toadd: new list(), }; }; -function leases() { +function users() { this.pending = { toremove: new list(), toadd: new list(), @@ -83,27 +65,19 @@ function slice(name) { this.users = new users(); this.leases = new leases(); -}; -slice.prototype.pending = function() { - -}; -slice.prototype.reserve = function() { - -}; -slice.prototype.unreserve = function() { - }; + /* * User */ -function user(u) { - this.u = u; - this.testbeds = {}; - this.slices = {}; +function user(user) { + this.user = user; + this.testbeds = new list(); + this.slices = new list(); - for (i = 0; i < this.u.slices.length; i++) { - this.slices[this.u.slices[i]] = new slice(this.u.slices[i]); + for (i = 0; i < this.user.slices.length; i++) { + this.slices[this.user.slices[i]] = new slice(this.user.slices[i]); } }; @@ -113,7 +87,7 @@ user.prototype.slice = function(name) { user.prototype.list = function() { for (s in this.slices) { - for (o in s) { + for (o in s) { if (typeof o != 'function') { console.log(o); } else { @@ -128,7 +102,21 @@ user.prototype.list = function() { */ var myslice = { user: {}, - + + user: function() { + if ($.isEmptyObject(this.user)) { + //this.login(function() { return this.user; }); + } else { + return this.user; + } + }, + + login: function(fn) { + $.post("/rest/user/",{'filters':{'user_hrn':'$user_hrn'}}, function( data ) { + myslice.user = new user(data[0]); + }); + }, + getSlices: function(name) { }, @@ -197,6 +185,8 @@ var myslice = { $(document).ready(function() { + //console.log(myslice.user().slices); + // $.post("/rest/user/",{'filters':{'user_hrn':'$user_hrn'}}, function(data) { // myslice.user = new user(data[0]); // console.log(myslice.user.slices); diff --git a/portal/supportview.py b/portal/supportview.py index bbb5b495..f42bbd87 100644 --- a/portal/supportview.py +++ b/portal/supportview.py @@ -12,7 +12,7 @@ from manifoldapi.manifoldresult import ManifoldResult from ui.topmenu import topmenu_items, the_user from myslice.configengine import ConfigEngine -from theme import ThemeView +from myslice.theme import ThemeView class SupportView (FreeAccessView, ThemeView): template_name = 'supportview.html' diff --git a/portal/templates/onelab/onelab__widget-topmenu.html b/portal/templates/_widget-topmenu.html similarity index 100% rename from portal/templates/onelab/onelab__widget-topmenu.html rename to portal/templates/_widget-topmenu.html diff --git a/ui/templates/base.html b/portal/templates/base.html similarity index 93% rename from ui/templates/base.html rename to portal/templates/base.html index 85139519..6dc48e73 100644 --- a/ui/templates/base.html +++ b/portal/templates/base.html @@ -1,3 +1,4 @@ +{% load portal_filters %} {# This is required by insert_above #}{% insert_handler %}<!DOCTYPE html> <html lang="en"><head> <title>OneLab - {{ section }}</title> @@ -8,6 +9,7 @@ <script type="text/javascript"> {# raw js code - use {% insert prelude_js %} ... {% endinsert %} #} {% container prelude_js %}</script> <script src="{{ STATIC_URL }}js/jquery.dataTables.min.js"></script> <script src="{{ STATIC_URL }}js/bootstrap.datatables.js"></script> +<script src="{{ STATIC_URL }}js/stash.min.js"></script> <script src="{{ STATIC_URL }}js/myslice.js"></script> <script src="{{ STATIC_URL }}js/myslice-ui.js"></script> <style type="text/css">{# In case we need to add raw css code #}{% container prelude_css %}</style> @@ -33,7 +35,7 @@ <body> {% block container %} {% block topmenu %} - {% include theme|add:"__widget-topmenu.html" %} + {% widget "_widget-topmenu.html" %} {% endblock topmenu %} {% include 'messages-transient.html' %} {% block base_content %} diff --git a/portal/templates/fantaastic/fantaastic_widget-topmenu.html b/portal/templates/fantaastic/fantaastic_widget-topmenu.html new file mode 100644 index 00000000..de37b04c --- /dev/null +++ b/portal/templates/fantaastic/fantaastic_widget-topmenu.html @@ -0,0 +1,76 @@ + +<div id="header"> + <div class="wrapper"> + <div class="logo"> + <a href="/"><img src="{{ STATIC_URL }}img/fantaastic-s.png" alt="FanTaaStic" /></a> + </div> + + <div id="secondary"> + <ul> + <li>News</li> + <li><a href="/portal/about">About</a></li> + <li><a target="_blank" href="http://www.onelab.eu">Public Website</a></li> + <li><a target="_blank" href="http://intranet.onelab.eu">Intranet</a></li> + </ul> + </div> + </div> + + {% if username %} + <div id="navigation"> + <div class="wrapper"> + <ul> + <li id="nav-account"><a href="/portal/account/">{{ username }}</a></li> + <li>|</li> + <li id="nav-institution" class=""><a href="/portal/institution">INSTITUTION</a></li> + <li class="slices"> + <a class="dropdown-toggle" data-toggle="dropdown" href="#"> + SLICES <span class="caret"></span> + </a> + + <div class="dropdown-menu" style="z-index:99;"> + <ul> + <li><a href="/portal/slice_request/">Request Slice</a></li> + <li><a href="/slice/ple.upmc.agent3/">ple.upmc.agent3</a></li> + <li><a href="/slice/ple.upmc.agent/">ple.upmc.agent</a></li> + <li><a href="/slice/ple.upmc.myslicedemo/">ple.upmc.myslicedemo</a></li> + <li><a href="/slice/ple.upmc.slicestat/">ple.upmc.slicestat</a></li> + <li><a href="/slice/ple.upmc.agent2/">ple.upmc.agent2</a></li> + </ul> + </div> + </li> + <li id="nav-request"><a href="/portal/validate">REQUESTS</a></li> + <li id="nav-support"><a href="/portal/support/">SUPPORT</a></li> + <li>|</li> + <li id="nav-logout" style="margin-top: 10px;"><a id="logout" style="cursor:pointer;" data-username="{{ username }}"><span class="glyphicon glyphicon-off"></span> LOGOUT</a></li> + </ul> + </div> + </div> + {% else %} + <div id="navigation"> + <div class="wrapper"></div> + </div> + {% endif %} +</div> +<script> + $(document).ready(function() { + $('li.slices').mouseenter(function() { + $('div#menu-slice-list').fadeIn(100); + }); + $('div#menu-slice-list').mouseleave(function(e) { + if (!$('li.slices').is(":hover")) { + $(this).fadeOut(100); + } + }); + // var slices = localStorage.getItem('slices'); + // if (slices.length == 0) { + // $.post("/rest/user/",{'filters':{'user_hrn':'$user_hrn'}}, function( data ) { + // var items = []; + // localStorage.setItem('slices', data[0].slice); + // }); + // } + // $.each(slices, function( key, val ) { + // items.push( "<li><a href=\"/slice/"+val.slice_hrn+"\">" + val.slice_hrn + "</a></li>" ); + // }); + // $("div#home-slice-list").html($( "<ul/>", { html: items.join( "" ) })); + }); +</script> diff --git a/portal/templates/fed4fire/fed4fire__widget-topmenu.html b/portal/templates/fed4fire/fed4fire_widget-topmenu.html similarity index 100% rename from portal/templates/fed4fire/fed4fire__widget-topmenu.html rename to portal/templates/fed4fire/fed4fire_widget-topmenu.html diff --git a/portal/templates/home-view.html b/portal/templates/home-view.html index c88902d2..453ed2fa 100644 --- a/portal/templates/home-view.html +++ b/portal/templates/home-view.html @@ -1,13 +1,13 @@ {% extends "layout.html" %} +{% load portal_filters %} {% block content %} -<link rel="stylesheet" type="text/css" href="{{STATIC_URL}}/css/registration.css" /> -<div id="home-dashboard"> +<div class="row" id="home-dashboard"> <ul class="nav nav-tabs"> - <li class="active"><a href="#">USER</a></li> - <li><a href="#">MANAGER</a></li> + <li class="active"><a class="home-tab" data-panel="user" href="#">USER</a></li> + <li><a class="home-tab" data-panel="manager" href="#">MANAGER</a></li> </ul> - <div id="user"> + <div class="home-panel" id="user"> <table> <tr> <td>ACCOUNT</td> @@ -15,49 +15,106 @@ <td>SUPPORT</td> </tr> <tr> - <td><a href="/portal/account"><img src="{{ STATIC_URL }}img/icon_user_color.png" alt="" /></a></td> - <td><img src="{{ STATIC_URL }}img/icon_slices.png" alt="" /></td> + <td><a href="/portal/account/"><img src="{{ STATIC_URL }}img/icon_user_color.png" alt="" /></a></td> + <td><a href="#"><img src="{{ STATIC_URL }}img/icon_slices.png" alt="" /></a></td> <td><a href="/portal/support"><img src="{{ STATIC_URL }}img/icon_support.png" alt="" /></a></td> </tr> <tr> - <td> - {% include '_widget-login-user.html' %} + {% if person %} + <td class="logged-in"> + <button id="logoutbtn" type="button" class="btn btn-default" data-username="{{ username }}"><span class="glyphicon glyphicon-off"></span> Logout</button> + <div> + {% if person.last_name %} + {{person.first_name}} {{person.last_name}}<br /> + {% endif %} + <span class="label">Email:</span> <a href='/portal/account/'>{{person.email}}</a> + </div> + {% else %} + <td> + {% widget '_widget-login-user.html' %} + {% endif %} </td> <td> - + {% if person %} + <button id="slicerequestbtn" type="button" class="btn btn-default"><span class="glyphicon glyphicon-plus"></span> Request Slice</button> + <div id="home-slice-list"><img src="{{ STATIC_URL }}img/loading.gif" alt="Loading Slices" /></div> + {% else %} + {% endif %} </td> <td class="support"> - <div><a href="/portal/contact">Contact</a></div> - <div><a href="">Documentation</a></div> + <button id="ticketbtn" type="button" class="btn btn-default"><span class="glyphicon glyphicon-plus"></span> Create Ticket</button> + <div> + <a href="/portal/contact">Contact</a> <br /> + <a href="/portal/support/documentation">Documentation</a> + </div> </td> </tr> </table> </div> - <div id="manager"> + <div class="home-panel" id="manager"> <table> <tr> <td>INSTITUTION</td> <td>SLICES</td> - <td>SUPPORT</td> + <td>REQUESTS</td> </tr> <tr> <td><a href="/portal/institution"><img src="{{ STATIC_URL }}img/icon_authority_color.png" alt="" /></a></td> - <td><img src="{{ STATIC_URL }}img/icon_slices.png" alt="" /></td> - <td><a href="/portal/support"><img src="{{ STATIC_URL }}img/icon_support.png" alt="" /></a></td> + <td><a href="/portal/institution#slices"><img src="{{ STATIC_URL }}img/icon_slices.png" alt="" /></a></td> + <td><a href="/portal/validate"><img src="{{ STATIC_URL }}img/icon_testbed_color.png" alt="" /></a></td> </tr> <tr> - <td> - {% include '_widget-login-manager.html' %} + {% if person %} + <td class="logged-in"> + <button id="logoutbtn" type="button" class="btn btn-default" data-username="{{ username }}"><span class="glyphicon glyphicon-off"></span> Logout</button> + {% else %} + <td> + {% widget '_widget-login-manager.html' %} + {% endif %} </td> <td> - + {% if person %} + <button id="slicerequestbtn" type="button" class="btn btn-default"><span class="glyphicon glyphicon-plus"></span> Create Slice</button> + {% endif %} </td> <td class="support"> - <div><a href="/portal/contact">Contact</a></div> - <div><a href="">Documentation</a></div> + {% if person %} + <button id="validaterequestbtn" type="button" class="btn btn-default"><span class="glyphicon glyphicon-ok"></span> Validate Requests</button> + {% endif %} </td> </tr> </table> </div> </div> +<script> + $(document).ready(function() { + $('a.home-tab').click(function() { + $('ul.nav-tabs li').removeClass('active'); + $(this).parent().addClass('active'); + $('div.home-panel').hide(); + $('div#'+$(this).data('panel')).show(); + }); + $('button#validaterequestbtn').click(function() { + window.location="/portal/validate/"; + }); + $('button#ticketbtn').click(function() { + window.location="/portal/contact/"; + }); + $('button#slicerequestbtn').click(function() { + window.location="/portal/slice_request/"; + }); + + {% if person %} + $.post("/rest/user/",{'filters':{'user_hrn':'$user_hrn'}}, function( data ) { + var items = []; + $.each( data[0].slices, function(i, val) { + items.push( "<li><a href=\"/slice/"+val+"\">" + val + "</a></li>" ); + }); + + $("div#home-slice-list").html($( "<ul/>", { html: items.join( "" ) })); + + }); + {% endif %} + }); +</script> {% endblock %} diff --git a/portal/templates/institution-tab-info.html b/portal/templates/institution-tab-info.html new file mode 100644 index 00000000..e69de29b diff --git a/portal/templates/onelab/onelab_widget-topmenu.html b/portal/templates/onelab/onelab_widget-topmenu.html new file mode 100644 index 00000000..4ed429ad --- /dev/null +++ b/portal/templates/onelab/onelab_widget-topmenu.html @@ -0,0 +1,76 @@ + +<div id="header"> + <div class="wrapper"> + <div class="logo"> + <a href="/"><img src="{{ STATIC_URL }}img/onelab-portal.png" alt="OneLab - Future Internet Testbeds" /></a> + </div> + + <div id="secondary"> + <ul> + <li>News</li> + <li><a href="/portal/about">About</a></li> + <li><a target="_blank" href="http://www.onelab.eu">Public Website</a></li> + <li><a target="_blank" href="http://intranet.onelab.eu">Intranet</a></li> + </ul> + </div> + </div> + + {% if username %} + <div id="navigation"> + <div class="wrapper"> + <ul> + <li id="nav-account"><a href="/portal/account/">{{ username }}</a></li> + <li>|</li> + <li id="nav-institution" class=""><a href="/portal/institution">INSTITUTION</a></li> + <li class="slices"> + <a class="dropdown-toggle" data-toggle="dropdown" href="#"> + SLICES <span class="caret"></span> + </a> + + <div class="dropdown-menu" style="z-index:99;"> + <ul> + <li><a href="/portal/slice_request/">Request Slice</a></li> + <li><a href="/slice/ple.upmc.agent3/">ple.upmc.agent3</a></li> + <li><a href="/slice/ple.upmc.agent/">ple.upmc.agent</a></li> + <li><a href="/slice/ple.upmc.myslicedemo/">ple.upmc.myslicedemo</a></li> + <li><a href="/slice/ple.upmc.slicestat/">ple.upmc.slicestat</a></li> + <li><a href="/slice/ple.upmc.agent2/">ple.upmc.agent2</a></li> + </ul> + </div> + </li> + <li id="nav-request"><a href="/portal/validate">REQUESTS</a></li> + <li id="nav-support"><a href="/portal/support/">SUPPORT</a></li> + <li>|</li> + <li id="nav-logout" style="margin-top: 10px;"><a id="logout" style="cursor:pointer;" data-username="{{ username }}"><span class="glyphicon glyphicon-off"></span> LOGOUT</a></li> + </ul> + </div> + </div> + {% else %} + <div id="navigation"> + <div class="wrapper"></div> + </div> + {% endif %} +</div> +<script> + $(document).ready(function() { + $('li.slices').mouseenter(function() { + $('div#menu-slice-list').fadeIn(100); + }); + $('div#menu-slice-list').mouseleave(function(e) { + if (!$('li.slices').is(":hover")) { + $(this).fadeOut(100); + } + }); + // var slices = localStorage.getItem('slices'); + // if (slices.length == 0) { + // $.post("/rest/user/",{'filters':{'user_hrn':'$user_hrn'}}, function( data ) { + // var items = []; + // localStorage.setItem('slices', data[0].slice); + // }); + // } + // $.each(slices, function( key, val ) { + // items.push( "<li><a href=\"/slice/"+val.slice_hrn+"\">" + val.slice_hrn + "</a></li>" ); + // }); + // $("div#home-slice-list").html($( "<ul/>", { html: items.join( "" ) })); + }); +</script> diff --git a/portal/templates/slice-resource-view.html b/portal/templates/slice-resource-view.html index 1c00cb8a..69f8bc14 100644 --- a/portal/templates/slice-resource-view.html +++ b/portal/templates/slice-resource-view.html @@ -1,4 +1,5 @@ {% extends "layout_wide.html" %} +{% load portal_filters %} {% block head %} <!-- <script type="text/javascript" src="https://maps.googleapis.com/maps/api/js?key=AIzaSyC1RUj824JAiHRVqgc2CSIg4CpKHhh84Lw&sensor=false"></script> --> @@ -24,7 +25,7 @@ </div> <div class="col-md-10" style="height:100%;"> <div class="row"> - {% include theme|add:"_widget-slice-sections.html" %} + {% widget '_widget-slice-sections.html' %} </div> <!-- <div class="row slice-pending"> <ul class="nav nav-pills"> diff --git a/portal/templates/slice-tab-info.html b/portal/templates/slice-tab-info.html index 747f3a13..bd10ac38 100644 --- a/portal/templates/slice-tab-info.html +++ b/portal/templates/slice-tab-info.html @@ -34,7 +34,7 @@ slice_row += "<tr><td>users:</td><td>"+user_length+"</td></tr>"; slice_row += "<tr><td>resources:</td><td>"+nodes_length+"</td></tr>"; slice_row += "<tr><td>created:</td><td>"+val.created+"</td></tr>"; - slice_row += "<tr><td>last update:</td><td>"+val.last_updated+"</td></tr>"; + slice_row += "<tr><td>last update:</td><td>"+val.slice_last_updated+"</td></tr>"; slice_row += "<tr><td>expires:</td><td>"+val.slice_expires+"</td></tr>"; table_slices.push(slice_row); }); diff --git a/portal/templates/slice-view.html b/portal/templates/slice-view.html index cf9ee7d8..d9ca0507 100644 --- a/portal/templates/slice-view.html +++ b/portal/templates/slice-view.html @@ -1,4 +1,5 @@ {% extends "layout_wide.html" %} +{% load portal_filters %} {% block head %} @@ -9,7 +10,7 @@ <div class="container"> <div class="row"> <div class="col-md-12"> - {% include theme|add:"_widget-slice-sections.html" %} + {% widget "_widget-slice-sections.html" %} </div> </div> </div> diff --git a/portal/templatetags/__init__.py b/portal/templatetags/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/portal/templatetags/portal_filters.py b/portal/templatetags/portal_filters.py new file mode 100644 index 00000000..9bd0175a --- /dev/null +++ b/portal/templatetags/portal_filters.py @@ -0,0 +1,40 @@ +from django import template +from django.template.loader_tags import do_include +from myslice.settings import theme + +register = template.Library() + +class IncludeNode(template.Node): + + def __init__(self, template_name): + if theme : + self.theme_template_name = "%s%s" % (theme, template_name) + self.template_name = template_name + + def render(self, context): + try: + # Loading the template and rendering it + included_template = template.loader.get_template(self.theme_template_name).render(context) + except template.TemplateDoesNotExist: + # template theme does not exists, try the generic one + try: + # Loading the template and rendering it + included_template = template.loader.get_template(self.template_name).render(context) + except template.TemplateDoesNotExist: + included_template = '' + + return included_template + +@register.tag +def widget(parser, token): + """Usage: {% widget "widget.html" %} + + This will fail silently if the template doesn't exist. If it does, it will + be rendered with the current context.""" + try: + tag_name, template_name = token.split_contents() + except ValueError: + raise template.TemplateSyntaxError, \ + "%r tag requires a single argument" % token.contents.split()[0] + + return IncludeNode(template_name[1:-1]) \ No newline at end of file diff --git a/portal/usersview.py b/portal/usersview.py index e8b7b684..5b4e2eef 100644 --- a/portal/usersview.py +++ b/portal/usersview.py @@ -10,7 +10,7 @@ from unfold.page import Page from manifoldapi.manifoldapi import execute_admin_query from unfold.loginrequired import LoginRequiredAutoLogoutView -from theme import ThemeView +from myslice.theme import ThemeView import json class UsersView (LoginRequiredAutoLogoutView, ThemeView): diff --git a/portal/validationview.py b/portal/validationview.py index e0f4ab1b..9ecd9627 100644 --- a/portal/validationview.py +++ b/portal/validationview.py @@ -44,7 +44,7 @@ from portal.actions import get_requests from manifoldapi.manifoldapi import execute_query from manifold.core.query import Query from unfold.page import Page -from theme import ThemeView +from myslice.theme import ThemeView class ValidatePendingView(FreeAccessView, ThemeView): template_name = "validate_pending.html" -- 2.47.0