Commit b0fd61ef by Bach Dániel

Merge branch 'feature-pipeline' into 'master'

Feature pipeline

👷 @kviktor

🚧 https://github.com/cyberdelia/django-pipeline/issues/313

See merge request !227
parents a8162edf 6d44029c
......@@ -35,9 +35,12 @@ circle/*.key
circle/*.pem
# collected static files:
circle/static
circle/static_collected
circle/bower_components
# jsi18n files
jsi18n
scripts.rc
# less
*.css
{
"name": "circle",
"version": "0.0.0",
"license": "GPL",
"private": true,
"ignore": [
"**/.*",
"node_modules",
"bower_components",
"test",
"tests"
],
"dependencies": {
"bootstrap": "~3.2.0",
"fontawesome": "~4.2.0",
"jquery": "~2.1.1",
"no-vnc": "*",
"jquery-knob": "~1.2.9",
"jquery-simple-slider": "https://github.com/BME-IK/jquery-simple-slider.git",
"bootbox": "~4.3.0",
"intro.js": "0.9.0"
}
}
......@@ -160,10 +160,88 @@ STATICFILES_FINDERS = (
'django.contrib.staticfiles.finders.AppDirectoriesFinder',
)
########## END STATIC FILE CONFIGURATION
STATICFILES_DIRS = [normpath(join(SITE_ROOT, 'bower_components'))]
p = normpath(join(SITE_ROOT, '../../site-circle/static'))
if exists(p):
STATICFILES_DIRS = (p, )
STATICFILES_DIRS.append(p)
STATICFILES_STORAGE = 'pipeline.storage.PipelineCachedStorage'
PIPELINE_COMPILERS = (
'pipeline.compilers.less.LessCompiler',
)
PIPELINE_CSS_COMPRESSOR = 'pipeline.compressors.yuglify.YuglifyCompressor'
PIPELINE_JS_COMPRESSOR = 'pipeline.compressors.slimit.SlimItCompressor'
PIPELINE_DISABLE_WRAPPER = True
PIPELINE_LESS_ARGUMENTS = u'--include-path={}'.format(':'.join(STATICFILES_DIRS))
PIPELINE_CSS = {
"all": {"source_filenames": (
"compile_bootstrap.less",
"bootstrap/dist/css/bootstrap-theme.css",
"fontawesome/css/font-awesome.css",
"jquery-simple-slider/css/simple-slider.css",
"intro.js/introjs.css",
"template.less",
"dashboard/dashboard.less",
"network/network.less",
"autocomplete_light/style.css",
),
"output_filename": "all.css",
}
}
PIPELINE_JS = {
"all": {"source_filenames": (
# "jquery/dist/jquery.js", # included separately
"bootbox/bootbox.js",
"bootstrap/dist/js/bootstrap.js",
"intro.js/intro.js",
"jquery-knob/dist/jquery.knob.min.js",
"jquery-simple-slider/js/simple-slider.js",
"dashboard/dashboard.js",
"dashboard/group-details.js",
"dashboard/group-list.js",
"dashboard/js/stupidtable.min.js", # no bower file
"dashboard/node-create.js",
"dashboard/node-details.js",
"dashboard/node-list.js",
"dashboard/profile.js",
"dashboard/store.js",
"dashboard/template-list.js",
"dashboard/vm-common.js",
"dashboard/vm-create.js",
"dashboard/vm-list.js",
"js/host.js",
"js/network.js",
"js/switch-port.js",
"autocomplete_light/autocomplete.js",
"autocomplete_light/widget.js",
"autocomplete_light/addanother.js",
"autocomplete_light/text_widget.js",
"autocomplete_light/remote.js",
),
"output_filename": "all.js",
},
"vm-detail": {"source_filenames": (
"dashboard/vm-details.js",
"no-vnc/include/util.js",
"no-vnc/include/webutil.js",
"no-vnc/include/base64.js",
"no-vnc/include/websock.js",
"no-vnc/include/des.js",
"no-vnc/include/keysym.js",
"no-vnc/include/keysymdef.js",
"no-vnc/include/keyboard.js",
"no-vnc/include/input.js",
"no-vnc/include/display.js",
"no-vnc/include/jsunzip.js",
"no-vnc/include/rfb.js",
"dashboard/vm-console.js",
"dashboard/vm-tour.js",
),
"output_filename": "vm-detail.js",
},
}
########## SECRET CONFIGURATION
......@@ -266,6 +344,7 @@ THIRD_PARTY_APPS = (
'statici18n',
'django_sshkey',
'autocomplete_light',
'pipeline',
)
# Apps specific for this project go here.
......
......@@ -109,3 +109,7 @@ CRISPY_FAIL_SILENTLY = not DEBUG
if DEBUG:
from django.dispatch import Signal
Signal.send_robust = Signal.send
PIPELINE_DISABLED_COMPILERS = (
'pipeline.compilers.less.LessCompiler',
)
......@@ -58,3 +58,6 @@ for i in LOCAL_APPS:
LOGGING['loggers'][i] = {'handlers': ['console'], 'level': level}
# Forbid store usage
STORE_URL = ""
# buildbot doesn't love pipeline
STATICFILES_STORAGE = 'django.contrib.staticfiles.storage.StaticFilesStorage'
from django.core.management.base import BaseCommand
from common.management.commands.watch import LessUtils
class Command(BaseCommand):
help = "Compiles all LESS files."
def handle(self, *args, **kwargs):
print("Compiling LESS")
LessUtils.initial_compile()
import subprocess
import os
import pyinotify
from django.core.management.base import BaseCommand
from django.conf import settings
STATIC_FILES = u'--include-path={}'.format(':'.join(settings.STATICFILES_DIRS))
IGNORED_FOLDERS = ("static_collected", "bower_components", )
class LessUtils(object):
@staticmethod
def less_path_to_css_path(pathname):
return "%s.css" % pathname[:-1 * len(".less")]
@staticmethod
def compile_less(less_pathname, css_pathname):
cmd = ["lessc", STATIC_FILES, less_pathname, css_pathname]
print("\n%s" % ("=" * 30))
print("Compiling: %s" % os.path.basename(less_pathname))
try:
subprocess.check_output(cmd)
except subprocess.CalledProcessError as e:
print(e.output)
else:
print("Successfully compiled:\n%s\n->\n%s" % (
less_pathname, css_pathname))
@staticmethod
def initial_compile():
""" Walks through the project looking for LESS files
and compiles them into CSS.
"""
for root, dirs, files in os.walk(settings.SITE_ROOT):
for f in files:
if not f.endswith(".less"):
continue
relpath = os.path.relpath(root, settings.SITE_ROOT)
if relpath.startswith(IGNORED_FOLDERS):
continue
less_pathname = "%s/%s" % (root, f)
css_pathname = LessUtils.less_path_to_css_path(less_pathname)
LessUtils.compile_less(less_pathname, css_pathname)
@staticmethod
def start_watch():
""" Watches for changes in LESS files recursively from the
project's root and compiles the files
"""
wm = pyinotify.WatchManager()
class EventHandler(pyinotify.ProcessEvent):
def process_IN_MODIFY(self, event):
if not event.name.endswith(".less"):
return
relpath = os.path.relpath(event.pathname, settings.SITE_ROOT)
if relpath.startswith(IGNORED_FOLDERS):
return
css_pathname = LessUtils.less_path_to_css_path(event.pathname)
LessUtils.compile_less(event.pathname, css_pathname)
handler = EventHandler()
notifier = pyinotify.Notifier(wm, handler)
wm.add_watch(settings.SITE_ROOT, pyinotify.IN_MODIFY, rec=True)
notifier.loop()
class Command(BaseCommand):
help = "Compiles all LESS files then watches for changes."
def handle(self, *args, **kwargs):
# for first run compile everything
print("Initial LESS compiles")
LessUtils.initial_compile()
print("\n%s\n" % ("=" * 30))
print("End of initial LESS compiles\n")
# after first run watch less files
LessUtils.start_watch()
// Core variables and mixins
@import "bootstrap/less/variables.less";
// Custom variables
@navbar-height: 45px;
@import "bootstrap/less/mixins.less";
// Reset and dependencies
@import "bootstrap/less/normalize.less";
@import "bootstrap/less/print.less";
// we don't use these, also they make collectstatic fail ...
// @import "bootstrap/less/glyphicons.less";
// Core CSS
@import "bootstrap/less/scaffolding.less";
@import "bootstrap/less/type.less";
@import "bootstrap/less/code.less";
@import "bootstrap/less/grid.less";
@import "bootstrap/less/tables.less";
@import "bootstrap/less/forms.less";
@import "bootstrap/less/buttons.less";
// Components
@import "bootstrap/less/component-animations.less";
@import "bootstrap/less/dropdowns.less";
@import "bootstrap/less/button-groups.less";
@import "bootstrap/less/input-groups.less";
@import "bootstrap/less/navs.less";
@import "bootstrap/less/navbar.less";
@import "bootstrap/less/breadcrumbs.less";
@import "bootstrap/less/pagination.less";
@import "bootstrap/less/pager.less";
@import "bootstrap/less/labels.less";
@import "bootstrap/less/badges.less";
@import "bootstrap/less/jumbotron.less";
@import "bootstrap/less/thumbnails.less";
@import "bootstrap/less/alerts.less";
@import "bootstrap/less/progress-bars.less";
@import "bootstrap/less/media.less";
@import "bootstrap/less/list-group.less";
@import "bootstrap/less/panels.less";
@import "bootstrap/less/responsive-embed.less";
@import "bootstrap/less/wells.less";
@import "bootstrap/less/close.less";
// Components w/ JavaScript
@import "bootstrap/less/modals.less";
@import "bootstrap/less/tooltip.less";
@import "bootstrap/less/popovers.less";
@import "bootstrap/less/carousel.less";
// Utility classes
@import "bootstrap/less/utilities.less";
@import "bootstrap/less/responsive-utilities.less";
/*!
* Slider for Bootstrap
*
* Copyright 2012 Stefan Petre
* Licensed under the Apache License v2.0
* http://www.apache.org/licenses/LICENSE-2.0
*
*/
.slider {
display: inline-block;
vertical-align: middle;
position: relative;
&.slider-horizontal {
width: 210px;
height: @baseLineHeight;
.slider-track {
height: @baseLineHeight/2;
width: 100%;
margin-top: -@baseLineHeight/4;
top: 50%;
left: 0;
}
.slider-selection {
height: 100%;
top: 0;
bottom: 0;
}
.slider-handle {
margin-left: -@baseLineHeight/2;
margin-top: -@baseLineHeight/4;
&.triangle {
border-width: 0 @baseLineHeight/2 @baseLineHeight/2 @baseLineHeight/2;
width: 0;
height: 0;
border-bottom-color: #0480be;
margin-top: 0;
}
}
}
&.slider-vertical {
height: 210px;
width: @baseLineHeight;
.slider-track {
width: @baseLineHeight/2;
height: 100%;
margin-left: -@baseLineHeight/4;
left: 50%;
top: 0;
}
.slider-selection {
width: 100%;
left: 0;
top: 0;
bottom: 0;
}
.slider-handle {
margin-left: -@baseLineHeight/4;
margin-top: -@baseLineHeight/2;
&.triangle {
border-width: @baseLineHeight/2 0 @baseLineHeight/2 @baseLineHeight/2;
width: 1px;
height: 1px;
border-left-color: #0480be;
margin-left: 0;
}
}
}
input {
display: none;
}
.tooltip-inner {
white-space: nowrap;
}
}
.slider-track {
position: absolute;
cursor: pointer;
#gradient > .vertical(#f5f5f5, #f9f9f9);
.box-shadow(inset 0 1px 2px rgba(0,0,0,.1));
.border-radius(@baseBorderRadius);
}
.slider-selection {
position: absolute;
#gradient > .vertical(#f9f9f9, #f5f5f5);
.box-shadow(inset 0 -1px 0 rgba(0,0,0,.15));
.box-sizing(border-box);
.border-radius(@baseBorderRadius);
}
.slider-handle {
position: absolute;
width: @baseLineHeight;
height: @baseLineHeight;
#gradient > .vertical(#149bdf, #0480be);
.box-shadow(~"inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05)");
opacity: 0.8;
border: 0px solid transparent;
&.round {
.border-radius(@baseLineHeight);
}
&.triangle {
background: transparent none;
}
}
\ No newline at end of file
/*!
* Slider for Bootstrap
*
* Copyright 2012 Stefan Petre
* Licensed under the Apache License v2.0
* http://www.apache.org/licenses/LICENSE-2.0
*
*/
.slider {
display: inline-block;
vertical-align: middle;
position: relative;
}
.slider.slider-horizontal {
width: 210px;
height: 20px;
}
.slider.slider-horizontal .slider-track {
height: 10px;
width: 100%;
margin-top: -5px;
top: 50%;
left: 0;
}
.slider.slider-horizontal .slider-selection {
height: 100%;
top: 0;
bottom: 0;
}
.slider.slider-horizontal .slider-handle {
margin-left: -10px;
margin-top: -5px;
}
.slider.slider-horizontal .slider-handle.triangle {
border-width: 0 10px 10px 10px;
width: 0;
height: 0;
border-bottom-color: #0480be;
margin-top: 0;
}
.slider.slider-vertical {
height: 210px;
width: 20px;
}
.slider.slider-vertical .slider-track {
width: 10px;
height: 100%;
margin-left: -5px;
left: 50%;
top: 0;
}
.slider.slider-vertical .slider-selection {
width: 100%;
left: 0;
top: 0;
bottom: 0;
}
.slider.slider-vertical .slider-handle {
margin-left: -5px;
margin-top: -10px;
}
.slider.slider-vertical .slider-handle.triangle {
border-width: 10px 0 10px 10px;
width: 1px;
height: 1px;
border-left-color: #0480be;
margin-left: 0;
}
.slider input {
display: none;
}
.slider .tooltip-inner {
white-space: nowrap;
}
.slider-track {
position: absolute;
cursor: pointer;
background-color: #f7f7f7;
background-image: -moz-linear-gradient(top, #f5f5f5, #f9f9f9);
background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#f5f5f5), to(#f9f9f9));
background-image: -webkit-linear-gradient(top, #f5f5f5, #f9f9f9);
background-image: -o-linear-gradient(top, #f5f5f5, #f9f9f9);
background-image: linear-gradient(to bottom, #f5f5f5, #f9f9f9);
background-repeat: repeat-x;
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#fff9f9f9', GradientType=0);
-webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);
-moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);
box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);
-webkit-border-radius: 4px;
-moz-border-radius: 4px;
border-radius: 4px;
}
.slider-selection {
position: absolute;
background-color: #f7f7f7;
background-image: -moz-linear-gradient(top, #f9f9f9, #f5f5f5);
background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#f9f9f9), to(#f5f5f5));
background-image: -webkit-linear-gradient(top, #f9f9f9, #f5f5f5);
background-image: -o-linear-gradient(top, #f9f9f9, #f5f5f5);
background-image: linear-gradient(to bottom, #f9f9f9, #f5f5f5);
background-repeat: repeat-x;
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff9f9f9', endColorstr='#fff5f5f5', GradientType=0);
-webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15);
-moz-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15);
box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15);
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
-webkit-border-radius: 4px;
-moz-border-radius: 4px;
border-radius: 4px;
}
.slider-handle {
position: absolute;
width: 20px;
height: 20px;
background-color: #0e90d2;
background-image: -moz-linear-gradient(top, #149bdf, #0480be);
background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#149bdf), to(#0480be));
background-image: -webkit-linear-gradient(top, #149bdf, #0480be);
background-image: -o-linear-gradient(top, #149bdf, #0480be);
background-image: linear-gradient(to bottom, #149bdf, #0480be);
background-repeat: repeat-x;
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff149bdf', endColorstr='#ff0480be', GradientType=0);
-webkit-box-shadow: inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05);
-moz-box-shadow: inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05);
box-shadow: inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05);
opacity: 0.8;
border: 0px solid transparent;
}
.slider-handle.round {
-webkit-border-radius: 20px;
-moz-border-radius: 20px;
border-radius: 20px;
}
.slider-handle.triangle {
background: transparent none;
}
/* custom */
.slider-handle, .slider-handle:hover {
background-color: #3071a9;
opacity: 1;
width: 8px;
height: 26px;
margin-top: -4px!important;
margin-left: -6px !important;
border-radius: 0px;
-moz-border-radius: 0px;
-webkit-border-radius: 0px;
text-shadow: 0 1px 0 #fff;
background-image: -webkit-gradient(linear, left 0%, left 100%, from(#428bca), to(#3071a9));
background-image: -webkit-linear-gradient(top, #428bca, 0%, #3071a9, 100%);
background-image: -moz-linear-gradient(top, #428bca 0%, #3071a9 100%);
background-image: linear-gradient(to bottom, #428bca 0%, #3071a9 100%);
background-repeat: repeat-x;
border-color: #2d6ca2;
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff3071a9', GradientType=0);
}
.slider-handle:hover {
background: #428bca;
background-image: none;
border-color: #2d6ca2;
}
.slider-track, .slider-selection {
height: 20px !important;
background: #ccc;
background: -webkit-linear-gradient(top, #bbb, #ddd);
background: -moz-linear-gradient(top, #bbb, #ddd);
background: linear-gradient(top, #bbb, #ddd);
-webkit-box-shadow: inset 0 2px 4px rgba(0,0,0,0.1);
-moz-box-shadow: inset 0 2px 4px rgba(0,0,0,0.1);
box-shadow: inset 0 2px 4px rgba(0,0,0,0.1);
-webkit-border-radius: 4px;
-moz-border-radius: 4px;
border-radius: 4px;
border: 1px solid #aaa;
}
.slider-selection {
background-color: #8DCA09;
background: -webkit-linear-gradient(top, #8DCA09, #72A307);
background: -moz-linear-gradient(top, #8DCA09, #72A307);
background: linear-gradient(top, #8DCA09, #72A307);
border-color: #496805;
}
.vm-slider {
width: 300px;
}
.output {
padding-left: 10px;
font-weight: bold;
}
......@@ -364,9 +364,11 @@ a.hover-black {
display: block;
}
.notification-messages {
#notification-messages {
padding: 10px 8px;
width: 350px;
right: 0;
left: auto;
}
.notification-message {
......@@ -375,7 +377,7 @@ a.hover-black {
border-bottom: 1px dotted #D3D3D3;
}
.notification-messages .notification-message:last-child {
#notification-messages .notification-message:last-child {
margin-bottom: 0px;
padding: 0px;
border-bottom: none;
......@@ -390,6 +392,15 @@ a.hover-black {
cursor: pointer;
}
#notification-button a.dropdown-toggle {
color: white;
font-size: 12px;
}
#notification-button {
margin-right: 15px;
}
#vm-migrate-node-list {
list-style: none;
}
......@@ -950,6 +961,48 @@ textarea[name="new_members"] {
#vm-list-search, #vm-mass-ops {
margin-top: 8px;
}
.list-group-item-last {
border-bottom: 1px solid #ddd !important;
}
.slider {
display: inline-block;
}
.slider .track {
height: 20px;
top: 50%;
}
.slider > .dragger, .slider > .dragger:hover {
border-radius: 0px;
-moz-border-radius: 0px;
-webkit-border-radius: 0px;
width: 8px;
height: 24px;
margin-top: -12px!important;
text-shadow: 0 1px 0 #fff;
background-image: -webkit-gradient(linear, left 0%, left 100%, from(#428bca), to(#3071a9));
background-image: -webkit-linear-gradient(top, #428bca, 0%, #3071a9, 100%);
background-image: -moz-linear-gradient(top, #428bca 0%, #3071a9 100%);
background-image: linear-gradient(to bottom, #428bca 0%, #3071a9 100%);
background-repeat: repeat-x;
border-color: #2d6ca2;
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff3071a9', GradientType=0);
}
.slider > .dragger:hover {
background-color: #3071a9;
background-image: none;
border-color: #2d6ca2;
}
.slider > .highlight-track {
height: 20px;
top: 50%;
}
.slider > .track, .slider > .highlight-track {
border-radius: 5px;
}
.slider {
width: 100%;
}
#vm-list-search-checkbox {
margin-top: -1px;
......@@ -1051,3 +1104,50 @@ textarea[name="new_members"] {
white-space: nowrap;