--- a/pyforge/pyforge/ext/admin/templates/admin_index.html
+++ b/pyforge/pyforge/ext/admin/templates/project_overview.html
@@ -1,4 +1,4 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:py="http://genshi.edgewall.org/"
@@ -11,394 +11,125 @@
<head>
<meta content="text/html; charset=UTF-8" http-equiv="content-type" py:replace="''"/>
- <title>Project Admin for $c.project.shortname</title>
+ <title>Project Overview for $c.project.shortname</title>
- <py:def function="role_select(name)">
- <select name="$name">
- <option py:for="r in c.project.roles"
- value="$r._id">${r.display()}</option>
- </select>
- </py:def>
<link rel="stylesheet" type="text/css" media="screen" href="${g.app_static('css/admin.css')}"/>
</head>
-
+
<body>
- <h1 class="title">Project Admin</h1>
+ <h1 class="title">Project Overview for $c.project.shortname</h1>
<div py:if="c.project.deleted" class="notice">This project has been deleted and is not visible to non-admin users</div>
- <div id="project_admin_tabs">
- <ul>
- <li><a href="#project-admin-overview">Overview</a></li>
- <li py:if="len(c.project.neighborhood_invitations)"><a href="#project-admin-invitations">Neighborhood Invitation(s)</a></li>
- <li><a href="#project-admin-tools">Tools/Subprojects</a></li>
- <li><a href="#project-admin-permissions"
- py:if="has_project_access('security')()">Permissions</a></li>
- <li><a href="#project-admin-roles"
- py:if="c.project.is_root and has_project_access('security')()">Roles</a></li>
- </ul>
- <div id="project-admin-invitations" py:if="len(c.project.neighborhood_invitations)">
- <form method="POST" action="join_neighborhood">
- <select name="nid">
- <option py:if="c.project.neighborhood.name != 'Projects'" value="">
- Leave $c.project.neighborhood.name</option>
- <option py:for="n in h.make_neighborhoods(c.project.neighborhood_invitations)"
- value="$n._id">$n.name</option>
+ <div py:if="not has_project_access('update')()">
+ <div class="span-3 clear"><label>Name</label></div>
+ <div class="span-15 last">$c.project.name</div>
+ <hr class="clear clearfix" />
+ <div class="span-3 clear"><label>Category</label></div>
+ <div class="span-15 last">${c.project.category and c.project.category.label or 'Uncategorized'}</div>
+ <hr class="clear clearfix" />
+ <div class="span-3 clear"><label>Icon</label></div>
+ <div class="span-15 last">
+ <img py:if="c.project.icon" src="${c.project.url()}/icon"/>
+ <span py:if="not c.project.icon"> </span>
+ </div>
+ <hr class="clear clearfix" />
+ <div class="span-3 clear"><label>Summary</label></div>
+ <div class="span-15 last"><pre>$c.project.short_description</pre></div>
+ <hr class="clear clearfix" />
+ <div class="span-3 clear"><label>Description</label></div>
+ <div class="span-15 last">${Markup(c.project.description_html)}</div>
+ <hr class="clear clearfix" />
+ <div class="span-3 clear"><label>Screenshots</label></div>
+ <div class="span-15 last">
+ <py:if test="len(c.project.get_screenshots())">
+ <a py:for="ss in c.project.get_screenshots()" href="${c.project.url()}screenshot/$ss.filename"><img src="${c.project.url()}screenshot/$ss.filename/thumb" style="margin-right: 1em"/></a>
+ </py:if>
+ <py:if test="not len(c.project.get_screenshots())">No screenshots have been created.</py:if>
+ </div>
+ </div>
+ <form py:if="has_project_access('update')()" method="POST" action="update" enctype="multipart/form-data">
+ <div class="span-3"><label>Name:</label></div>
+ <div class="editable viewing span-13 last">
+ <div class="viewer">$c.project.name</div>
+ <div class="editor"><input name="name" value="$c.project.name"/></div>
+ </div>
+ <hr class="clear clearfix" />
+
+ <div class="span-3"><label>Shortname:</label></div>
+ <div class="span-13 last fakeinput">$c.project.shortname</div>
+ <hr class="clear clearfix" />
+
+ <div class="span-3"><label>Category:</label></div>
+ <div class="editable viewing span-13 last">
+ <div class="viewer">${c.project.category and c.project.category.label or 'Uncategorized'}</div>
+ <div class="editor">
+ <select name="category">
+ <option value="">Uncategorized</option>
+ <py:for each="cat in categories">
+ <option value="$cat._id" py:if="c.project.category and c.project.category._id == cat._id" selected="selected">$cat.label</option>
+ <option value="$cat._id" py:if="not c.project.category or (c.project.category and c.project.category._id != cat._id)">$cat.label</option>
+ <py:for each="subcat in cat.subcategories">
+ <option value="$subcat._id" py:if="c.project.category and c.project.category._id == subcat._id" selected="selected">-- $subcat.label</option>
+ <option value="$subcat._id" py:if="not c.project.category or (c.project.category and c.project.category._id != subcat._id)">-- $subcat.label</option>
+ </py:for>
+ </py:for>
</select>
- <input type="submit" value="Join Neighborhood" class="ui-state-default ui-button ui-button-text"/>
- </form>
- </div>
- <div id="project-admin-overview" style="overflow: auto">
- <div py:if="not has_project_access('update')()">
- <div class="span-3 clear"><label>Name</label></div>
- <div class="span-15 last">$c.project.name</div>
- <hr class="clear clearfix" />
- <div class="span-3 clear"><label>Category</label></div>
- <div class="span-15 last">${c.project.category and c.project.category.label or 'Uncategorized'}</div>
- <hr class="clear clearfix" />
- <div class="span-3 clear"><label>Icon</label></div>
- <div class="span-15 last">
- <img py:if="c.project.icon" src="${c.project.url()}/icon"/>
- <span py:if="not c.project.icon"> </span>
- </div>
- <hr class="clear clearfix" />
- <div class="span-3 clear"><label>Summary</label></div>
- <div class="span-15 last"><pre>$c.project.short_description</pre></div>
- <hr class="clear clearfix" />
- <div class="span-3 clear"><label>Description</label></div>
- <div class="span-15 last">${Markup(c.project.description_html)}</div>
- <hr class="clear clearfix" />
- <div class="span-3 clear"><label>Screenshots</label></div>
- <div class="span-15 last">
- <py:if test="len(c.project.get_screenshots())">
- <a py:for="ss in c.project.get_screenshots()" href="${c.project.url()}screenshot/$ss.filename"><img src="${c.project.url()}screenshot/$ss.filename/thumb" style="margin-right: 1em"/></a>
- </py:if>
- <py:if test="not len(c.project.get_screenshots())">No screenshots have been created.</py:if>
- </div>
- </div>
- <form py:if="has_project_access('update')()" method="POST" action="update" enctype="multipart/form-data">
- <div class="span-3"><label>Name:</label></div>
- <div class="editable viewing span-13 last">
- <div class="viewer">$c.project.name</div>
- <div class="editor"><input name="name" value="$c.project.name"/></div>
- </div>
- <hr class="clear clearfix" />
-
- <div class="span-3"><label>Shortname:</label></div>
- <div class="span-13 last fakeinput">$c.project.shortname</div>
- <hr class="clear clearfix" />
-
- <div class="span-3"><label>Category:</label></div>
- <div class="editable viewing span-13 last">
- <div class="viewer">${c.project.category and c.project.category.label or 'Uncategorized'}</div>
- <div class="editor">
- <select name="category">
- <option value="">Uncategorized</option>
- <py:for each="cat in categories">
- <option value="$cat._id" py:if="c.project.category and c.project.category._id == cat._id" selected="selected">$cat.label</option>
- <option value="$cat._id" py:if="not c.project.category or (c.project.category and c.project.category._id != cat._id)">$cat.label</option>
- <py:for each="subcat in cat.subcategories">
- <option value="$subcat._id" py:if="c.project.category and c.project.category._id == subcat._id" selected="selected">-- $subcat.label</option>
- <option value="$subcat._id" py:if="not c.project.category or (c.project.category and c.project.category._id != subcat._id)">-- $subcat.label</option>
- </py:for>
- </py:for>
- </select>
- </div>
- </div>
- <hr class="clear clearfix" />
-
- <div class="span-3"><label>Icon:</label></div>
- <div class="editable viewing span-13 last">
- <div class="viewer" py:if="c.project.icon"><img src="${c.project.url()}/icon"/></div>
- <div class="viewer" py:if="not c.project.icon">No icon has been created.</div>
- <div class="editor">${file_field('icon', 'File')}</div>
- </div>
- <div class="push-3 span-13 last" py:if="c.project.icon">
- <input type="submit" name="delete_icon" value="Delete Icon"
- class="ui-state-default ui-button ui-button-text clear clearfix"/>
- </div>
- <hr class="clear clearfix" />
-
- <div class="span-3"><label>Summary:</label></div>
- <div class="editable viewing span-13 last">
- <div class="viewer"><pre>$c.project.short_description</pre></div>
- <div class="editor"><textarea name="short_description">$c.project.short_description</textarea></div>
- </div>
- <hr class="clear clearfix" />
-
- <div class="span-3"><label>Description:</label></div>
- <div class="span-13 last">${c.markdown_editor.display(name='description',value=c.project.description)}</div>
- <hr class="clear clearfix" />
-
- <div class="span-3"><label>Tags:</label></div>
- <div class="editable viewing span-13 last">
- <div class="viewer">${len(c.project.labels) and ', '.join(c.project.labels) or "No Tags"}</div>
- <div class="editor">${c.label_edit.display(name='labels',value=c.project.labels)}</div>
- </div>
- <hr class="clear clearfix" />
-
- <div class="span-3"><label>Screenshots:</label></div>
- <div class="editable viewing span-13 last">
- <div class="viewer">
- <py:if test="len(c.project.get_screenshots())">
- <a py:for="ss in c.project.get_screenshots()" href="${c.project.url()}screenshot/$ss.filename"><img src="${c.project.url()}screenshot/$ss.filename/thumb" style="margin-right: 1em"/></a>
- </py:if>
- <py:if test="not len(c.project.get_screenshots())">No screenshots have been created.</py:if>
- </div>
- <div class="editor">${file_field('screenshot', 'File')}</div>
- </div>
- <hr class="clear clearfix" />
-
- <div class="push-3 span-15 last">
- <input type="submit" value="Save"
- class="ui-state-default ui-button ui-button-text"/>
- <input type="submit" value="Delete Project" name="delete"
- class="ui-state-default ui-button ui-button-text"
- py:if="not c.project.deleted"/>
- <input type="submit" value="Undelete Project" name="undelete"
- class="ui-state-default ui-button ui-button-text"
- py:if="c.project.deleted"/>
- </div>
- </form>
- </div>
- <div id="project-admin-tools">
- <div>
- <table>
- <thead>
- <tr>
- <th>Type</th>
- <th>Mount Point</th>
- <th py:if="has_project_access('tool')()">Edit</th>
- <th py:if="has_project_access('tool')()"></th>
- </tr>
- </thead>
- <tbody>
- <form method="POST" action="update_mounts" id="mounts_edit">
- <input py:for="i, sp in enumerate(c.project.direct_subprojects)"
- type="hidden"
- name="subproject-${i}.shortname"
- value="$sp.shortname"/>
- <input py:for="i, config in enumerate(c.project.app_configs)"
- type="hidden"
- name="tool-${i}.mount_point"
- value="$config.options.mount_point"/>
- <tr py:for="i, sp in enumerate(c.project.direct_subprojects)">
- <td>Subproject</td>
- <td>$sp.shortname</td>
- <td py:if="has_project_access('tool')()"><a href="${sp.url() + 'admin/'}">
- <span class="ui-icon ui-icon-pencil"></span> Edit
- </a></td>
- <td class="tool-delete">
- <a py:if="has_project_access('tool')()"
- class="subproject-${i}" href="#">
- <span class="ui-icon ui-icon-close"></span> Delete
- </a>
- </td>
- </tr>
- <tr py:for="i, config in enumerate(c.project.app_configs)">
- <td>Tool: $config.tool_name</td>
- <td>$config.options.mount_point</td>
- <td>
- <a py:if="has_project_access('tool')()"
- href="$config.options.mount_point/">
- <span class="ui-icon ui-icon-pencil"></span> Edit
- </a>
- </td>
- <td class="tool-delete">
- <a py:if="has_project_access('tool')() and config.load().installable"
- class="tool-${i}" href="#">
- <span class="ui-icon ui-icon-close"></span> Delete
- </a>
- <!-- <input py:if="has_project_access('tool')() and config.load().installable"
- name="tool-${i}.delete" type="submit" value="Delete"
- class="ui-state-default ui-button ui-button-text"/> -->
- </td>
- </tr>
- </form>
- <form method="POST" action="update_mounts">
- <input py:for="i, sp in enumerate(c.project.direct_subprojects)"
- type="hidden"
- name="subproject-${i}.shortname"
- value="$sp.shortname"/>
- <input py:for="i, config in enumerate(c.project.app_configs)"
- type="hidden"
- name="tool-${i}.mount_point"
- value="$config.options.mount_point"/>
- <tr py:if="has_project_access('tool')()">
- <td>
- <select name="new.ep_name" class="new_ep_name">
- <option value="">New Subproject</option>
- <optgroup label="New Tool">
- <option py:for="name in installable_tool_names" value="$name">$name</option>
- </optgroup>
- </select>
- </td>
- <td>
- <input name="new.mount_point" class="title"/>
- </td>
- <td colspan="2">
- <input type="submit" value="Install" name="new.install" class="ui-state-default ui-button ui-button-text"/>
- </td>
- </tr>
- </form>
- </tbody>
- </table>
</div>
</div>
- <div id="project-admin-permissions"
- py:if="has_project_access('security')()">
- <p>The project ACL determines project-level permissions.</p>
- <div id="acl-admin">
- <py:for each="permission, role_ids in c.project.acl.iteritems()">
- <h3><a href="#" id="permission_$permission">Permission: $permission</a></h3>
- <div>
- <form method="POST" action="update_acl">
- <input type="hidden" name="permission" value="$permission"/>
- <input py:for="i,rid in enumerate(role_ids)"
- type="hidden" name="role-${i}.id" value="$rid"/>
- <table>
- <thead>
- <tr><th>Role</th><th>Username</th><th/></tr>
- </thead>
- <tbody>
- <tr py:for="i, r in enumerate(h.make_roles(role_ids))">
- <td>${r.display()}</td>
- <td>${r.user._id and r.user.username or ''}</td>
- <td><input type="submit" value="Remove" name="role-${i}.delete" class="ui-state-default ui-button ui-button-text" /></td>
- </tr>
- <tr>
- <td>
- <select name="new.id">
- <option value="">User</option>
- <optgroup label="Existing role">
- <option py:for="r in c.project.roles"
- value="$r._id">${r.display()}</option>
- </optgroup>
- </select>
- </td>
- <td>
- <input name="new.username" class="title"/>
- </td>
- <td>
- <input type="submit" name="new.add" value="Add Permission" class="ui-state-default ui-button ui-button-text"/>
- </td>
- </tr>
- </tbody>
- </table>
- </form>
- </div>
- </py:for>
+ <hr class="clear clearfix" />
+
+ <div class="span-3"><label>Icon:</label></div>
+ <div class="editable viewing span-13 last">
+ <div class="viewer" py:if="c.project.icon"><img src="${c.project.url()}/icon"/></div>
+ <div class="viewer" py:if="not c.project.icon">No icon has been created.</div>
+ <div class="editor">${file_field('icon', 'File')}</div>
+ </div>
+ <div class="push-3 span-13 last" py:if="c.project.icon">
+ <input type="submit" name="delete_icon" value="Delete Icon"
+ class="ui-state-default ui-button ui-button-text clear clearfix"/>
+ </div>
+ <hr class="clear clearfix" />
+
+ <div class="span-3"><label>Summary:</label></div>
+ <div class="editable viewing span-13 last">
+ <div class="viewer"><pre>$c.project.short_description</pre></div>
+ <div class="editor"><textarea name="short_description">$c.project.short_description</textarea></div>
+ </div>
+ <hr class="clear clearfix" />
+
+ <div class="span-3"><label>Description:</label></div>
+ <div class="span-13 last">${c.markdown_editor.display(name='description',value=c.project.description)}</div>
+ <hr class="clear clearfix" />
+
+ <div class="span-3"><label>Tags:</label></div>
+ <div class="editable viewing span-13 last">
+ <div class="viewer">${len(c.project.labels) and ', '.join(c.project.labels) or "No Tags"}</div>
+ <div class="editor">${c.label_edit.display(name='labels',value=c.project.labels)}</div>
+ </div>
+ <hr class="clear clearfix" />
+
+ <div class="span-3"><label>Screenshots:</label></div>
+ <div class="editable viewing span-13 last">
+ <div class="viewer">
+ <py:if test="len(c.project.get_screenshots())">
+ <a py:for="ss in c.project.get_screenshots()" href="${c.project.url()}screenshot/$ss.filename"><img src="${c.project.url()}screenshot/$ss.filename/thumb" style="margin-right: 1em"/></a>
+ </py:if>
+ <py:if test="not len(c.project.get_screenshots())">No screenshots have been created.</py:if>
</div>
+ <div class="editor">${file_field('screenshot', 'File')}</div>
</div>
- <div id="project-admin-roles" py:if="c.project.is_root and has_project_access('security')()">
- <div class="content">
- <p>
- Each user on the project has a private role.
- Each role can have subroles. A role inherits all the permissions
- that its subroles have. All users who have read access should
- automatically appear here.
- </p>
- <form method="POST" action="update_roles" id="roles_form">
- <input py:for="i,r in enumerate(c.project.roles)"
- type="hidden"
- name="role-${i}.id"
- value="$r._id"/>
- <table>
- <thead>
- <tr>
- <th>User</th>
- <th>Roles</th>
- <th>Edit</th>
- <th/>
- </tr>
- </thead>
- <tbody>
- <tr py:for="i, r in enumerate(c.project.roles)" class="${i%2 and 'even' or ''}">
- <td>${r.display()}</td>
- <td>
- <span py:for="j, sr in enumerate(h.make_roles(r.roles))" class="removable">
- ${sr.display()}
- <input type="hidden" name="role-${i}.subroles-${j}.id" value="$sr._id"/>
- <!-- <input type="submit" name="role-${i}.subroles-${j}.delete" value="Del"/> -->
- </span>
- </td>
- <td>
- Acts as
- <select name="role-${i}.new.id" style="width: 100px" class="add_role">
- <option value=""> </option>
- <option py:for="r in roles" py:if="not r.special" value="$r._id">
- ${r.display()}
- </option>
- </select>
- <input py:if="not r.special" name="role-${i}.delete" type="submit" value="Delete"
- class="ui-state-default ui-button ui-button-text"/>
- </td>
- </tr>
- <tr>
- <td><input name="new.name" class="title"/></td>
- <td colspan="3">
- <input type="submit" name="new.add" value="Create Role"
- class="ui-state-default ui-button ui-button-text"/>
- </td>
- </tr>
- </tbody>
- </table>
- </form>
- </div>
+ <hr class="clear clearfix" />
+
+ <div class="push-3 span-15 last">
+ <input type="submit" value="Save"
+ class="ui-state-default ui-button ui-button-text"/>
+ <input type="submit" value="Delete Project" name="delete"
+ class="ui-state-default ui-button ui-button-text"
+ py:if="not c.project.deleted"/>
+ <input type="submit" value="Undelete Project" name="undelete"
+ class="ui-state-default ui-button ui-button-text"
+ py:if="c.project.deleted"/>
</div>
- </div>
- <script type="text/javascript">
- /*<![CDATA[*/
- $(function() {
- $("#project_admin_tabs").tabs({cookie:{expires:30}});
- });
- $(function() {
- $("#acl-admin").accordion({
- autoHeight: false,
- navigation: true,
- change: function(event,ui) {
- var hid = ui.newHeader.children('a').attr('id');
- if (hid === undefined) {
- $.cookie('project-acl-admin', null);
- } else {
- $.cookie('project-acl-admin', hid, { path: '/', expires: 2 });
- }
- }
- });
- });
- $(document).ready(function(){
- if($.cookie('project-acl-admin')) {
- $('#acl-admin').accordion('option', 'animated', false)
- .accordion('activate', $('#' + $.cookie('project-acl-admin')).parent('h3'))
- .accordion('option', 'animated', 'slide');
- }
- });
- $('.new_ep_name').change(function() {
- $(this).closest('tr').find('.new_mount_point').val($(this).val().toLowerCase());
- });
- $('span.removable').click(function(e){
- var vals = $('#roles_form').serialize();
- var del_name = $('input', this)[0].name.replace('.id','.delete');
- $.post($('#roles_form')[0].action, vals+'&'+del_name+'=Del', function(){
- e.target.parentNode.removeChild(e.target);
- });
- });
- $('select.add_role').change(function(e){
- var vals = $('#roles_form').serialize();
- var add_name = e.target.name.replace('.id','.add');
- $.post($('#roles_form')[0].action, vals+'&'+add_name+'=Add', function(){
- window.location.reload();
- });
- });
- $('td.tool-delete a').click(function(e){
- var vals = $('#mounts_edit').serialize();
- var del_name = e.target.className+'.delete';
- $.post($('#mounts_edit')[0].action, vals+'&'+del_name+'=Del', function(){
- window.location.reload();
- });
- return false;
- });
- /*]]>*/
- </script>
- <script type="text/javascript" src="${g.app_static('js/admin.js')}"/>
+ </form>
</body>
</html>