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
db31f971
authored
Sep 01, 2014
by
Kálmán Viktor
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'master' into custom-connect-command
Conflicts: circle/dashboard/static/dashboard/dashboard.css
parents
d0ae4fc4
4268ac9d
Expand all
Show whitespace changes
Inline
Side-by-side
Showing
37 changed files
with
656 additions
and
420 deletions
+656
-420
circle/circle/settings/base.py
+3
-3
circle/common/models.py
+36
-4
circle/common/operations.py
+25
-8
circle/dashboard/forms.py
+35
-15
circle/dashboard/static/dashboard/dashboard.css
+72
-0
circle/dashboard/static/dashboard/dashboard.js
+8
-3
circle/dashboard/static/dashboard/group-list.js
+0
-126
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
+4
-3
circle/dashboard/templates/dashboard/_vm-create-2.html
+3
-1
circle/dashboard/templates/dashboard/_vm-mass-migrate.html
+36
-0
circle/dashboard/templates/dashboard/group-list.html
+3
-42
circle/dashboard/templates/dashboard/group-list/column-actions.html
+5
-1
circle/dashboard/templates/dashboard/index-nodes.html
+4
-2
circle/dashboard/templates/dashboard/index-vm.html
+6
-4
circle/dashboard/templates/dashboard/instanceactivity_detail.html
+4
-8
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
+6
-6
circle/dashboard/templates/dashboard/vm-detail/_operations.html
+1
-1
circle/dashboard/templates/dashboard/vm-list.html
+30
-27
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
+13
-6
circle/vm/models/instance.py
+16
-1
circle/vm/models/node.py
+1
-1
circle/vm/operations.py
+37
-37
No files found.
circle/circle/settings/base.py
View file @
db31f971
...
@@ -368,9 +368,9 @@ if get_env_variable('DJANGO_SAML', 'FALSE') == 'TRUE':
...
@@ -368,9 +368,9 @@ if get_env_variable('DJANGO_SAML', 'FALSE') == 'TRUE':
from
shutilwhich
import
which
from
shutilwhich
import
which
from
saml2
import
BINDING_HTTP_POST
,
BINDING_HTTP_REDIRECT
from
saml2
import
BINDING_HTTP_POST
,
BINDING_HTTP_REDIRECT
# INSTALLED_APPS += ( # needed only for testing djangosaml2
INSTALLED_APPS
+=
(
# 'djangosaml
',
'djangosaml2
'
,
#
)
)
AUTHENTICATION_BACKENDS
=
(
AUTHENTICATION_BACKENDS
=
(
'django.contrib.auth.backends.ModelBackend'
,
'django.contrib.auth.backends.ModelBackend'
,
'djangosaml2.backends.Saml2Backend'
,
'djangosaml2.backends.Saml2Backend'
,
...
...
circle/common/models.py
View file @
db31f971
...
@@ -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 @
db31f971
...
@@ -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/forms.py
View file @
db31f971
...
@@ -636,12 +636,8 @@ class LeaseForm(forms.ModelForm):
...
@@ -636,12 +636,8 @@ class LeaseForm(forms.ModelForm):
Field
(
'name'
),
Field
(
'name'
),
Field
(
"suspend_interval_seconds"
,
type
=
"hidden"
,
value
=
"0"
),
Field
(
"suspend_interval_seconds"
,
type
=
"hidden"
,
value
=
"0"
),
Field
(
"delete_interval_seconds"
,
type
=
"hidden"
,
value
=
"0"
),
Field
(
"delete_interval_seconds"
,
type
=
"hidden"
,
value
=
"0"
),
HTML
(
string_concat
(
"<label>"
,
_
(
"Suspend in"
),
"</label>"
)),
Div
(
Div
(
Div
(
HTML
(
_
(
"Suspend in"
)),
css_class
=
"input-group-addon"
,
style
=
"width: 100px;"
,
),
NumberField
(
"suspend_hours"
,
css_class
=
"form-control"
),
NumberField
(
"suspend_hours"
,
css_class
=
"form-control"
),
Div
(
Div
(
HTML
(
_
(
"hours"
)),
HTML
(
_
(
"hours"
)),
...
@@ -664,12 +660,8 @@ class LeaseForm(forms.ModelForm):
...
@@ -664,12 +660,8 @@ class LeaseForm(forms.ModelForm):
),
),
css_class
=
"input-group interval-input"
,
css_class
=
"input-group interval-input"
,
),
),
HTML
(
string_concat
(
"<label>"
,
_
(
"Delete in"
),
"</label>"
)),
Div
(
Div
(
Div
(
HTML
(
_
(
"Delete in"
)),
css_class
=
"input-group-addon"
,
style
=
"width: 100px;"
,
),
NumberField
(
"delete_hours"
,
css_class
=
"form-control"
),
NumberField
(
"delete_hours"
,
css_class
=
"form-control"
),
Div
(
Div
(
HTML
(
_
(
"hours"
)),
HTML
(
_
(
"hours"
)),
...
@@ -693,7 +685,7 @@ class LeaseForm(forms.ModelForm):
...
@@ -693,7 +685,7 @@ class LeaseForm(forms.ModelForm):
css_class
=
"input-group interval-input"
,
css_class
=
"input-group interval-input"
,
)
)
)
)
helper
.
add_input
(
Submit
(
"submit"
,
"Save changes"
))
helper
.
add_input
(
Submit
(
"submit"
,
_
(
"Save changes"
)
))
return
helper
return
helper
class
Meta
:
class
Meta
:
...
@@ -705,6 +697,8 @@ class VmRenewForm(forms.Form):
...
@@ -705,6 +697,8 @@ class VmRenewForm(forms.Form):
force
=
forms
.
BooleanField
(
required
=
False
,
label
=
_
(
force
=
forms
.
BooleanField
(
required
=
False
,
label
=
_
(
"Set expiration times even if they are shorter than "
"Set expiration times even if they are shorter than "
"the current value."
))
"the current value."
))
save
=
forms
.
BooleanField
(
required
=
False
,
label
=
_
(
"Save selected lease."
))
def
__init__
(
self
,
*
args
,
**
kwargs
):
def
__init__
(
self
,
*
args
,
**
kwargs
):
choices
=
kwargs
.
pop
(
'choices'
)
choices
=
kwargs
.
pop
(
'choices'
)
...
@@ -716,6 +710,32 @@ class VmRenewForm(forms.Form):
...
@@ -716,6 +710,32 @@ class VmRenewForm(forms.Form):
empty_label
=
None
,
label
=
_
(
'Length'
)))
empty_label
=
None
,
label
=
_
(
'Length'
)))
if
len
(
choices
)
<
2
:
if
len
(
choices
)
<
2
:
self
.
fields
[
'lease'
]
.
widget
=
HiddenInput
()
self
.
fields
[
'lease'
]
.
widget
=
HiddenInput
()
self
.
fields
[
'save'
]
.
widget
=
HiddenInput
()
@property
def
helper
(
self
):
helper
=
FormHelper
(
self
)
helper
.
form_tag
=
False
return
helper
class
VmStateChangeForm
(
forms
.
Form
):
interrupt
=
forms
.
BooleanField
(
required
=
False
,
label
=
_
(
"Forcibly interrupt all running activities."
),
help_text
=
_
(
"Set all activities to finished state, "
"but don't interrupt any tasks."
))
new_state
=
forms
.
ChoiceField
(
Instance
.
STATUS
,
label
=
_
(
"New status"
))
def
__init__
(
self
,
*
args
,
**
kwargs
):
show_interrupt
=
kwargs
.
pop
(
'show_interrupt'
)
status
=
kwargs
.
pop
(
'status'
)
super
(
VmStateChangeForm
,
self
)
.
__init__
(
*
args
,
**
kwargs
)
if
not
show_interrupt
:
self
.
fields
[
'interrupt'
]
.
widget
=
HiddenInput
()
self
.
fields
[
'new_state'
]
.
initial
=
status
@property
@property
def
helper
(
self
):
def
helper
(
self
):
...
@@ -1164,9 +1184,9 @@ class VmResourcesForm(forms.ModelForm):
...
@@ -1164,9 +1184,9 @@ class VmResourcesForm(forms.ModelForm):
vm_search_choices
=
(
vm_search_choices
=
(
(
0
,
_
(
"owned"
)),
(
"owned"
,
_
(
"owned"
)),
(
1
,
_
(
"shared"
)),
(
"shared"
,
_
(
"shared"
)),
(
2
,
_
(
"all"
)),
(
"all"
,
_
(
"all"
)),
)
)
...
@@ -1185,5 +1205,5 @@ class VmListSearchForm(forms.Form):
...
@@ -1185,5 +1205,5 @@ class VmListSearchForm(forms.Form):
# set initial value, otherwise it would be overwritten by request.GET
# set initial value, otherwise it would be overwritten by request.GET
if
not
self
.
data
.
get
(
"stype"
):
if
not
self
.
data
.
get
(
"stype"
):
data
=
self
.
data
.
copy
()
data
=
self
.
data
.
copy
()
data
[
'stype'
]
=
2
data
[
'stype'
]
=
"all"
self
.
data
=
data
self
.
data
=
data
circle/dashboard/static/dashboard/dashboard.css
View file @
db31f971
...
@@ -874,3 +874,75 @@ textarea[name="list-new-namelist"] {
...
@@ -874,3 +874,75 @@ textarea[name="list-new-namelist"] {
text-align
:
center
;
text-align
:
center
;
vertical-align
:
middle
;
vertical-align
:
middle
;
}
}
#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 @
db31f971
...
@@ -262,7 +262,7 @@ $(function () {
...
@@ -262,7 +262,7 @@ $(function () {
$
(
"#dashboard-vm-search-form"
).
submit
(
function
()
{
$
(
"#dashboard-vm-search-form"
).
submit
(
function
()
{
var
vm_list_items
=
$
(
"#dashboard-vm-list .list-group-item"
);
var
vm_list_items
=
$
(
"#dashboard-vm-list .list-group-item"
);
if
(
vm_list_items
.
length
==
1
)
{
if
(
vm_list_items
.
length
==
1
&&
vm_list_items
.
first
().
prop
(
"href"
)
)
{
window
.
location
.
href
=
vm_list_items
.
first
().
prop
(
"href"
);
window
.
location
.
href
=
vm_list_items
.
first
().
prop
(
"href"
);
return
false
;
return
false
;
}
}
...
@@ -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/group-list.js
View file @
db31f971
var
ctrlDown
,
shiftDown
=
false
;
var
ctrlKey
=
17
;
var
shiftKey
=
16
;
var
selected
=
[];
$
(
function
()
{
$
(
function
()
{
$
(
document
).
keydown
(
function
(
e
)
{
if
(
e
.
keyCode
==
ctrlKey
)
ctrlDown
=
true
;
if
(
e
.
keyCode
==
shiftKey
)
shiftDown
=
true
;
}).
keyup
(
function
(
e
)
{
if
(
e
.
keyCode
==
ctrlKey
)
ctrlDown
=
false
;
if
(
e
.
keyCode
==
shiftKey
)
shiftDown
=
false
;
});
$
(
'.group-list-table tbody'
).
find
(
'tr'
).
mousedown
(
function
()
{
var
retval
=
true
;
if
(
ctrlDown
)
{
setRowColor
(
$
(
this
));
if
(
!
$
(
this
).
hasClass
(
'group-list-selected'
))
{
selected
.
splice
(
selected
.
indexOf
(
$
(
this
).
index
()),
1
);
}
else
{
selected
.
push
(
$
(
this
).
index
());
}
retval
=
false
;
}
else
if
(
shiftDown
)
{
if
(
selected
.
length
>
0
)
{
start
=
selected
[
selected
.
length
-
1
]
+
1
;
end
=
$
(
this
).
index
();
if
(
start
>
end
)
{
var
tmp
=
start
-
1
;
start
=
end
;
end
=
tmp
-
1
;
}
for
(
var
i
=
start
;
i
<=
end
;
i
++
)
{
if
(
selected
.
indexOf
(
i
)
<
0
)
{
selected
.
push
(
i
);
setRowColor
(
$
(
'.group-list-table tbody tr'
).
eq
(
i
));
}
}
}
retval
=
false
;
}
else
{
$
(
'.group-list-selected'
).
removeClass
(
'group-list-selected'
);
$
(
this
).
addClass
(
'group-list-selected'
);
selected
=
[
$
(
this
).
index
()];
}
// reset btn disables
$
(
'.group-list-table tbody tr .btn'
).
attr
(
'disabled'
,
false
);
// show/hide group controls
if
(
selected
.
length
>
1
)
{
$
(
'.group-list-group-control a'
).
attr
(
'disabled'
,
false
);
for
(
var
i
=
0
;
i
<
selected
.
length
;
i
++
)
{
$
(
'.group-list-table tbody tr'
).
eq
(
selected
[
i
]).
find
(
'.btn'
).
attr
(
'disabled'
,
true
);
}
}
else
{
$
(
'.group-list-group-control a'
).
attr
(
'disabled'
,
true
);
}
return
retval
;
});
$
(
'#group-list-group-migrate'
).
click
(
function
()
{
console
.
log
(
collectIds
(
selected
));
});
$
(
'tbody a'
).
mousedown
(
function
(
e
)
{
// parent tr doesn't get selected when clicked
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 */
/* rename */
$
(
"#group-list-rename-button, .group-details-rename-button"
).
click
(
function
()
{
$
(
"#group-list-rename-button, .group-details-rename-button"
).
click
(
function
()
{
$
(
"#group-list-column-name"
,
$
(
this
).
closest
(
"tr"
)).
hide
();
$
(
"#group-list-column-name"
,
$
(
this
).
closest
(
"tr"
)).
hide
();
...
@@ -113,51 +34,4 @@ $(function() {
...
@@ -113,51 +34,4 @@ $(function() {
return
false
;
return
false
;
});
});
/* group actions */
/* select all */
$
(
'#group-list-group-select-all'
).
click
(
function
()
{
$
(
'.group-list-table tbody tr'
).
each
(
function
()
{
var
index
=
$
(
this
).
index
();
if
(
selected
.
indexOf
(
index
)
<
0
)
{
selected
.
push
(
index
);
$
(
this
).
addClass
(
'group-list-selected'
);
}
});
if
(
selected
.
length
>
0
)
$
(
'.group-list-group-control a'
).
attr
(
'disabled'
,
false
);
return
false
;
});
/* mass vm delete */
$
(
'#group-list-group-delete'
).
click
(
function
()
{
addModalConfirmation
(
massDeleteVm
,
{
'url'
:
'/dashboard/group/mass-delete/'
,
'data'
:
{
'selected'
:
selected
,
'v'
:
collectIds
(
selected
)
}
}
);
return
false
;
});
});
});
function
collectIds
(
rows
)
{
var
ids
=
[];
for
(
var
i
=
0
;
i
<
rows
.
length
;
i
++
)
{
var
div
=
$
(
'td:first-child div'
,
$
(
'.group-list-table tbody tr'
).
eq
(
rows
[
i
]));
ids
.
push
(
div
.
prop
(
'id'
).
replace
(
'node-'
,
''
));
}
return
ids
;
}
function
setRowColor
(
row
)
{
if
(
!
row
.
hasClass
(
'group-list-selected'
))
{
row
.
addClass
(
'group-list-selected'
);
}
else
{
row
.
removeClass
(
'group-list-selected'
);
}
}
circle/dashboard/static/dashboard/vm-create.js
View file @
db31f971
...
@@ -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 @
db31f971
...
@@ -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() {