Project import generated by Copybara.

GitOrigin-RevId: d9e9e3fb4e31372ec1fb43b178994ca78fa8fe70
diff --git a/templates/project/people-add-members-form.ezt b/templates/project/people-add-members-form.ezt
new file mode 100644
index 0000000..f013a0a
--- /dev/null
+++ b/templates/project/people-add-members-form.ezt
@@ -0,0 +1,103 @@
+
+[if-any offer_membership_editing]
+<br>
+<div class="h4" style="margin-bottom:4px" id="addmembers">Add Members</div>
+
+<div id="makechanges" class="closed">
+
+  <div class="ifClosed">
+   <textarea id="tempt" rows="4" style="color:#666; width:500px; margin-left:4px"
+    >Enter new member email addresses</textarea>
+  </div>
+
+
+<table class="ifOpened vt" cellspacing="2" cellpadding="2" style="margin-top:0">
+  <tr>
+   <td colspan="2">
+      <textarea name="addmembers" style="width:500px" rows="4"
+                id="addMembersTextArea">[initial_add_members]</textarea>
+     [if-any errors.addmembers]
+      <div class="fielderror">[errors.addmembers]</div>
+     [end]<br>
+   </td>
+   <td rowspan="3">
+       <div class="tip" style="margin-top:0; margin-left:4px">
+           Enter the email addresses of users that you would like to
+           add to this [is arg0 "project"]project[else]
+	   [is arg0 "hotlist"]hotlist.
+	   <strong>You can also add group lists to give every member of the group permission to edit this hotlist</strong>
+	   [else]group[end][end].<br><br>
+           Each email address must correspond to a Google Account when in use.
+       </div>
+    </td>
+   </tr>
+
+  <tr>
+    <th width="30" align="left">Role:</th>
+
+    <td width="470" align="left">
+    [is arg0 "project"]
+       <input type="radio" name="role" value="owner" id="owner">
+       <label for="owner">Owner: may make any change to this
+       project.</label><br>
+
+       <input type="radio" name="role" value="committer" id="committer"
+              checked="checked">
+       <label for="committer">Committer: may work in the project, but may
+       not reconfigure it.</label><br>
+
+       <input type="radio" name="role" value="contributor" id="contributor">
+       <label for="contributor">Contributor: starts with the same permissions
+       as non-members.</label><br>
+       [# TODO(jrobbins): custom roles]
+    [else][is arg0 "hotlist"]
+       <input type="radio" name="role" value="editor" id="editor"
+              checked="checked">
+       <label for="editor">Editor: may add/remove/rank issues.</label><br>
+       [if-any errors.incorrect_email_input]
+       <div class="fielderror">[errors.incorrect_email_input]</div>
+       [end]
+    [else]
+       <input type="radio" name="role" value="owner" id="owner">
+       <label for="owner">Owner: may make any change to this
+       group.</label><br>
+
+       <input type="radio" name="role" value="member" id="member"
+              checked="checked">
+       <label for="member">Member: member of this user group.</label><br>
+    [end][end]
+    </td>
+
+    </tr>
+    <tr>
+     <td colspan="2">
+      <input type="submit" name="addbtn" id="addbtn"
+             value="Save changes" style="margin-top:1em">
+     </td>
+    </tr>
+</table>
+
+</div>
+
+
+<script type="text/javascript" nonce="[nonce]">
+runOnLoad(function() {
+  window._openAddMembersForm = function _openAddMembersForm() {
+    document.location.hash='addmembers';
+    document.getElementById('makechanges').className = "opened";
+    window.setTimeout(
+        function () { document.getElementById('addMembersTextArea').focus(); },
+        100);
+  }
+
+  [if-any initially_expand_form]
+    _openAddMembersForm();
+  [end]
+
+  if ($("tempt"))
+    $("tempt").addEventListener("mousedown", _openAddMembersForm);
+
+});
+</script>
+
+[end]
diff --git a/templates/project/people-detail-page.ezt b/templates/project/people-detail-page.ezt
new file mode 100644
index 0000000..fda3e96
--- /dev/null
+++ b/templates/project/people-detail-page.ezt
@@ -0,0 +1,186 @@
+[define category_css]css/ph_detail.css[end]
+[include "../framework/header.ezt" "showtabs"]
+
+<a href="list">&lsaquo; Back to people list</a>
+
+<form action="detail.do" method="POST" id="peopledetail">
+<input type="hidden" name="token" value="[form_token]">
+<input type="hidden" name="u" value="[member.user.user_id]">
+<table cellspacing="8" class="rowmajor vt">
+<tr>
+ <th width="1%">User:</th>
+ <td>[include "../framework/user-link.ezt" member.user]</td>
+</tr>
+
+ <tr class="[if-any expand_perms]opened[else]closed[end]">
+ <th>Role:</th>
+ <td>
+   [# Show a widget if the current user is allowed to edit roles.]
+   [if-any perms.EditProject]
+     [define offer_role_select]Yes[end]
+   [else]
+     [define offer_role_select]No[end]
+   [end]
+   [# But, don't offer it if the user could remove themselves as the last owner.]
+   [is total_num_owners "1"][if-any warn_abandonment]
+     [define offer_role_select]No[end]
+   [end][end]
+
+   [is offer_role_select "Yes"]
+     <select name="role">
+       <option [is member.role "Owner"]selected="selected"[end]
+               value="owner">Owner</option>
+       <option [is member.role "Committer"]selected="selected"[end]
+               value="committer">Committer</option>
+       <option [is member.role "Contributor"]selected="selected"[end]
+               value="contributor">Contributor</option>
+     </select>
+   [else]
+     [member.role]
+   [end]
+   <a class="ifClosed toggleHidden" href="#" id="show_permissions"
+      style="font-size:90%; margin-left:1em">Show permissions</a>
+   <a class="ifOpened toggleHidden" href="#" id="hide_permissions"
+      style="font-size:90%; margin-left:1em">Hide permissions</a>
+   [include "people-detail-perms-part.ezt"]
+ </td>
+ <td>
+   <div class="ifOpened tip" style="width:17em">
+      <b>Permissions</b> enable members to perform specific actions in
+      a project.  Appropriate permissions are already defined for each
+      role: Owner, Committer, and Contributor.  Additional permissions can
+      be granted to individual members, if needed.
+
+      <p>Most project owners will never need to grant any individual
+      member permissions.  It is usually more important to describe
+      each member's duties in the notes.</p>
+
+      <div style="margin-top:.5em">
+        <a href="https://chromium.googlesource.com/infra/infra/+/main/appengine/monorail/doc/userguide/working-with-issues.md#Who-can-view-an-issue" target="new">Learn more</a>
+        <a href="http://code.google.com/p/monorail/wiki/Permissions" target="new"><img src="/static/images/tearoff_icon.gif" width="16" height="16"></a>
+      </div>
+   </div>
+ </td>
+</tr>
+
+
+<tr>
+ <th>Notes:</th>
+ <td>
+  [if-any offer_edit_member_notes]
+   <div style="width:40em">
+    <textarea style="width:100%" rows="4" class="ifExpand" name="notes"
+              >[member.notes]</textarea>
+   </div>
+  [else]
+   [if-any member.notes][member.notes][else]----[end]
+  [end]
+
+ </td>
+</tr>
+
+<tr>
+ <th>Autocomplete:</th>
+ <td>
+    [if-any perms.EditProject]
+      [define disable_checkbox]No[end]
+    [else]
+      [define disable_checkbox]Yes[end]
+    [end]
+    [if-any member.is_service_account]
+      [define disable_checkbox]Yes[end]
+    [end]
+     <div>
+       <input type="checkbox" name="ac_include" id="ac_include"
+            [if-any member.is_service_account][else]
+              [if-any member.ac_include]checked[end]
+            [end]
+            [is disable_checkbox "Yes"]disabled[end]
+            value="[member.user.user_id]"
+            >
+       <label for="ac_include">Include this member in autocomplete menus</label>
+     </div>
+     [if-any member.is_service_account]
+       <div>(service account is excluded by default)</div>
+     [end]
+
+     [if-any member.is_group]
+       <div>
+         <input type="checkbox" name="ac_expand" id="ac_expand"
+              [if-any member.ac_expand]checked[end]
+              [is disable_checkbox "Yes"]disabled[end]
+              value="[member.user.user_id]"
+              >
+         <label for="ac_expand">Expand this user group in autocomplete menus</label>
+       </div>
+     [else]
+       <input type="hidden" name="ac_expand" value="[member.user.user_id]">
+     [end]
+
+ </td>
+</tr>
+
+[if-any read_only]
+   <tr>
+     <th></th>
+     <td>
+       [include "../framework/read-only-rejection.ezt"]
+     </td>
+   </tr>
+[else]
+  [if-any offer_edit_perms offer_edit_member_notes]
+   <tr>
+     <th></th>
+     <td>
+      <input type="submit" name="submit" value="Save changes">
+      [if-any offer_remove_role]
+        <input type="submit" class="secondary" name="remove" value="Remove member"
+               id="remove_member">
+      [end]
+     </td>
+   </tr>
+  [end]
+[end]
+
+</table>
+</form>
+
+
+<script type="text/javascript" nonce="[nonce]">
+runOnLoad(function() {
+ function _confirmRemove() {
+  [if-any warn_abandonment]
+    [is total_num_owners "1"]
+      alert('You cannot remove the last project owner.');
+      return false;
+    [else]
+      return confirm('Remove yourself?\nYou will be locked out of making further changes.');
+    [end]
+  [else]
+    return confirm('Remove member [format "js"][member.user.email][end]?');
+  [end]
+ }
+
+ if ($("remove_member"))
+   $("remove_member").addEventListener("click", function(event) {
+      if (!_confirmRemove())
+        event.preventDefault();
+   });
+
+ [if-any read_only][else]
+   if ($("show_permissions"))
+     $("show_permissions").addEventListener("click", function() {
+        window.prpcClient.call(
+            'monorail.Users', 'SetExpandPermsPreference', {expandPerms: true});
+     });
+   if ($("hide_permissions"))
+     $("hide_permissions").addEventListener("click", function() {
+        window.prpcClient.call(
+            'monorail.Users', 'SetExpandPermsPreference', {expandPerms: false});
+     });
+ [end]
+
+});
+</script>
+
+[include "../framework/footer.ezt"]
diff --git a/templates/project/people-detail-perms-part.ezt b/templates/project/people-detail-perms-part.ezt
new file mode 100644
index 0000000..3a30417
--- /dev/null
+++ b/templates/project/people-detail-perms-part.ezt
@@ -0,0 +1,82 @@
+<table id="perm_defs" class="ifOpened">
+ [if-any offer_edit_perms displayed_extra_perms]
+  <tr><th colspan="2">Standard permissions</th></tr>
+ [end]
+
+ [include "people-detail-row-part.ezt" role_perms.View member_perms.View "View" "View issues"]
+ [include "people-detail-row-part.ezt" role_perms.Commit member_perms.Commit "Commit" "Full project member"]
+
+ [include "people-detail-row-part.ezt" role_perms.CreateIssue member_perms.CreateIssue "CreateIssue" "Enter a new issue"]
+ [include "people-detail-row-part.ezt" role_perms.AddIssueComment member_perms.AddIssueComment "AddIssueComment" "Add a comment to an issue"]
+ [include "people-detail-row-part.ezt" role_perms.EditIssue member_perms.EditIssue "EditIssue" "Edit any attribute of an issue"]
+ [include "people-detail-row-part.ezt" role_perms.EditIssueOwner member_perms.EditIssueOwner "EditIssueOwner" "- Edit the owner of an issue"]
+ [include "people-detail-row-part.ezt" role_perms.EditIssueSummary member_perms.EditIssueSummary "EditIssueSummary" "- Edit the summary of an issue"]
+ [include "people-detail-row-part.ezt" role_perms.EditIssueStatus member_perms.EditIssueStatus "EditIssueStatus" "- Edit the status of an issue"]
+ [include "people-detail-row-part.ezt" role_perms.EditIssueCc member_perms.EditIssueCc "EditIssueCc" "- Edit the CC list of an issue"]
+ [include "people-detail-row-part.ezt" role_perms.DeleteIssue member_perms.DeleteIssue "DeleteIssue" "Delete/undelete an issue"]
+
+ [include "people-detail-row-part.ezt" role_perms.DeleteAny member_perms.DeleteAny "DeleteAny" "Delete comments by anyone"]
+ [include "people-detail-row-part.ezt" role_perms.EditAnyMemberNotes member_perms.EditAnyMemberNotes "EditAnyMemberNotes" "Edit anyone's member notes"]
+ [include "people-detail-row-part.ezt" role_perms.ModerateSpam member_perms.ModerateSpam "ModerateSpam" "Mark or un-mark issues and comments as spam"]
+
+
+
+ [if-any offer_edit_perms displayed_extra_perms]
+  <tr><th colspan="2">Custom permissions</th></tr>
+ [end]
+
+ [if-any offer_edit_perms]
+  <tr>
+   <td id="displayed_extra_perms" colspan="2">
+   <div style="width:12em">
+    [for displayed_extra_perms]
+        <input style="width:100%" name="extra_perms"
+               value="[displayed_extra_perms]">
+    [end]
+     <input style="width:100%" name="extra_perms"
+            id="first_extra_perms"
+            value="" autocomplete="off">
+   </div>
+   </td>
+  </tr>
+ [else]
+   [for displayed_extra_perms]
+    <tr>
+     <td>
+      <input type="checkbox" checked="checked" disabled="disabled">
+      [displayed_extra_perms]
+     </td>
+     <td></td>
+    </tr>
+   [end]
+ [end]
+
+</table>
+
+<script type="text/javascript" nonce="[nonce]">
+runOnLoad(function() {
+  function _addInput(event) {
+    if (event.target.value == "") {
+      return;
+    }
+    var area = event.target.parentNode;
+    var newInput = document.createElement("input");
+    newInput.style.width = "100%";
+    newInput.name = event.target.name;
+    newInput.onfocus = function(e) {
+        _acrob(null);
+        _acof(e);
+    };
+    newInput.setAttribute("autocomplete", "off");
+    newInput.addEventListener("keyup", _addInput);
+    area.appendChild(newInput);
+    area.appendChild(document.createElement("br"));
+
+    // Make it only fire once.
+    event.target.removeEventListener("keyup", _addInput);
+  }
+
+  if ($("first_extra_perms"))
+    $("first_extra_perms").addEventListener("keyup", _addInput);
+});
+</script>
diff --git a/templates/project/people-detail-row-part.ezt b/templates/project/people-detail-row-part.ezt
new file mode 100644
index 0000000..785005f
--- /dev/null
+++ b/templates/project/people-detail-row-part.ezt
@@ -0,0 +1,29 @@
+[#  Display one row in the permissions table.
+
+Args:
+  arg0: True if the permission is native to the role. So, it cannot be removed.
+  arg1: True if the user has this permission. So, it will be shown when not in editing mode.
+  arg2: Permission name.
+  arg3: Permission description.
+
+References globals:
+  offer_edit_perms: True if the user can edit permissions on this page.
+]
+
+<tr>
+ <td>
+   <input type="checkbox" [if-any arg1]checked="checked"[end] id="[arg2]"
+    [if-any offer_edit_perms]
+      [if-any arg0]
+       disabled="disabled"
+      [else]
+       name="extra_perms" value="[arg2]"
+      [end]
+    [else]
+      disabled="disabled"
+    [end]
+    >
+  <label for="[arg2]">[arg2]</label>
+ </td>
+ <td>[arg3]</td>
+</tr>
diff --git a/templates/project/people-list-page.ezt b/templates/project/people-list-page.ezt
new file mode 100644
index 0000000..f3756e8
--- /dev/null
+++ b/templates/project/people-list-page.ezt
@@ -0,0 +1,197 @@
+[define title]People[end]
+[define category_css]css/ph_list.css[end]
+[if-any is_hotlist][define category2_css]css/ph_detail.css[end][end]
+[include "../framework/header.ezt" "hidetabs"]
+[include "../framework/js-placeholders.ezt"]
+
+<form method="POST" action=[if-any is_hotlist]"people.do"[else]"list.do"[end] id="membership_form">
+<input type="hidden" name="token" value="[form_token]">
+[if-any newly_added_views]
+  <br/>
+  The following new members were successfully added:
+  <br/>
+  [for newly_added_views]
+    <a href="[newly_added_views.detail_url]">[newly_added_views.user.display_name]</a> ([newly_added_views.role])
+    <br/>
+  [end]
+  <br/>
+[end]
+
+<div id="colcontrol">
+   <div class="list">
+     [if-any pagination.visible]
+       <div class="pagination">
+         [if-any pagination.prev_url]<a href="[pagination.prev_url]"><b>&lsaquo;</b> Prev</a>[end]
+         Members [pagination.start] - [pagination.last] of [pagination.total_count]
+         [if-any pagination.next_url]<a href="[pagination.next_url]">Next <b>&rsaquo;</b></a>[end]
+       </div>
+     [end]
+
+     <h4 style="display: inline">[if-any is_hotlist]Hotlist[else]Project[end] People</h4>
+
+     [if-any read_only][else]
+       [if-any offer_membership_editing]
+        <input type="button" value="Add members"
+               id="add_members_button" class="primary">
+        <input type="submit" value="Remove members"
+               id="removebtn" class="secondary" name="removebtn" disabled="disabled">
+        [# TOOD(jrobbins): extra confirmation when removing yourself as owner.]
+        [if-any is_hotlist]
+          <a id="transfer-ownership" class="buttonify">Transfer ownership</a>
+          [include "../features/transfer-hotlist-form.ezt"]
+        [end]
+       [end]
+       [if-any is_hotlist]
+        [if-any offer_remove_self]
+         <a id="remove-self" class="buttonify">Remove myself</a>
+         [include "../features/remove-self-hotlist-form.ezt"]
+        [end]
+       [end]
+     [end]
+   </div>
+
+  <table cellspacing="0" cellpadding="2" border="0" class="results striped vt" id="resultstable" width="100%">
+  <tbody>
+   [if-any pagination.visible_results]
+
+      <tr id="headingrow">
+       [if-any offer_membership_editing]
+         <th style="border-right:0; padding-right:2px">&nbsp;</th>
+       [end]
+
+       <th style="white-space:nowrap">Name</th>
+       <th style="white-space:nowrap">Role</th>
+       [if-any is_hotlist]
+       [else]
+       <th style="white-space:nowrap">Autocomplete</th>
+       <th style="white-space:nowrap">Notes</th>
+       [end]
+      </tr>
+
+      [for pagination.visible_results]
+       [if-any is_hotlist]
+         [include "people-list-row-part.ezt" "hotlist"]
+       [else]
+        [include "people-list-row-part.ezt" "project"]
+       [end]
+      [end]
+
+   [else]
+    <tr>
+     <td colspan="40" class="id">
+      <div style="padding: 3em; text-align: center">
+       This [if-any is_hotlist]hotlist[else]project[end] does not have any members.
+      </div>
+     </td>
+    </tr>
+   [end]
+
+
+  </tbody>
+  </table>
+  <div class="list-foot">
+    <div class="pagination">
+    [if-any pagination.prev_url]<a href="[pagination.prev_url]"><b>&lsaquo;</b> Prev</a>[end]
+    [pagination.start] - [pagination.last] of [pagination.total_count]
+    [if-any pagination.next_url]<a href="[pagination.next_url]">Next <b>&rsaquo;</b></a>[end]
+    </div>
+  </div>
+</div>
+
+[if-any untrusted_user_groups]
+  <div style="width:45em">
+    [include "untrusted-user-groups-part.ezt"]
+  </div>
+[end]
+
+[if-any read_only][else]
+  [if-any is_hotlist]
+  [include "people-add-members-form.ezt" "hotlist"]
+  [else]
+  [include "people-add-members-form.ezt" "project"]
+  [end]
+  [# TODO(jojwang): make more elegant later, just one line]
+[end]
+
+</form>
+
+[if-any offer_membership_editing]
+  <script type="text/javascript" nonce="[nonce]">
+runOnLoad(function() {
+    $("add_members_button").addEventListener("click", _openAddMembersForm);
+
+    function _countChecked(opt_className) {
+      var numChecked = 0;
+      var inputs = document.getElementsByTagName('input');
+      for (var i = 0; i < inputs.length; i++) {
+        var el = inputs[[]i];
+        if (el.type == 'checkbox' && el.name == 'remove' && el.checked &&
+            (!opt_className || opt_className == el.className)) {
+          numChecked++;
+        }
+      }
+      return numChecked;
+    }
+
+   function _enableRemoveButton() {
+     var removeButton = document.getElementById('removebtn');
+     if (_countChecked() > 0) {
+       removeButton.disabled = false;
+     } else {
+       removeButton.disabled = true;
+     }
+   }
+
+   setInterval(_enableRemoveButton, 700);
+
+   function _preventAbandonment(event) {
+      var meCheckbox = document.getElementById("me_checkbox");
+      if (meCheckbox && meCheckbox.checked) {
+        numOwnersChecked = _countChecked("owner");
+        if (numOwnersChecked == [total_num_owners]) {
+          alert("You cannot remove all project owners.");
+          event.preventDefault();
+        } else {
+          if (!confirm("Remove yourself as project owner?\n" +
+                       "You will be locked out of making further changes.")) {
+              event.preventDefault();
+          }
+        }
+      }
+      return true;
+   }
+   [if-any check_abandonment]
+     $("membership_form").addEventListener("submit", _preventAbandonment);
+   [end]
+
+   [if-any is_hotlist]
+   initializeDialogBox("[hotlist_id]");
+   [end]
+});
+  </script>
+[end]
+[if-any is_hotlist][if-any offer_remove_self]
+  <script type="text/javascript" nonce="[nonce]">
+  runOnLoad(function () {initializeDialogBoxRemoveSelf()});
+  </script>
+[end][end]
+
+<script type="text/javascript" nonce="[nonce]">
+runOnLoad(function() {
+  function _handleResultsClick(event) {
+    var target = event.target;
+    if (target.tagName == "A")
+      return;
+    if (target.classList.contains("rowwidgets") || target.parentNode.classList.contains("rowwidgets"))
+      return;
+    if (target.tagName != "TR") target = target.parentNode;
+    _go(target.attributes[[]"data-url"].value,
+        (event.metaKey || event.ctrlKey || event.button == 1));
+  };
+  _addClickListener($("resultstable"), _handleResultsClick);
+
+});
+</script>
+
+
+[include "../framework/footer.ezt"]
diff --git a/templates/project/people-list-row-part.ezt b/templates/project/people-list-row-part.ezt
new file mode 100644
index 0000000..f30eaf5
--- /dev/null
+++ b/templates/project/people-list-row-part.ezt
@@ -0,0 +1,62 @@
+[define detail_url][pagination.visible_results.detail_url][end]
+<tr data-url="[detail_url]">
+
+  [if-any offer_membership_editing]
+    [is arg0 "hotlist"][is pagination.visible_results.role "Owner"]
+    <td style="padding-right:2px" class="rowwidgets"></td>
+    [else]
+     <td style="padding-right:2px" class="rowwidgets">
+         <input type="checkbox" name="remove"
+                value="[pagination.visible_results.user.email]"
+                >
+     </td>
+    [end]
+    [else]
+     <td style="padding-right:2px" class="rowwidgets">
+         <input type="checkbox" name="remove"
+                [is pagination.visible_results.role "Owner"]class="owner"[end]
+                value="[pagination.visible_results.user.email]"
+                [if-any pagination.visible_results.viewing_self]
+                  id="me_checkbox"
+                [end]
+                >
+     </td>
+  [end][end]
+
+  <td style="white-space:nowrap; text-align:left;" class="id">
+     <a href="[detail_url]"
+      >[pagination.visible_results.user.display_name]</a>
+      [if-any pagination.visible_results.viewing_self]
+       <b>- me</b>
+      [end]
+  </td>
+
+  <td>
+    <a href="[detail_url]" style="white-space:nowrap">
+      [pagination.visible_results.role]<br>
+      [is arg0 "hotlist"][else]
+        [for pagination.visible_results.extra_perms]
+          <div style="font-size:90%">+ [pagination.visible_results.extra_perms]</div>
+        [end]
+      [end]
+    </a>
+  </td>
+
+  <td style="white-space:nowrap">
+    [is arg0 "hotlist"][else]
+      [if-any pagination.visible_results.is_service_account]
+        <a href="[detail_url]">Excluded</a>
+      [else][if-any pagination.visible_results.ac_include]
+        [# Nothing is displayed when the member is included.]
+      [else]
+        <a href="[detail_url]">Excluded</a>
+      [end][end]
+    [end]
+  </td>
+
+  [is arg0 "hotlist"][else]
+  <td width="90%">
+    <a href="[detail_url]">[pagination.visible_results.notes]</a>
+  </td>
+  [end]
+</tr>
diff --git a/templates/project/project-admin-advanced-page.ezt b/templates/project/project-admin-advanced-page.ezt
new file mode 100644
index 0000000..de91e40
--- /dev/null
+++ b/templates/project/project-admin-advanced-page.ezt
@@ -0,0 +1,11 @@
+[include "../framework/header.ezt" "showtabs"]
+
+ <form action="adminAdvanced.do" method="POST">
+  <input type="hidden" name="token" value="[form_token]">
+
+  [include "project-admin-publishing-part.ezt"]
+  [include "project-admin-quota-part.ezt"]
+
+ </form>
+
+[include "../framework/footer.ezt"]
diff --git a/templates/project/project-admin-page.ezt b/templates/project/project-admin-page.ezt
new file mode 100644
index 0000000..84c001f
--- /dev/null
+++ b/templates/project/project-admin-page.ezt
@@ -0,0 +1,134 @@
+[define category_css]css/ph_detail.css[end]
+[include "../framework/header.ezt" "showtabs"]
+
+[if-any read_only][include "../framework/read-only-rejection.ezt"]
+[else]
+
+ <form action="admin.do" method="POST" autocomplete="off" enctype="multipart/form-data">
+  <input type="hidden" name="token" value="[form_token]">
+
+<h4>Project metadata</h4>
+
+<div class="section">
+  [include "../framework/project-descriptive-fields.ezt"]
+</div>
+
+
+<h4>Project access</h4>
+
+<div class="section">
+  [if-any offer_access_level initial_access]
+    <br>This project may be viewed by:
+    [include "../framework/project-access-part.ezt" "dontchecksubmit"]<br>
+  [end]
+
+<div class="section">
+ <div class="closed">
+  <p>Restriction labels allow project members to restrict access to individual
+     issues.
+  <a class="ifClosed toggleHidden" href="#" style="font-size:90%; margin-left:.5em">Learn more</a></p>
+  <div class="ifOpened help">
+      Normally, if a project member may edit the labels, then they may also
+      edit restriction labels.  That allows project committers to adjust access
+      controls for the items that they are working on.  However, some project
+      owners may prefer that once a restriction label is in place, only a project
+      owner may remove it.
+  </div>
+ </div>
+ <input type="checkbox" name="only_owners_remove_restrictions"
+        id="only_owners_remove_restrictions"
+        [if-any only_owners_remove_restrictions]checked="checked"[end] >
+ <label for="only_owners_remove_restrictions">Only project owners
+  may remove <tt>Restrict-*</tt> labels</label>
+</div>
+
+<div class="section">
+ <div class="closed">
+  <p>Collaboration style
+  <a class="ifClosed toggleHidden" href="#" style="font-size:90%; margin-left:.5em">Learn more</a></p>
+  <div class="ifOpened help">
+      Project workspaces are usually intended to promote collaboration among
+      all project members.  However, sometimes a compartmentalized collaboration
+      style is more appropriate.  For example, one company might want to work
+      with several partners, but not let each partner know about the others.
+      Note: In such a project, all artifacts should have restriction labels.
+  </div>
+ </div>
+ <input type="checkbox" name="only_owners_see_contributors" id="only_owners_see_contributors"
+        [if-any only_owners_see_contributors]checked="checked"[end] >
+ <label for="only_owners_see_contributors">Only project owners may see the list of contributors.</label>
+</div>
+
+</div>
+
+
+<h4>Activity notifications</h4>
+
+<div class="section">
+  <p>Email notifications of issue tracker activity will automatically be sent to
+     the following email address.</p>
+
+   <table cellpadding="2">
+     <tr><th>All issue changes:</th>
+      <td><input type="email" name="issue_notify" size="35" value="[issue_notify]"><br>
+       [if-any errors.issue_notify]
+       <div class="fielderror">[errors.issue_notify]</div>
+       [end]
+      </td>
+     </tr>
+   </table>
+  [# TODO: validate as address is entered ]
+
+  [include "../framework/admin-email-sender-part.ezt"]
+
+ <div class="closed">
+  <p>Notification contents
+  <a class="ifClosed toggleHidden" href="#" style="font-size:90%; margin-left:.5em">Learn more</a></p>
+  <div class="ifOpened help">
+      By default, notifications content will be limited based on user preference,
+      Restrict-* labels, and their membership in a given project. This option
+      forces the full notification content to be sent regardless of other factors.
+  </div>
+ </div>
+ <input type="checkbox" name="issue_notify_always_detailed" id="issue_notify_always_detailed"
+        [if-any issue_notify_always_detailed]checked="checked"[end] >
+ <label for="issue_notify_always_detailed">Always send detailed notification content.</label>
+</div>
+
+
+<h4>Email reply processing</h4>
+
+<div class="section">
+ <div class="closed">
+  <p>Users may add comments and make updates by replying to
+   certain notification emails.
+  <a class="ifClosed toggleHidden" style="font-size:90%; margin-left:.5em">Learn more</a></p>
+  <div class="ifOpened help">
+      Users may add comments to an issue
+      by replying to a notification email:
+
+      <ul>
+       <li>Look for a note in the footer of the email indicating that
+           a reply will be processed by the server.</li>
+       <li>Comments must be in replies to notification emails sent directly
+           to the member, not through a mailing list.</li>
+       <li>The reply must be <tt>From:</tt> the same email address to which
+           the notification was sent.</li>
+       <li>Project members who have permission to edit issues may make
+           changes via email replies.</li>
+      </ul>
+  </div>
+ </div>
+ <input type="checkbox" name="process_inbound_email" id="process_inbound_email"
+        [if-any process_inbound_email]checked="checked"[end] >
+ <label for="process_inbound_email">Process email replies</label>
+</div>
+
+<br>
+
+  <input type="submit" id="savechanges" name="btn" value="Save changes" class="submit">
+ </form>
+
+[end]
+
+[include "../framework/footer.ezt"]
diff --git a/templates/project/project-admin-publishing-part.ezt b/templates/project/project-admin-publishing-part.ezt
new file mode 100644
index 0000000..bef52df
--- /dev/null
+++ b/templates/project/project-admin-publishing-part.ezt
@@ -0,0 +1,110 @@
+[# This is the "Project publishing options" on the "Advanced" subtab. ]
+
+<h4>Project state</h4>
+
+<div class="section">
+<table class="vt" cellspacing="20" style="width:60em">
+ [if-any offer_archive]
+ <tr>
+  <td>
+    <input type="submit" name="archivebtn" style="width:6em"
+           value="Archive">
+  </td>
+  <td>
+    Archive this project. It will only be visible read-only to
+    project members.  Once it is archived, you may unarchive it, or go ahead
+    and fully delete it.
+    <br><br>
+  </td>
+ </tr>
+ [end]
+
+ [if-any offer_delete]
+ <tr>
+  <td>
+    <input type="submit" name="deletebtn" style="width:6em"
+           value="Delete" id="delbtn">
+  </td>
+  <td>
+    Completely delete this project now.
+    <br><br>
+  </td>
+ </tr>
+ [end]
+
+ [if-any offer_publish]
+ <tr>
+  <td>
+    <input type="submit" name="publishbtn" style="width:6em"
+           value="Unarchive">
+  </td>
+  <td>
+    Make this project active again.
+    All project contents will become visible and editable to users as normal.
+    <br><br>
+  </td>
+ </tr>
+ [end]
+
+ [if-any offer_move]
+ <tr>
+  <td>
+    <input type="submit" name="movedbtn" style="width:6em"
+           value="Move">
+  </td>
+  <td>
+    If you have moved your project to a different location, enter it here and
+    users will be directed to that location.  If the destination is another
+    project on this site, enter just the new project name.  If the destination
+    is another site, enter the new project home page URL.
+    <br><br>
+    <b>Location:</b>
+    <input type="text" name="moved_to" size="50" value="[moved_to]">
+  </td>
+ </tr>
+ [end]
+
+ [if-any offer_doom]
+ <tr>
+  <td>
+    <input type="submit" name="doombtn" style="width:6em"
+           value="Doom">
+  </td>
+  <td>
+    Immediately archive this project and schedule it for deletion in
+    90 days.  Only a site admin can un-archive the project, not a
+    project owner.  In the meantime, the project will be read-only for
+    project members only, and the reason for deletion will be displayed at the top
+    of each page.
+    <br><br>
+    <b>Reason:</b>
+    <input type="text" name="reason" size="50" value="[default_doom_reason]">
+  </td>
+ </tr>
+ [end]
+
+ [if-any offer_archive offer_delete offer_publish offer_doom offer_move][else]
+ <tr>
+  <td>
+  </td>
+  <td>
+    You are not authorized to change the project state.
+  </td>
+ </tr>
+ [end]
+
+</table>
+
+</div>
+
+<script type="text/javascript" nonce="[nonce]">
+runOnLoad(function() {
+  if ($("delbtn")) {
+    $("delbtn").addEventListener("click", function(event) {
+        var msg = "Really delete the whole project?\nThis operation cannot be undone.";
+        if (!confirm(msg))
+          event.preventDefault();
+    });
+  }
+});
+</script>
diff --git a/templates/project/project-admin-quota-part.ezt b/templates/project/project-admin-quota-part.ezt
new file mode 100644
index 0000000..1649eab
--- /dev/null
+++ b/templates/project/project-admin-quota-part.ezt
@@ -0,0 +1,30 @@
+<h4>Storage quota</h4>
+
+<div class="section">
+
+  <table cellspacing="6" style="padding:6px">
+    <tr>
+      <td>Issue attachments:</td>
+      <td>[include "quota-bar.ezt" attachment_quota]</td>
+    </tr>
+    <tr>
+      <td style="padding:15px 0">
+        [if-any offer_quota_editing]
+          <input type="submit" name="savechanges" value="Update Quota">
+        [end]
+      </td>
+      <td style="padding:15px 0">
+        [if-any offer_quota_editing]
+          <input type="number" name="[attachment_quota.field_name]" value="[attachment_quota.quota_mb]"
+                 size="5" min="1" style="font-size:90%; padding:0">
+          [if-any errors.attachment_quota]
+            <div class="fielderror">[errors.attachment_quota]</div>
+          [end]
+        [else]
+          [attachment_quota.quota_mb]
+        [end]
+        MB
+      </td>
+    </tr>
+  </table>
+</div>
diff --git a/templates/project/project-export-page.ezt b/templates/project/project-export-page.ezt
new file mode 100644
index 0000000..487b051
--- /dev/null
+++ b/templates/project/project-export-page.ezt
@@ -0,0 +1,23 @@
+[define category_css]css/ph_detail.css[end]
+[include "../framework/header.ezt" "showtabs"]
+
+<h3>Project export</h3>
+
+<form action="projectExport/json" method="GET">
+  [# We use xhr_token here because we are doing a GET on a JSON servlet.]
+  <input type="hidden" name="token" value="[xhr_token]">
+  <table cellpadding="3" class="rowmajor vt">
+    <tr>
+     <th>Format</th>
+     <td style="width:90%">JSON</td>
+   </tr>
+   <tr>
+     <th></th>
+     <td><input type="submit" name="btn" value="Submit"></td>
+   </tr>
+ </table>
+</form>
+
+
+
+[include "../framework/footer.ezt"]
diff --git a/templates/project/project-summary-page.ezt b/templates/project/project-summary-page.ezt
new file mode 100644
index 0000000..4c45bd3
--- /dev/null
+++ b/templates/project/project-summary-page.ezt
@@ -0,0 +1,102 @@
+[define category_css]css/ph_detail.css[end]
+[include "../framework/header.ezt" "showtabs"]
+[# TODO: add UI element permissions when I add editing elements to this page. ]
+[define show_star][if-any project_stars_enabled][if-any logged_in_user][if-any read_only][else]yes[end][end][end][end]
+
+<h4>Project: [projectname]</h4>
+<div class="section">
+  <div><i>[project_summary]</i></div>
+
+  [if-any show_star]
+  <div>
+   <a class="star" id="star"
+    style="color:[if-any is_project_starred]cornflowerblue[else]gray[end];"
+    title="[if-any is_project_starred]Un-s[else]S[end]tar this project">
+   [if-any is_project_starred]&#9733;[else]&#9734;[end]
+   </a>
+   Starred by [num_stars] user[plural]
+   </div>
+  [end]
+</div>
+
+
+<h4>Project description</h4>
+<div class="section">
+  [format "raw"][formatted_project_description][end]
+</div>
+
+<h4>Project access</h4>
+<div class="section">
+  [access_level.name]
+</div>
+
+
+[if-any home_page]
+  <h4>Project home page</h4>
+  <div class="section">
+    <a href="[home_page]">[home_page]</a>
+  </div>
+[end]
+
+[if-any docs_url]
+  <h4>Project documentation</h4>
+  <div class="section">
+    <a href="[docs_url]">[docs_url]</a>
+  </div>
+[end]
+
+[if-any source_url]
+  <h4>Project source browser</h4>
+  <div class="section">
+    <a href="[source_url]">[source_url]</a>
+  </div>
+[end]
+
+<!--  TODO(jrobbins): expose this later when it is more fully baked.
+
+<h4>Issue tracking process</h4>
+<div class="section">
+  Brief paragraph about how you intend this issue tracker to be used.
+
+</div>
+
+
+<h4>Ground rules</h4>
+  <ul>
+    <li>Non-members may enter new issues, but they will be moderated...</li>
+    <li>Please keep to the facts of the issue, don't try to advocate.</li>
+    <li>We are not currently looking for feature requests from non-members.</li>
+  </ul>
+
+
+
+<h4>Guidelines</h4>
+  <ul>
+    <li>Make sure the defect is verified with the latest build</li>
+    <li>Another bullet item describing how to collaborate in this project</li>
+    <li>A few more</li>
+    <li>And going into a little detail</li>
+    <li>But not too much... also need good defaults and examples</li>
+  </ul>
+
+
+<h4>For more information</h4>
+  <ul>
+    <li>Link to external docs</li>
+    <li>And discussion forums</li>
+  </ul>
+
+-->
+
+<script type="text/javascript" nonce="[nonce]">
+runOnLoad(function() {
+  if ($("star")) {
+    [# The user viewing this page wants to star the project *on* this page]
+    $("star").addEventListener("click", function () {
+       _TKR_toggleStar($("star"), "[projectname]");
+    });
+  }
+});
+</script>
+
+[include "../framework/footer.ezt"]
diff --git a/templates/project/project-updates-page.ezt b/templates/project/project-updates-page.ezt
new file mode 100644
index 0000000..c3ee3b4
--- /dev/null
+++ b/templates/project/project-updates-page.ezt
@@ -0,0 +1,7 @@
+[define page_css]css/d_updates_page.css[end]
+
+[include "../framework/header.ezt" "hidetabs"]
+
+[include "../features/updates-page.ezt"]
+
+[include "../framework/footer.ezt"]
diff --git a/templates/project/quota-bar.ezt b/templates/project/quota-bar.ezt
new file mode 100644
index 0000000..e89a6e2
--- /dev/null
+++ b/templates/project/quota-bar.ezt
@@ -0,0 +1,22 @@
+[# Display a little HTML bar and labels. This is not really a bar chart.
+   For comparison, see the bars in the top half of
+   https://www.google.com/accounts/ManageStorage
+
+arg0: an EZTItem with quota info for one component.
+]
+
+<table border="0" cellpadding="0" cellspacing="0">
+  <tr>
+    <td style="width:200px">
+      <table border="0" cellpadding="0" cellspacing="0" style="width:100%; border:1px solid #345BA6">
+        <tr>
+          <td style="background:#345BA6; width:[arg0.used_percent]%"> &nbsp; </td>
+          <td style="background:#EBF0FA; width:[arg0.avail_percent]%"> &nbsp; </td>
+        </tr>
+      </table>
+    </td>
+    <td style="padding-left:.7em">
+      [arg0.used] ([arg0.used_percent]%) in use
+    </td>
+  </tr>
+</table>
diff --git a/templates/project/rules-deleted-notification-email.ezt b/templates/project/rules-deleted-notification-email.ezt
new file mode 100644
index 0000000..2155004
--- /dev/null
+++ b/templates/project/rules-deleted-notification-email.ezt
@@ -0,0 +1,6 @@
+The following Filter rules were deleted for the [project_name] project.
+
+[for rules] <div>[rules]</div> [end]
+
+If these rules need to be added back please re-create them <a href="[rules_url]">here</a>
+<br>
diff --git a/templates/project/untrusted-user-groups-part.ezt b/templates/project/untrusted-user-groups-part.ezt
new file mode 100644
index 0000000..474cfe7
--- /dev/null
+++ b/templates/project/untrusted-user-groups-part.ezt
@@ -0,0 +1,14 @@
+[if-any perms.EditProject]
+  <div class="help" style="background: #ddf8cc;">
+       <b>Important:</b> Users could be given indirect
+       roles in this project without your knowledge.
+       The following user groups either have group managers
+       who are not project owners in this project, or they allow anyone to
+       join the group:
+       <ul style="list-style-type: none">
+         [for untrusted_user_groups]
+         <li>[untrusted_user_groups.email]</li> [# TODO(jrobbins): hyperlink]
+         [end]
+       </ul>
+  </div>
+[end]