Skip to content
Toggle navigation
P
Projects
G
Groups
S
Snippets
Help
CIRCLE
/
cloud
This project
Loading...
Sign in
Toggle navigation
Go to a project
Project
Repository
Issues
94
Merge Requests
10
Pipelines
Wiki
Snippets
Members
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Commit
15d3d135
authored
Aug 29, 2014
by
Kálmán Viktor
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'master' into feature-template-list
parents
a304c0e4
4268ac9d
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
28 changed files
with
567 additions
and
227 deletions
+567
-227
circle/common/models.py
+36
-4
circle/common/operations.py
+25
-8
circle/dashboard/static/dashboard/dashboard.css
+73
-0
circle/dashboard/static/dashboard/dashboard.js
+7
-2
circle/dashboard/static/dashboard/vm-create.js
+5
-0
circle/dashboard/static/dashboard/vm-list.js
+113
-79
circle/dashboard/templates/dashboard/_notifications-timeline.html
+3
-2
circle/dashboard/templates/dashboard/_vm-mass-migrate.html
+36
-0
circle/dashboard/templates/dashboard/instanceactivity_detail.html
+3
-7
circle/dashboard/templates/dashboard/lease-create.html
+1
-1
circle/dashboard/templates/dashboard/lease-edit.html
+1
-1
circle/dashboard/templates/dashboard/mass-operate.html
+38
-0
circle/dashboard/templates/dashboard/node-detail/_activity-timeline.html
+2
-4
circle/dashboard/templates/dashboard/template-list.html
+1
-1
circle/dashboard/templates/dashboard/vm-detail/_activity-timeline.html
+5
-5
circle/dashboard/templates/dashboard/vm-list.html
+40
-37
circle/dashboard/templatetags/hro.py
+12
-0
circle/dashboard/tests/test_mockedviews.py
+109
-1
circle/dashboard/tests/test_views.py
+0
-14
circle/dashboard/urls.py
+2
-5
circle/dashboard/views.py
+0
-0
circle/dashboard/vm/urls.py
+12
-4
circle/locale/hu/LC_MESSAGES/django.po
+0
-0
circle/locale/hu/LC_MESSAGES/djangojs.po
+12
-11
circle/vm/models/activity.py
+9
-6
circle/vm/models/instance.py
+7
-1
circle/vm/models/node.py
+1
-1
circle/vm/operations.py
+14
-33
No files found.
circle/common/models.py
View file @
15d3d135
...
@@ -27,6 +27,7 @@ from warnings import warn
...
@@ -27,6 +27,7 @@ from warnings import warn
from
django.contrib
import
messages
from
django.contrib
import
messages
from
django.contrib.auth.models
import
User
from
django.contrib.auth.models
import
User
from
django.core.cache
import
cache
from
django.core.cache
import
cache
from
django.core.exceptions
import
PermissionDenied
from
django.core.serializers.json
import
DjangoJSONEncoder
from
django.core.serializers.json
import
DjangoJSONEncoder
from
django.db.models
import
(
from
django.db.models
import
(
CharField
,
DateTimeField
,
ForeignKey
,
NullBooleanField
CharField
,
DateTimeField
,
ForeignKey
,
NullBooleanField
...
@@ -413,6 +414,10 @@ class HumanReadableObject(object):
...
@@ -413,6 +414,10 @@ class HumanReadableObject(object):
self
.
_set_values
(
user_text_template
,
admin_text_template
,
params
)
self
.
_set_values
(
user_text_template
,
admin_text_template
,
params
)
def
_set_values
(
self
,
user_text_template
,
admin_text_template
,
params
):
def
_set_values
(
self
,
user_text_template
,
admin_text_template
,
params
):
if
isinstance
(
user_text_template
,
Promise
):
user_text_template
=
user_text_template
.
_proxy____args
[
0
]
if
isinstance
(
admin_text_template
,
Promise
):
admin_text_template
=
admin_text_template
.
_proxy____args
[
0
]
self
.
user_text_template
=
user_text_template
self
.
user_text_template
=
user_text_template
self
.
admin_text_template
=
admin_text_template
self
.
admin_text_template
=
admin_text_template
self
.
params
=
params
self
.
params
=
params
...
@@ -451,6 +456,12 @@ class HumanReadableObject(object):
...
@@ -451,6 +456,12 @@ class HumanReadableObject(object):
self
.
user_text_template
,
unicode
(
self
.
params
))
self
.
user_text_template
,
unicode
(
self
.
params
))
return
self
.
user_text_template
return
self
.
user_text_template
def
get_text
(
self
,
user
):
if
user
and
user
.
is_superuser
:
return
self
.
get_admin_text
()
else
:
return
self
.
get_user_text
()
def
to_dict
(
self
):
def
to_dict
(
self
):
return
{
"user_text_template"
:
self
.
user_text_template
,
return
{
"user_text_template"
:
self
.
user_text_template
,
"admin_text_template"
:
self
.
admin_text_template
,
"admin_text_template"
:
self
.
admin_text_template
,
...
@@ -481,13 +492,34 @@ class HumanReadableException(HumanReadableObject, Exception):
...
@@ -481,13 +492,34 @@ class HumanReadableException(HumanReadableObject, Exception):
self
.
level
=
"error"
self
.
level
=
"error"
def
send_message
(
self
,
request
,
level
=
None
):
def
send_message
(
self
,
request
,
level
=
None
):
if
request
.
user
and
request
.
user
.
is_superuser
:
msg
=
self
.
get_text
(
request
.
user
)
msg
=
self
.
get_admin_text
()
else
:
msg
=
self
.
get_user_text
()
getattr
(
messages
,
level
or
self
.
level
)(
request
,
msg
)
getattr
(
messages
,
level
or
self
.
level
)(
request
,
msg
)
def
fetch_human_exception
(
exception
,
user
=
None
):
"""Fetch user readable message from exception.
>>> r = humanize_exception("foo", Exception())
>>> fetch_human_exception(r, User())
u'foo'
>>> fetch_human_exception(r).get_text(User())
u'foo'
>>> fetch_human_exception(Exception(), User())
u'Unknown error'
>>> fetch_human_exception(PermissionDenied(), User())
u'Permission Denied'
"""
if
not
isinstance
(
exception
,
HumanReadableException
):
if
isinstance
(
exception
,
PermissionDenied
):
exception
=
create_readable
(
ugettext_noop
(
"Permission Denied"
))
else
:
exception
=
create_readable
(
ugettext_noop
(
"Unknown error"
),
ugettext_noop
(
"Unknown error:
%(ex)
s"
),
ex
=
unicode
(
exception
))
return
exception
.
get_text
(
user
)
if
user
else
exception
def
humanize_exception
(
message
,
exception
=
None
,
level
=
None
,
**
params
):
def
humanize_exception
(
message
,
exception
=
None
,
level
=
None
,
**
params
):
"""Return new dynamic-class exception which is based on
"""Return new dynamic-class exception which is based on
HumanReadableException and the original class with the dict of exception.
HumanReadableException and the original class with the dict of exception.
...
...
circle/common/operations.py
View file @
15d3d135
...
@@ -18,10 +18,10 @@
...
@@ -18,10 +18,10 @@
from
inspect
import
getargspec
from
inspect
import
getargspec
from
logging
import
getLogger
from
logging
import
getLogger
from
.models
import
activity_context
,
has_suffix
from
django.core.exceptions
import
PermissionDenied
,
ImproperlyConfigured
from
django.core.exceptions
import
PermissionDenied
,
ImproperlyConfigured
from
django.utils.translation
import
ugettext_noop
from
.models
import
activity_context
,
has_suffix
,
humanize_exception
logger
=
getLogger
(
__name__
)
logger
=
getLogger
(
__name__
)
...
@@ -31,6 +31,7 @@ class Operation(object):
...
@@ -31,6 +31,7 @@ class Operation(object):
"""
"""
async_queue
=
'localhost.man'
async_queue
=
'localhost.man'
required_perms
=
None
required_perms
=
None
superuser_required
=
False
do_not_call_in_templates
=
True
do_not_call_in_templates
=
True
abortable
=
False
abortable
=
False
has_percentage
=
False
has_percentage
=
False
...
@@ -143,13 +144,26 @@ class Operation(object):
...
@@ -143,13 +144,26 @@ class Operation(object):
def
check_precond
(
self
):
def
check_precond
(
self
):
pass
pass
def
check_auth
(
self
,
user
):
@classmethod
if
self
.
required_perms
is
None
:
def
check_perms
(
cls
,
user
):
"""Check if user is permitted to run this operation on any instance
"""
if
cls
.
required_perms
is
None
:
raise
ImproperlyConfigured
(
raise
ImproperlyConfigured
(
"Set required_perms to () if none needed."
)
"Set required_perms to () if none needed."
)
if
not
user
.
has_perms
(
self
.
required_perms
):
if
not
user
.
has_perms
(
cls
.
required_perms
):
raise
PermissionDenied
(
"
%
s doesn't have the required permissions."
raise
PermissionDenied
(
"
%
s doesn't have the required permissions."
%
user
)
%
user
)
if
cls
.
superuser_required
and
not
user
.
is_superuser
:
raise
humanize_exception
(
ugettext_noop
(
"Superuser privileges are required."
),
PermissionDenied
())
def
check_auth
(
self
,
user
):
"""Check if user is permitted to run this operation on this instance
"""
self
.
check_perms
(
user
)
def
create_activity
(
self
,
parent
,
user
,
kwargs
):
def
create_activity
(
self
,
parent
,
user
,
kwargs
):
raise
NotImplementedError
raise
NotImplementedError
...
@@ -185,14 +199,17 @@ class OperatedMixin(object):
...
@@ -185,14 +199,17 @@ class OperatedMixin(object):
def
__getattr__
(
self
,
name
):
def
__getattr__
(
self
,
name
):
# NOTE: __getattr__ is only called if the attribute doesn't already
# NOTE: __getattr__ is only called if the attribute doesn't already
# exist in your __dict__
# exist in your __dict__
cls
=
self
.
__class__
return
self
.
get_operation_class
(
name
)(
self
)
@classmethod
def
get_operation_class
(
cls
,
name
):
ops
=
getattr
(
cls
,
operation_registry_name
,
{})
ops
=
getattr
(
cls
,
operation_registry_name
,
{})
op
=
ops
.
get
(
name
)
op
=
ops
.
get
(
name
)
if
op
:
if
op
:
return
op
(
self
)
return
op
else
:
else
:
raise
AttributeError
(
"
%
r object has no attribute
%
r"
%
raise
AttributeError
(
"
%
r object has no attribute
%
r"
%
(
self
.
__class__
.
__name__
,
name
))
(
cls
.
__name__
,
name
))
def
get_available_operations
(
self
,
user
):
def
get_available_operations
(
self
,
user
):
"""Yield Operations that match permissions of user and preconditions.
"""Yield Operations that match permissions of user and preconditions.
...
...
circle/dashboard/static/dashboard/dashboard.css
View file @
15d3d135
...
@@ -867,3 +867,76 @@ textarea[name="list-new-namelist"] {
...
@@ -867,3 +867,76 @@ textarea[name="list-new-namelist"] {
border-bottom
:
1px
dotted
#aaa
;
border-bottom
:
1px
dotted
#aaa
;
padding
:
5px
0px
;
padding
:
5px
0px
;
}
}
#vm-list-table
.migrating-icon
{
-webkit-animation
:
passing
2s
linear
infinite
;
animation
:
passing
2s
linear
infinite
;
}
@-webkit-keyframes
passing
{
0
%
{
-webkit-transform
:
translateX
(
50%
);
transform
:
translateX
(
50%
);
opacity
:
0
;
}
50
%
{
-webkit-transform
:
translateX
(
0%
);
transform
:
translateX
(
0%
);
opacity
:
1
;
}
100
%
{
-webkit-transform
:
translateX
(
-50%
);
transform
:
translateX
(
-50%
);
opacity
:
0
;
}
}
@keyframes
passing
{
0
%
{
-webkit-transform
:
translateX
(
50%
);
-ms-transform
:
translateX
(
50%
);
transform
:
translateX
(
50%
);
opacity
:
0
;
}
50
%
{
-webkit-transform
:
translateX
(
0%
);
-ms-transform
:
translateX
(
0%
);
transform
:
translateX
(
0%
);
opacity
:
1
;
}
100
%
{
-webkit-transform
:
translateX
(
-50%
);
-ms-transform
:
translateX
(
-50%
);
transform
:
translateX
(
-50%
);
opacity
:
0
;
}
}
.mass-migrate-node
{
cursor
:
pointer
;
}
.mass-op-panel
{
padding
:
6px
10px
;
}
.mass-op-panel
.check
{
color
:
#449d44
;
}
.mass-op-panel
.minus
{
color
:
#d9534f
;
}
.mass-op-panel
.status-icon
{
font-size
:
.8em
;
}
#vm-list-search
,
#vm-mass-ops
{
margin-top
:
8px
;
}
circle/dashboard/static/dashboard/dashboard.js
View file @
15d3d135
...
@@ -488,14 +488,19 @@ function addSliderMiscs() {
...
@@ -488,14 +488,19 @@ function addSliderMiscs() {
ram_fire
=
true
;
ram_fire
=
true
;
$
(
".ram-slider"
).
simpleSlider
(
"setValue"
,
parseInt
(
val
));
$
(
".ram-slider"
).
simpleSlider
(
"setValue"
,
parseInt
(
val
));
});
});
$
(
".cpu-priority-input"
).
trigger
(
"change"
);
$
(
".cpu-count-input, .ram-input"
).
trigger
(
"input"
);
setDefaultSliderValues
(
);
$
(
".cpu-priority-slider"
).
simpleSlider
(
"setDisabled"
,
$
(
".cpu-priority-input"
).
prop
(
"disabled"
));
$
(
".cpu-priority-slider"
).
simpleSlider
(
"setDisabled"
,
$
(
".cpu-priority-input"
).
prop
(
"disabled"
));
$
(
".cpu-count-slider"
).
simpleSlider
(
"setDisabled"
,
$
(
".cpu-count-input"
).
prop
(
"disabled"
));
$
(
".cpu-count-slider"
).
simpleSlider
(
"setDisabled"
,
$
(
".cpu-count-input"
).
prop
(
"disabled"
));
$
(
".ram-slider"
).
simpleSlider
(
"setDisabled"
,
$
(
".ram-input"
).
prop
(
"disabled"
));
$
(
".ram-slider"
).
simpleSlider
(
"setDisabled"
,
$
(
".ram-input"
).
prop
(
"disabled"
));
}
}
function
setDefaultSliderValues
()
{
$
(
".cpu-priority-input"
).
trigger
(
"change"
);
$
(
".ram-input, .cpu-count-input"
).
trigger
(
"input"
);
}
/* deletes the VM with the pk
/* deletes the VM with the pk
* if dir is true, then redirect to the dashboard landing page
* if dir is true, then redirect to the dashboard landing page
...
...
circle/dashboard/static/dashboard/vm-create.js
View file @
15d3d135
...
@@ -28,6 +28,9 @@ function vmCreateLoaded() {
...
@@ -28,6 +28,9 @@ function vmCreateLoaded() {
$
(
'#create-modal'
).
on
(
'hidden.bs.modal'
,
function
()
{
$
(
'#create-modal'
).
on
(
'hidden.bs.modal'
,
function
()
{
$
(
'#create-modal'
).
remove
();
$
(
'#create-modal'
).
remove
();
});
});
$
(
"#create-modal"
).
on
(
"shown.bs.modal"
,
function
()
{
setDefaultSliderValues
();
});
});
});
return
false
;
return
false
;
});
});
...
@@ -217,6 +220,8 @@ function vmCustomizeLoaded() {
...
@@ -217,6 +220,8 @@ function vmCustomizeLoaded() {
});
});
if
(
error
)
return
true
;
if
(
error
)
return
true
;
$
(
this
).
find
(
"i"
).
prop
(
"class"
,
"fa fa-spinner fa-spin"
);
$
.
ajax
({
$
.
ajax
({
url
:
'/dashboard/vm/create/'
,
url
:
'/dashboard/vm/create/'
,
headers
:
{
"X-CSRFToken"
:
getCookie
(
'csrftoken'
)},
headers
:
{
"X-CSRFToken"
:
getCookie
(
'csrftoken'
)},
...
...
circle/dashboard/static/dashboard/vm-list.js
View file @
15d3d135
...
@@ -14,6 +14,7 @@ $(function() {
...
@@ -14,6 +14,7 @@ $(function() {
$
(
'.vm-list-table tbody'
).
find
(
'tr'
).
mousedown
(
function
()
{
$
(
'.vm-list-table tbody'
).
find
(
'tr'
).
mousedown
(
function
()
{
var
retval
=
true
;
var
retval
=
true
;
if
(
!
$
(
this
).
data
(
"vm-pk"
))
return
;
if
(
ctrlDown
)
{
if
(
ctrlDown
)
{
setRowColor
(
$
(
this
));
setRowColor
(
$
(
this
));
if
(
!
$
(
this
).
hasClass
(
'vm-list-selected'
))
{
if
(
!
$
(
this
).
hasClass
(
'vm-list-selected'
))
{
...
@@ -46,86 +47,20 @@ $(function() {
...
@@ -46,86 +47,20 @@ $(function() {
selected
=
[{
'index'
:
$
(
this
).
index
(),
'vm'
:
$
(
this
).
data
(
"vm-pk"
)}];
selected
=
[{
'index'
:
$
(
this
).
index
(),
'vm'
:
$
(
this
).
data
(
"vm-pk"
)}];
}
}
// reset btn disables
$
(
'.vm-list-table tbody tr .btn'
).
attr
(
'disabled'
,
false
);
// show/hide group controls
// show/hide group controls
if
(
selected
.
length
>
0
)
{
if
(
selected
.
length
>
0
)
{
$
(
'.vm-list-group-control a'
).
attr
(
'disabled'
,
false
);
$
(
'#vm-mass-ops .mass-operation'
).
attr
(
'disabled'
,
false
);
for
(
var
i
=
0
;
i
<
selected
.
length
;
i
++
)
{
$
(
'.vm-list-table tbody tr'
).
eq
(
selected
[
i
]).
find
(
'.btn'
).
attr
(
'disabled'
,
true
);
}
}
else
{
}
else
{
$
(
'
.vm-list-group-control a
'
).
attr
(
'disabled'
,
true
);
$
(
'
#vm-mass-ops .mass-operation
'
).
attr
(
'disabled'
,
true
);
}
}
return
retval
;
return
retval
;
});
});
$
(
'#vm-list-group-migrate'
).
click
(
function
()
{
// pass?
});
$
(
'.vm-list-details'
).
popover
({
'placement'
:
'auto'
,
'html'
:
true
,
'trigger'
:
'hover'
});
$
(
'.vm-list-connect'
).
popover
({
'placement'
:
'left'
,
'html'
:
true
,
'trigger'
:
'click'
});
$
(
'tbody a'
).
mousedown
(
function
(
e
)
{
$
(
'tbody a'
).
mousedown
(
function
(
e
)
{
// parent tr doesn't get selected when clicked
// parent tr doesn't get selected when clicked
e
.
stopPropagation
();
e
.
stopPropagation
();
});
});
$
(
'tbody a'
).
click
(
function
(
e
)
{
// browser doesn't jump to top when clicked the buttons
if
(
!
$
(
this
).
hasClass
(
'real-link'
))
{
return
false
;
}
});
/* rename */
$
(
"#vm-list-rename-button, .vm-details-rename-button"
).
click
(
function
()
{
$
(
"#vm-list-column-name"
,
$
(
this
).
closest
(
"tr"
)).
hide
();
$
(
"#vm-list-rename"
,
$
(
this
).
closest
(
"tr"
)).
css
(
'display'
,
'inline'
);
$
(
"#vm-list-rename-name"
,
$
(
this
).
closest
(
"tr"
)).
focus
();
});
/* rename ajax */
$
(
'.vm-list-rename-submit'
).
click
(
function
()
{
var
row
=
$
(
this
).
closest
(
"tr"
)
var
name
=
$
(
'#vm-list-rename-name'
,
row
).
val
();
var
url
=
'/dashboard/vm/'
+
row
.
children
(
"td:first-child"
).
text
().
replace
(
" "
,
""
)
+
'/'
;
$
.
ajax
({
method
:
'POST'
,
url
:
url
,
data
:
{
'new_name'
:
name
},
headers
:
{
"X-CSRFToken"
:
getCookie
(
'csrftoken'
)},
success
:
function
(
data
,
textStatus
,
xhr
)
{
$
(
"#vm-list-column-name"
,
row
).
html
(
$
(
"<a/>"
,
{
'class'
:
"real-link"
,
href
:
"/dashboard/vm/"
+
data
[
'vm_pk'
]
+
"/"
,
text
:
data
[
'new_name'
]
})
).
show
();
$
(
'#vm-list-rename'
,
row
).
hide
();
// addMessage(data['message'], "success");
},
error
:
function
(
xhr
,
textStatus
,
error
)
{
addMessage
(
"Error during renaming!"
,
"danger"
);
}
});
return
false
;
});
/* group actions */
/* group actions */
/* select all */
/* select all */
...
@@ -133,27 +68,69 @@ $(function() {
...
@@ -133,27 +68,69 @@ $(function() {
$
(
'.vm-list-table tbody tr'
).
each
(
function
()
{
$
(
'.vm-list-table tbody tr'
).
each
(
function
()
{
var
index
=
$
(
this
).
index
();
var
index
=
$
(
this
).
index
();
var
vm
=
$
(
this
).
data
(
"vm-pk"
);
var
vm
=
$
(
this
).
data
(
"vm-pk"
);
if
(
!
isAlreadySelected
(
vm
))
{
if
(
vm
&&
!
isAlreadySelected
(
vm
))
{
selected
.
push
({
'index'
:
index
,
'vm'
:
vm
});
selected
.
push
({
'index'
:
index
,
'vm'
:
vm
});
$
(
this
).
addClass
(
'vm-list-selected'
);
$
(
this
).
addClass
(
'vm-list-selected'
);
}
}
});
});
if
(
selected
.
length
>
0
)
if
(
selected
.
length
>
0
)
$
(
'
.vm-list-group-control a
'
).
attr
(
'disabled'
,
false
);
$
(
'
#vm-mass-ops .mass-operation
'
).
attr
(
'disabled'
,
false
);
return
false
;
return
false
;
});
});
/* mass vm delete */
$
(
'#vm-list-group-delete'
).
click
(
function
()
{
/* mass operations */
addModalConfirmation
(
massDeleteVm
,
$
(
"#vm-mass-ops"
).
on
(
'click'
,
'.mass-operation'
,
function
(
e
)
{
{
var
icon
=
$
(
this
).
children
(
"i"
).
addClass
(
'fa-spinner fa-spin'
);
'url'
:
'/dashboard/vm/mass-delete/'
,
params
=
"?"
+
selected
.
map
(
function
(
a
){
return
"vm="
+
a
.
vm
}).
join
(
"&"
);
'data'
:
{
'selected'
:
selected
,
$
.
ajax
({
'v'
:
collectIds
(
selected
)
type
:
'GET'
,
url
:
$
(
this
).
attr
(
'href'
)
+
params
,
success
:
function
(
data
)
{
icon
.
removeClass
(
"fa-spinner fa-spin"
);
$
(
'body'
).
append
(
data
);
$
(
'#confirmation-modal'
).
modal
(
'show'
);
$
(
'#confirmation-modal'
).
on
(
'hidden.bs.modal'
,
function
()
{
$
(
'#confirmation-modal'
).
remove
();
});
$
(
"[title]"
).
tooltip
({
'placement'
:
"left"
});
}
});
return
false
;
});
$
(
"body"
).
on
(
"click"
,
"#op-form-send"
,
function
()
{
var
url
=
$
(
this
).
closest
(
"form"
).
prop
(
"action"
);
$
(
this
).
find
(
"i"
).
prop
(
"class"
,
"fa fa-fw fa-spinner fa-spin"
);
$
.
ajax
({
url
:
url
,
headers
:
{
"X-CSRFToken"
:
getCookie
(
'csrftoken'
)},
type
:
'POST'
,
data
:
$
(
this
).
closest
(
'form'
).
serialize
(),
success
:
function
(
data
,
textStatus
,
xhr
)
{
/* hide the modal we just submitted */
$
(
'#confirmation-modal'
).
modal
(
"hide"
);
updateStatuses
(
1
);
/* if there are messages display them */
if
(
data
.
messages
&&
data
.
messages
.
length
>
0
)
{
addMessage
(
data
.
messages
.
join
(
"<br />"
),
"danger"
);
}
},
error
:
function
(
xhr
,
textStatus
,
error
)
{
$
(
'#confirmation-modal'
).
modal
(
"hide"
);
if
(
xhr
.
status
==
500
)
{
addMessage
(
"500 Internal Server Error"
,
"danger"
);
}
else
{
addMessage
(
xhr
.
status
+
" "
+
xhr
.
statusText
,
"danger"
);
}
}
}
}
);
}
);
return
false
;
return
false
;
});
});
...
@@ -181,8 +158,65 @@ $(function() {
...
@@ -181,8 +158,65 @@ $(function() {
$
(
".vm-list-table th a"
).
on
(
"click"
,
function
(
event
)
{
$
(
".vm-list-table th a"
).
on
(
"click"
,
function
(
event
)
{
event
.
preventDefault
();
event
.
preventDefault
();
});
});
$
(
document
).
on
(
"click"
,
".mass-migrate-node"
,
function
()
{
$
(
this
).
find
(
'input[type="radio"]'
).
prop
(
"checked"
,
true
);
});
if
(
checkStatusUpdate
())
{
updateStatuses
(
1
);
}
});
});
function
checkStatusUpdate
()
{
icons
=
$
(
"#vm-list-table tbody td.state i"
);
if
(
icons
.
hasClass
(
"fa-spin"
)
||
icons
.
hasClass
(
"migrating-icon"
))
{
return
true
;
}
}
function
updateStatuses
(
runs
)
{
$
.
get
(
"/dashboard/vm/list/?compact"
,
function
(
result
)
{
$
(
"#vm-list-table tbody tr"
).
each
(
function
()
{
vm
=
$
(
this
).
data
(
"vm-pk"
);
status_td
=
$
(
this
).
find
(
"td.state"
);
status_icon
=
status_td
.
find
(
"i"
);
status_text
=
status_td
.
find
(
"span"
);
if
(
vm
in
result
)
{
if
(
result
[
vm
].
in_status_change
)
{
if
(
!
status_icon
.
hasClass
(
"fa-spin"
))
{
status_icon
.
prop
(
"class"
,
"fa fa-fw fa-spinner fa-spin"
);
}
}
else
if
(
result
[
vm
].
status
==
"MIGRATING"
)
{
if
(
!
status_icon
.
hasClass
(
"migrating-icon"
))
{
status_icon
.
prop
(
"class"
,
"fa fa-fw "
+
result
[
vm
].
icon
+
" migrating-icon"
);
}
}
else
{
status_icon
.
prop
(
"class"
,
"fa fa-fw "
+
result
[
vm
].
icon
);
}
status_text
.
text
(
result
[
vm
].
status
);
if
(
"node"
in
result
[
vm
])
{
$
(
this
).
find
(
".node"
).
text
(
result
[
vm
].
node
);
}
}
else
{
$
(
this
).
remove
();
}
});
if
(
checkStatusUpdate
())
{
setTimeout
(
function
()
{
updateStatuses
(
runs
+
1
)},
1000
+
Math
.
exp
(
runs
*
0.05
)
);
}
});
}
function
isAlreadySelected
(
vm
)
{
function
isAlreadySelected
(
vm
)
{
for
(
var
i
=
0
;
i
<
selected
.
length
;
i
++
)
for
(
var
i
=
0
;
i
<
selected
.
length
;
i
++
)
if
(
selected
[
i
].
vm
==
vm
)
if
(
selected
[
i
].
vm
==
vm
)
...
...
circle/dashboard/templates/dashboard/_notifications-timeline.html
View file @
15d3d135
{% load i18n %}
{% load i18n %}
{% load hro %}
{% for n in notifications %}
{% for n in notifications %}
<li
class=
"notification-message"
id=
"msg-{{n.id}}"
>
<li
class=
"notification-message"
id=
"msg-{{n.id}}"
>
<span
class=
"notification-message-subject"
>
<span
class=
"notification-message-subject"
>
{% if n.status == "new" %}
<i
class=
"fa fa-envelope-o"
></i>
{% endif %}
{% if n.status == "new" %}
<i
class=
"fa fa-envelope-o"
></i>
{% endif %}
{{ n.subject
.get_user_text
}}
{{ n.subject
|get_text:user
}}
</span>
</span>
<span
class=
"notification-message-date pull-right"
title=
"{{n.created}}"
>
<span
class=
"notification-message-date pull-right"
title=
"{{n.created}}"
>
{{ n.created|timesince }}
{{ n.created|timesince }}
</span>
</span>
<div
style=
"clear: both;"
></div>
<div
style=
"clear: both;"
></div>
<div
class=
"notification-message-text"
>
<div
class=
"notification-message-text"
>
{{ n.message
.get_user_text
|safe }}
{{ n.message
|get_text:user
|safe }}
</div>
</div>
</li>
</li>
{% empty %}
{% empty %}
...
...
circle/dashboard/templates/dashboard/_vm-mass-migrate.html
0 → 100644
View file @
15d3d135
{% extends "dashboard/mass-operate.html" %}
{% load i18n %}
{% load sizefieldtags %}
{% block formfields %}
<hr
/>
<ul
id=
"vm-migrate-node-list"
class=
"list-unstyled"
>
<li
class=
"panel panel-default panel-primary mass-migrate-node"
>
<div
class=
"panel-body"
>
<label
for=
"migrate-to-none"
>
<strong>
{% trans "Reschedule" %}
</strong>
</label>
<input
id=
"migrate-to-none"
type=
"radio"
name=
"node"
value=
""
style=
"float: right;"
checked=
"checked"
>
<span
class=
"vm-migrate-node-property"
>
{% trans "This option will reschedule each virtual machine to the optimal node." %}
</span>
<div
style=
"clear: both;"
></div>
</div>
</li>
{% for n in nodes %}
<li
class=
"panel panel-default mass-migrate-node"
>
<div
class=
"panel-body"
>
<label
for=
"migrate-to-{{n.pk}}"
>
<strong>
{{ n }}
</strong>
</label>
<input
id=
"migrate-to-{{n.pk}}"
type=
"radio"
name=
"node"
value=
"{{ n.pk }}"
style=
"float: right;"
/>
<span
class=
"vm-migrate-node-property"
>
{% trans "CPU load" %}: {{ n.cpu_usage }}
</span>
<span
class=
"vm-migrate-node-property"
>
{% trans "RAM usage" %}: {{ n.byte_ram_usage|filesize }}/{{ n.ram_size|filesize }}
</span>
<div
style=
"clear: both;"
></div>
</div>
</li>
{% endfor %}
</ul>
<hr
/>
{% endblock %}
circle/dashboard/templates/dashboard/instanceactivity_detail.html
View file @
15d3d135
{% extends "dashboard/base.html" %}
{% extends "dashboard/base.html" %}
{% load i18n %}
{% load i18n %}
{% load hro %}
{% block content %}
{% block content %}
<div
class=
"body-content"
>
<div
class=
"body-content"
>
<div
class=
"page-header"
>
<div
class=
"page-header"
>
<h1><i
class=
"fa fa-{{icon}}"
></i>
<h1><i
class=
"fa fa-{{icon}}"
></i>
{{ object.instance.name }}:
{{ object.instance.name }}: {{object.readable_name|get_text:user}}
{% if user.is_superuser %}
{{object.readable_name.get_admin_text}}
{% else %}
{{object.readable_name.get_user_text}}
{% endif %}
</h1>
</h1>
</div>
</div>
<div
class=
"row"
>
<div
class=
"row"
>
...
@@ -58,7 +54,7 @@
...
@@ -58,7 +54,7 @@
<dt>
{% trans "result" %}
</dt>
<dt>
{% trans "result" %}
</dt>
<dd><textarea
class=
"form-control"
>
{
% if user.is_superuser %}{{object.result.get_admin_text}}{% else %}{{object.result.get_user_text}}{% endif %
}
</textarea></dd>
<dd><textarea
class=
"form-control"
>
{
{object.result|get_text:user}
}
</textarea></dd>
<dt>
{% trans "resultant state" %}
</dt>
<dt>
{% trans "resultant state" %}
</dt>
<dd>
{{object.resultant_state|default:'n/a'}}
</dd>
<dd>
{{object.resultant_state|default:'n/a'}}
</dd>
...
...
circle/dashboard/templates/dashboard/lease-create.html
View file @
15d3d135
...
@@ -11,7 +11,7 @@
...
@@ -11,7 +11,7 @@
<div
class=
"panel panel-default"
>
<div
class=
"panel panel-default"
>
<div
class=
"panel-heading"
>
<div
class=
"panel-heading"
>
<a
class=
"pull-right btn btn-default btn-xs"
href=
"{% url "
dashboard
.
views
.
template-list
"
%}"
>
{% trans "Back" %}
</a>
<a
class=
"pull-right btn btn-default btn-xs"
href=
"{% url "
dashboard
.
views
.
template-list
"
%}"
>
{% trans "Back" %}
</a>
<h3
class=
"no-margin"
><i
class=
"fa fa-
time
"
></i>
{% trans "Create lease" %}
</h3>
<h3
class=
"no-margin"
><i
class=
"fa fa-
clock-o
"
></i>
{% trans "Create lease" %}
</h3>
</div>
</div>
<div
class=
"panel-body"
>
<div
class=
"panel-body"
>
{% with form=form %}
{% with form=form %}
...
...
circle/dashboard/templates/dashboard/lease-edit.html
View file @
15d3d135
...
@@ -10,7 +10,7 @@
...
@@ -10,7 +10,7 @@
<div
class=
"panel panel-default"
>
<div
class=
"panel panel-default"
>
<div
class=
"panel-heading"
>
<div
class=
"panel-heading"
>
<a
class=
"pull-right btn btn-default btn-xs"
href=
"{% url "
dashboard
.
views
.
template-list
"
%}"
>
{% trans "Back" %}
</a>
<a
class=
"pull-right btn btn-default btn-xs"
href=
"{% url "
dashboard
.
views
.
template-list
"
%}"
>
{% trans "Back" %}
</a>
<h3
class=
"no-margin"
><i
class=
"fa fa-
time
"
></i>
{% trans "Edit lease" %}
</h3>
<h3
class=
"no-margin"
><i
class=
"fa fa-
clock-o
"
></i>
{% trans "Edit lease" %}
</h3>
</div>
</div>
<div
class=
"panel-body"
>
<div
class=
"panel-body"
>
{% with form=form %}