Skip to content
Toggle navigation
P
Projects
G
Groups
S
Snippets
Help
Gelencsér Szabolcs
/
circlestack
This project
Loading...
Sign in
Toggle navigation
Go to a project
Project
Repository
Issues
0
Merge Requests
0
Pipelines
Wiki
Snippets
Members
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Commit
a304c0e4
authored
Aug 29, 2014
by
Kálmán Viktor
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
dashboard: reworked template list
parent
aea321fc
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
106 additions
and
68 deletions
+106
-68
circle/dashboard/forms.py
+19
-0
circle/dashboard/static/dashboard/template-list.js
+1
-0
circle/dashboard/tables.py
+9
-9
circle/dashboard/templates/dashboard/_display-name.html
+1
-5
circle/dashboard/templates/dashboard/template-list/column-template-created.html
+3
-0
circle/dashboard/templates/dashboard/template-list/column-template-owner.html
+1
-1
circle/dashboard/templates/dashboard/template-list/column-template-resources.html
+9
-0
circle/dashboard/views.py
+63
-53
No files found.
circle/dashboard/forms.py
View file @
a304c0e4
...
...
@@ -1184,3 +1184,22 @@ class VmListSearchForm(forms.Form):
data
=
self
.
data
.
copy
()
data
[
'stype'
]
=
"all"
self
.
data
=
data
class
TemplateListSearchForm
(
forms
.
Form
):
s
=
forms
.
CharField
(
widget
=
forms
.
TextInput
(
attrs
=
{
'class'
:
"form-control input-tags"
,
'placeholder'
:
_
(
"Search..."
)
}))
stype
=
forms
.
ChoiceField
(
vm_search_choices
,
widget
=
forms
.
Select
(
attrs
=
{
'class'
:
"btn btn-default input-tags"
,
}))
def
__init__
(
self
,
*
args
,
**
kwargs
):
super
(
TemplateListSearchForm
,
self
)
.
__init__
(
*
args
,
**
kwargs
)
# set initial value, otherwise it would be overwritten by request.GET
if
not
self
.
data
.
get
(
"stype"
):
data
=
self
.
data
.
copy
()
data
[
'stype'
]
=
"all"
self
.
data
=
data
circle/dashboard/static/dashboard/template-list.js
View file @
a304c0e4
...
...
@@ -39,6 +39,7 @@ $(function() {
$
(
".template-list-table thead th"
).
css
(
"cursor"
,
"pointer"
);
$
(
".template-list-table th a"
).
on
(
"click"
,
function
(
event
)
{
if
(
!
$
(
this
).
closest
(
"th"
).
data
(
"sort"
))
return
true
;
event
.
preventDefault
();
});
});
...
...
circle/dashboard/tables.py
View file @
a304c0e4
...
...
@@ -146,13 +146,10 @@ class TemplateListTable(Table):
template_name
=
"dashboard/template-list/column-template-name.html"
,
attrs
=
{
'th'
:
{
'data-sort'
:
"string"
}}
)
num_cores
=
Column
(
verbose_name
=
_
(
"Cores"
),
attrs
=
{
'th'
:
{
'data-sort'
:
"int"
}}
)
ram_size
=
TemplateColumn
(
"{{ record.ram_size }} MiB"
,
resources
=
TemplateColumn
(
template_name
=
"dashboard/template-list/column-template-resources.html"
,
attrs
=
{
'th'
:
{
'data-sort'
:
"int"
}},
order_by
=
(
"ram_size"
),
)
lease
=
TemplateColumn
(
"{{ record.lease.name }}"
,
...
...
@@ -170,11 +167,14 @@ class TemplateListTable(Table):
verbose_name
=
_
(
"Owner"
),
attrs
=
{
'th'
:
{
'data-sort'
:
"string"
}}
)
created
=
TemplateColumn
(
template_name
=
"dashboard/template-list/column-template-created.html"
,
verbose_name
=
_
(
"Created at"
),
)
running
=
TemplateColumn
(
template_name
=
"dashboard/template-list/column-template-running.html"
,
verbose_name
=
_
(
"Running"
),
attrs
=
{
'th'
:
{
'data-sort'
:
"int"
}},
orderable
=
False
,
)
actions
=
TemplateColumn
(
verbose_name
=
_
(
"Actions"
),
...
...
@@ -187,8 +187,8 @@ class TemplateListTable(Table):
model
=
InstanceTemplate
attrs
=
{
'class'
:
(
'table table-bordered table-striped table-hover'
' template-list-table'
)}
fields
=
(
'name'
,
'
num_cores'
,
'ram_size'
,
'system
'
,
'
access_method'
,
'lease'
,
'owner
'
,
'running'
,
'actions'
,
)
fields
=
(
'name'
,
'
resources'
,
'system'
,
'access_method'
,
'lease
'
,
'
owner'
,
'created
'
,
'running'
,
'actions'
,
)
prefix
=
"template-"
...
...
circle/dashboard/templates/dashboard/_display-name.html
View file @
a304c0e4
{% load i18n %}
{% if user and user.pk %}
{% if user.get_full_name %}
{{ user.get_full_name }}
{% else %}
{{ user.username }}
{% endif %}
{% if user.get_full_name %}{{ user.get_full_name }}{% else %}{{ user.username }}{% endif %}{% if new_line %}
<br
/>
{% endif %}
{% if show_org %}
{% if user.profile and user.profile.org_id %}
...
...
circle/dashboard/templates/dashboard/template-list/column-template-created.html
0 → 100644
View file @
a304c0e4
{{ record.created|date }}
<br
/>
{{ record.created|time }}
circle/dashboard/templates/dashboard/template-list/column-template-owner.html
View file @
a304c0e4
{% include "dashboard/_display-name.html" with user=record.owner show_org=True %}
{% include "dashboard/_display-name.html" with user=record.owner show_org=True
new_line=True
%}
circle/dashboard/templates/dashboard/template-list/column-template-resources.html
0 → 100644
View file @
a304c0e4
{% load i18n %}
{{ record.ram_size }}MiB RAM
<br
/>
{% blocktrans with num_cores=record.num_cores count count=record.num_cores %}
{{ num_cores }} CPU core
{% plural %}
{{ num_cores }} CPU cores
{% endblocktrans %}
circle/dashboard/views.py
View file @
a304c0e4
...
...
@@ -70,7 +70,8 @@ from .forms import (
VmSaveForm
,
UserKeyForm
,
VmRenewForm
,
VmStateChangeForm
,
CirclePasswordChangeForm
,
VmCreateDiskForm
,
VmDownloadDiskForm
,
TraitsForm
,
RawDataForm
,
GroupPermissionForm
,
AclUserAddForm
,
VmResourcesForm
,
VmAddInterfaceForm
,
VmListSearchForm
VmResourcesForm
,
VmAddInterfaceForm
,
VmListSearchForm
,
TemplateListSearchForm
,
)
from
.tables
import
(
...
...
@@ -169,6 +170,52 @@ class FilterMixin(object):
return
super
(
FilterMixin
,
self
)
.
get_queryset
()
.
filter
(
**
self
.
get_queryset_filters
())
def
create_fake_get
(
self
):
"""
Updates the request's GET dict to filter the vm list
For example: "name:xy node:1" updates the GET dict
to resemble this URL ?name=xy&node=1
"name:xy node:1".split(":") becomes ["name", "xy node", "1"]
we pop the the first element and use it as the first dict key
then we iterate over the rest of the list and split by the last
whitespace, the first part of this list will be the previous key's
value, then last part of the list will be the next key.
The final dict looks like this: {'name': xy, 'node':1}
"""
s
=
self
.
request
.
GET
.
get
(
"s"
)
if
s
:
s
=
s
.
split
(
":"
)
if
len
(
s
)
<
2
:
# if there is no ':' in the string, filter by name
got
=
{
'name'
:
s
[
0
]}
else
:
latest
=
s
.
pop
(
0
)
got
=
{
'
%
s'
%
latest
:
None
}
for
i
in
s
[:
-
1
]:
new
=
i
.
rsplit
(
" "
,
1
)
got
[
latest
]
=
new
[
0
]
latest
=
new
[
1
]
if
len
(
new
)
>
1
else
None
got
[
latest
]
=
s
[
-
1
]
# generate a new GET request, that is kinda fake
fake
=
self
.
request
.
GET
.
copy
()
for
k
,
v
in
got
.
iteritems
():
fake
[
k
]
=
v
self
.
request
.
GET
=
fake
def
create_acl_queryset
(
self
,
model
):
cleaned_data
=
self
.
search_form
.
cleaned_data
stype
=
cleaned_data
.
get
(
'stype'
,
"all"
)
superuser
=
stype
==
"all"
shared
=
stype
==
"shared"
level
=
"owner"
if
stype
==
"owned"
else
"user"
queryset
=
model
.
get_objects_with_level
(
level
,
self
.
request
.
user
,
group_also
=
shared
,
disregard_superuser
=
not
superuser
,
)
return
queryset
class
IndexView
(
LoginRequiredMixin
,
TemplateView
):
template_name
=
"dashboard/index.html"
...
...
@@ -1517,7 +1564,7 @@ class TemplateDetail(LoginRequiredMixin, SuccessMessageMixin, UpdateView):
return
kwargs
class
TemplateList
(
LoginRequiredMixin
,
SingleTableView
):
class
TemplateList
(
LoginRequiredMixin
,
FilterMixin
,
SingleTableView
):
template_name
=
"dashboard/template-list.html"
model
=
InstanceTemplate
table_class
=
TemplateListTable
...
...
@@ -1525,15 +1572,24 @@ class TemplateList(LoginRequiredMixin, SingleTableView):
def
get_context_data
(
self
,
*
args
,
**
kwargs
):
context
=
super
(
TemplateList
,
self
)
.
get_context_data
(
*
args
,
**
kwargs
)
context
[
'lease_table'
]
=
LeaseListTable
(
Lease
.
objects
.
all
(),
request
=
self
.
request
)
context
[
'lease_table'
]
=
LeaseListTable
(
Lease
.
get_objects_with_level
(
"user"
,
self
.
request
.
user
),
request
=
self
.
request
)
context
[
'search_form'
]
=
self
.
search_form
return
context
def
get
(
self
,
*
args
,
**
kwargs
):
self
.
search_form
=
TemplateListSearchForm
(
self
.
request
.
GET
)
self
.
search_form
.
full_clean
()
return
super
(
TemplateList
,
self
)
.
get
(
*
args
,
**
kwargs
)
def
get_queryset
(
self
):
logger
.
debug
(
'TemplateList.get_queryset() called. User:
%
s'
,
unicode
(
self
.
request
.
user
))
return
InstanceTemplate
.
get_objects_with_level
(
'user'
,
self
.
request
.
user
)
.
all
(
)
queryset
=
self
.
create_acl_queryset
(
InstanceTemplate
)
return
queryset
.
annotate
(
running
=
Count
(
'instance_set'
)
)
class
TemplateDelete
(
LoginRequiredMixin
,
DeleteView
):
...
...
@@ -1611,7 +1667,7 @@ class VmList(LoginRequiredMixin, FilterMixin, ListView):
def
get_queryset
(
self
):
logger
.
debug
(
'VmList.get_queryset() called. User:
%
s'
,
unicode
(
self
.
request
.
user
))
queryset
=
self
.
create_
default_queryset
(
)
queryset
=
self
.
create_
acl_queryset
(
Instance
)
.
filter
(
destroyed_at
=
None
)
self
.
create_fake_get
()
sort
=
self
.
request
.
GET
.
get
(
"sort"
)
...
...
@@ -1626,52 +1682,6 @@ class VmList(LoginRequiredMixin, FilterMixin, ListView):
**
self
.
get_queryset_filters
())
.
select_related
(
'owner'
,
'node'
)
.
distinct
()
def
create_default_queryset
(
self
):
cleaned_data
=
self
.
search_form
.
cleaned_data
stype
=
cleaned_data
.
get
(
'stype'
,
"all"
)
superuser
=
stype
==
"all"
shared
=
stype
==
"shared"
level
=
"owner"
if
stype
==
"owned"
else
"user"
queryset
=
Instance
.
get_objects_with_level
(
level
,
self
.
request
.
user
,
group_also
=
shared
,
disregard_superuser
=
not
superuser
,
)
.
filter
(
destroyed_at
=
None
)
return
queryset
def
create_fake_get
(
self
):
"""
Updates the request's GET dict to filter the vm list
For example: "name:xy node:1" updates the GET dict
to resemble this URL ?name=xy&node=1
"name:xy node:1".split(":") becomes ["name", "xy node", "1"]
we pop the the first element and use it as the first dict key
then we iterate over the rest of the list and split by the last
whitespace, the first part of this list will be the previous key's
value, then last part of the list will be the next key.
The final dict looks like this: {'name': xy, 'node':1}
"""
s
=
self
.
request
.
GET
.
get
(
"s"
)
if
s
:
s
=
s
.
split
(
":"
)
if
len
(
s
)
<
2
:
# if there is no ':' in the string, filter by name
got
=
{
'name'
:
s
[
0
]}
else
:
latest
=
s
.
pop
(
0
)
got
=
{
'
%
s'
%
latest
:
None
}
for
i
in
s
[:
-
1
]:
new
=
i
.
rsplit
(
" "
,
1
)
got
[
latest
]
=
new
[
0
]
latest
=
new
[
1
]
if
len
(
new
)
>
1
else
None
got
[
latest
]
=
s
[
-
1
]
# generate a new GET request, that is kinda fake
fake
=
self
.
request
.
GET
.
copy
()
for
k
,
v
in
got
.
iteritems
():
fake
[
k
]
=
v
self
.
request
.
GET
=
fake
class
NodeList
(
LoginRequiredMixin
,
SuperuserRequiredMixin
,
SingleTableView
):
template_name
=
"dashboard/node-list.html"
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment