From f6a57ac50379a7e68c4af5bc2a491ace74ddc66b Mon Sep 17 00:00:00 2001 From: Brad Larson Date: Tue, 3 Mar 2009 22:26:30 -0600 Subject: Add support for abandoning a dead change Add the ability to abandon a change. When the abandon button is clicked, a dialog will pop up for the user to enter an abandon message. This message will be added as a comment to the change and an email will be sent to all reviewers of the change. Bug: GERRIT-41 Signed-off-by: Brad Larson Signed-off-by: Shawn O. Pearce --- src/main/java/com/google/gerrit/Gerrit.gwt.xml | 2 +- .../gerrit/client/changes/AbandonChangeDialog.java | 105 +++ .../gerrit/client/changes/ChangeConstants.java | 7 + .../client/changes/ChangeConstants.properties | 7 + .../client/changes/ChangeDetailServiceImpl.java | 27 +- .../gerrit/client/changes/PatchSetPanel.java | 22 + .../google/gerrit/client/data/ChangeDetail.java | 9 +- .../gerrit/client/patches/PatchDetailService.java | 4 + .../com/google/gerrit/public/gerrit2.cache.css | 824 -------------------- .../com/google/gerrit/public/gerrit3.cache.css | 850 +++++++++++++++++++++ .../java/com/google/gerrit/server/ChangeMail.java | 35 + .../server/patch/PatchDetailServiceImpl.java | 93 +++ 12 files changed, 1157 insertions(+), 828 deletions(-) create mode 100644 src/main/java/com/google/gerrit/client/changes/AbandonChangeDialog.java delete mode 100644 src/main/java/com/google/gerrit/public/gerrit2.cache.css create mode 100644 src/main/java/com/google/gerrit/public/gerrit3.cache.css diff --git a/src/main/java/com/google/gerrit/Gerrit.gwt.xml b/src/main/java/com/google/gerrit/Gerrit.gwt.xml index 8d73d5cb44..2f03f9b62b 100644 --- a/src/main/java/com/google/gerrit/Gerrit.gwt.xml +++ b/src/main/java/com/google/gerrit/Gerrit.gwt.xml @@ -12,7 +12,7 @@ - + diff --git a/src/main/java/com/google/gerrit/client/changes/AbandonChangeDialog.java b/src/main/java/com/google/gerrit/client/changes/AbandonChangeDialog.java new file mode 100644 index 0000000000..b0d419bfde --- /dev/null +++ b/src/main/java/com/google/gerrit/client/changes/AbandonChangeDialog.java @@ -0,0 +1,105 @@ +// Copyright (C) 2009 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package com.google.gerrit.client.changes; + +import com.google.gerrit.client.patches.PatchUtil; +import com.google.gerrit.client.reviewdb.PatchSet; +import com.google.gerrit.client.rpc.GerritCallback; +import com.google.gerrit.client.ui.SmallHeading; +import com.google.gwt.user.client.DOM; +import com.google.gwt.user.client.rpc.AsyncCallback; +import com.google.gwt.user.client.ui.Button; +import com.google.gwt.user.client.ui.ClickListener; +import com.google.gwt.user.client.ui.FlowPanel; +import com.google.gwt.user.client.ui.TextArea; +import com.google.gwt.user.client.ui.Widget; +import com.google.gwtexpui.user.client.AutoCenterDialogBox; +import com.google.gwtjsonrpc.client.VoidResult; + +public class AbandonChangeDialog extends AutoCenterDialogBox { + + private final FlowPanel panel; + private final TextArea message; + private final Button sendButton; + private final Button cancelButton; + private final PatchSet.Id psid; + private final AsyncCallback appCallback; + + public AbandonChangeDialog(final PatchSet.Id psi, + final AsyncCallback callback) { + super(/* auto hide */true, /* modal */true); + + psid = psi; + appCallback = callback; + addStyleName("gerrit-AbandonChangeDialog"); + setText(Util.C.abandonChangeTitle()); + + panel = new FlowPanel(); + add(panel); + + panel.add(new SmallHeading(Util.C.headingAbandonMessage())); + + final FlowPanel mwrap = new FlowPanel(); + mwrap.setStyleName("gerrit-AbandonMessage"); + panel.add(mwrap); + + message = new TextArea(); + message.setCharacterWidth(60); + message.setVisibleLines(10); + DOM.setElementPropertyBoolean(message.getElement(), "spellcheck", true); + mwrap.add(message); + + final FlowPanel buttonPanel = new FlowPanel(); + buttonPanel.setStyleName("gerrit-CommentEditor-Buttons"); + panel.add(buttonPanel); + + sendButton = new Button(Util.C.buttonAbandonChangeSend()); + sendButton.addClickListener(new ClickListener() { + public void onClick(Widget sender) { + sendButton.setEnabled(false); + PatchUtil.DETAIL_SVC.abandonChange(psid, message.getText().trim(), + new GerritCallback() { + public void onSuccess(VoidResult result) { + if (appCallback != null) { + appCallback.onSuccess(null); + } + hide(); + } + + @Override + public void onFailure(Throwable caught) { + sendButton.setEnabled(true); + super.onFailure(caught); + } + }); + } + }); + buttonPanel.add(sendButton); + + cancelButton = new Button(Util.C.buttonAbandonChangeCancel()); + cancelButton.addClickListener(new ClickListener() { + public void onClick(Widget sender) { + hide(); + } + }); + buttonPanel.add(cancelButton); + } + + @Override + protected void onLoad() { + super.onLoad(); + message.setFocus(true); + } +} diff --git a/src/main/java/com/google/gerrit/client/changes/ChangeConstants.java b/src/main/java/com/google/gerrit/client/changes/ChangeConstants.java index afc1555b9b..a69d85adc4 100644 --- a/src/main/java/com/google/gerrit/client/changes/ChangeConstants.java +++ b/src/main/java/com/google/gerrit/client/changes/ChangeConstants.java @@ -70,6 +70,13 @@ public interface ChangeConstants extends Constants { String patchSetInfoAuthor(); String patchSetInfoCommitter(); String patchSetInfoDownload(); + + String buttonAbandonChangeBegin(); + String buttonAbandonChangeSend(); + String buttonAbandonChangeCancel(); + String headingAbandonMessage(); + String abandonChangeTitle(); + String buttonPublishCommentsBegin(); String buttonPublishCommentsSend(); String buttonPublishCommentsCancel(); diff --git a/src/main/java/com/google/gerrit/client/changes/ChangeConstants.properties b/src/main/java/com/google/gerrit/client/changes/ChangeConstants.properties index 38546e923c..d0662c42e8 100644 --- a/src/main/java/com/google/gerrit/client/changes/ChangeConstants.properties +++ b/src/main/java/com/google/gerrit/client/changes/ChangeConstants.properties @@ -50,6 +50,13 @@ messageCollapseAll = Collapse All patchSetInfoAuthor = Author patchSetInfoCommitter = Committer patchSetInfoDownload = Download + +buttonAbandonChangeBegin = Abandon Change +buttonAbandonChangeSend = Abandon Change +buttonAbandonChangeCancel = Cancel +headingAbandonMessage = Abandon Message: +abandonChangeTitle = Code Review - Abandon Change + buttonPublishCommentsBegin = Publish Comments buttonPublishCommentsSend = Publish Comments buttonPublishCommentsCancel = Cancel diff --git a/src/main/java/com/google/gerrit/client/changes/ChangeDetailServiceImpl.java b/src/main/java/com/google/gerrit/client/changes/ChangeDetailServiceImpl.java index 959ced2deb..52263ddb92 100644 --- a/src/main/java/com/google/gerrit/client/changes/ChangeDetailServiceImpl.java +++ b/src/main/java/com/google/gerrit/client/changes/ChangeDetailServiceImpl.java @@ -17,8 +17,11 @@ package com.google.gerrit.client.changes; import com.google.gerrit.client.data.AccountInfoCacheFactory; import com.google.gerrit.client.data.ChangeDetail; import com.google.gerrit.client.data.PatchSetDetail; +import com.google.gerrit.client.data.ProjectCache; +import com.google.gerrit.client.reviewdb.Account; import com.google.gerrit.client.reviewdb.Change; import com.google.gerrit.client.reviewdb.PatchSet; +import com.google.gerrit.client.reviewdb.Project; import com.google.gerrit.client.reviewdb.ReviewDb; import com.google.gerrit.client.rpc.BaseServiceImplementation; import com.google.gerrit.client.rpc.Common; @@ -32,14 +35,23 @@ public class ChangeDetailServiceImpl extends BaseServiceImplementation final AsyncCallback callback) { run(callback, new Action() { public ChangeDetail run(final ReviewDb db) throws OrmException, Failure { + final Account.Id me = Common.getAccountId(); final Change change = db.changes().get(id); if (change == null) { throw new Failure(new NoSuchEntityException()); } + final PatchSet patch = db.patchSets().get(change.currentPatchSetId()); + final ProjectCache.Entry projEnt = + Common.getProjectCache().get(change.getDest().getParentKey()); + if (patch == null || projEnt == null) { + throw new Failure(new NoSuchEntityException()); + } + final Project proj = projEnt.getProject(); assertCanRead(change); final boolean anon; - if (Common.getAccountId() == null) { + boolean canAbandon = false; + if (me == null) { // Safe assumption, this wouldn't be allowed if it wasn't. // anon = true; @@ -48,9 +60,20 @@ public class ChangeDetailServiceImpl extends BaseServiceImplementation // we can that doesn't mean the anonymous user could. // anon = canRead(null, change.getDest().getParentKey()); + + // The change owner, current patchset uploader, Gerrit administrator, + // and project administrator can mark the change as abandoned. + // + canAbandon = + me.equals(change.getOwner()) + || me.equals(patch.getUploader()) + || Common.getGroupCache().isAdministrator(me) + || Common.getGroupCache().isInGroup(me, + proj.getOwnerGroupId()); } final ChangeDetail d = new ChangeDetail(); - d.load(db, new AccountInfoCacheFactory(db), change, anon); + + d.load(db, new AccountInfoCacheFactory(db), change, anon, canAbandon); return d; } }); diff --git a/src/main/java/com/google/gerrit/client/changes/PatchSetPanel.java b/src/main/java/com/google/gerrit/client/changes/PatchSetPanel.java index 0bf1c3fa4d..4295f27e76 100644 --- a/src/main/java/com/google/gerrit/client/changes/PatchSetPanel.java +++ b/src/main/java/com/google/gerrit/client/changes/PatchSetPanel.java @@ -33,6 +33,7 @@ import com.google.gerrit.client.rpc.Common; import com.google.gerrit.client.rpc.GerritCallback; import com.google.gerrit.client.ui.RefreshListener; import com.google.gwt.user.client.Window; +import com.google.gwt.user.client.rpc.AsyncCallback; import com.google.gwt.user.client.ui.Button; import com.google.gwt.user.client.ui.ClickListener; import com.google.gwt.user.client.ui.Composite; @@ -161,6 +162,9 @@ class PatchSetPanel extends Composite implements DisclosureHandler { if (Gerrit.isSignedIn() && changeDetail.isCurrentPatchSet(detail)) { populateCommentAction(); populateActions(detail); + if (changeDetail.canAbandon()) { + populateAbandonAction(); + } } body.add(patchTable); } @@ -311,6 +315,24 @@ class PatchSetPanel extends Composite implements DisclosureHandler { } } + private void populateAbandonAction() { + final Button b = new Button(Util.C.buttonAbandonChangeBegin()); + b.addClickListener(new ClickListener() { + public void onClick(Widget sender) { + new AbandonChangeDialog(patchSet.getId(), new AsyncCallback() { + public void onSuccess(Object result) { + actionsPanel.remove(b); + fireOnSuggestRefresh(); + } + + public void onFailure(Throwable caught) { + } + }).center(); + } + }); + actionsPanel.add(b); + } + private void populateCommentAction() { final Button b = new Button(Util.C.buttonPublishCommentsBegin()); b.addClickListener(new ClickListener() { diff --git a/src/main/java/com/google/gerrit/client/data/ChangeDetail.java b/src/main/java/com/google/gerrit/client/data/ChangeDetail.java index 036de1e977..9677789409 100644 --- a/src/main/java/com/google/gerrit/client/data/ChangeDetail.java +++ b/src/main/java/com/google/gerrit/client/data/ChangeDetail.java @@ -41,6 +41,7 @@ import java.util.Set; public class ChangeDetail { protected AccountInfoCache accounts; protected boolean allowsAnonymous; + protected boolean canAbandon; protected Change change; protected List dependsOn; protected List neededBy; @@ -56,12 +57,14 @@ public class ChangeDetail { } public void load(final ReviewDb db, final AccountInfoCacheFactory acc, - final Change c, final boolean allowAnon) throws OrmException { + final Change c, final boolean allowAnon, final boolean canAbdn) + throws OrmException { change = c; final Account.Id owner = change.getOwner(); acc.want(owner); allowsAnonymous = allowAnon; + canAbandon = canAbdn; patchSets = db.patchSets().byChange(change.getId()).toList(); messages = db.changeMessages().byChange(change.getId()).toList(); for (final ChangeMessage m : messages) { @@ -177,6 +180,10 @@ public class ChangeDetail { return allowsAnonymous; } + public boolean canAbandon() { + return canAbandon; + } + public Change getChange() { return change; } diff --git a/src/main/java/com/google/gerrit/client/patches/PatchDetailService.java b/src/main/java/com/google/gerrit/client/patches/PatchDetailService.java index 7d00318975..04d506baba 100644 --- a/src/main/java/com/google/gerrit/client/patches/PatchDetailService.java +++ b/src/main/java/com/google/gerrit/client/patches/PatchDetailService.java @@ -54,4 +54,8 @@ public interface PatchDetailService extends RemoteJsonService { @SignInRequired void addReviewers(Change.Id id, List reviewers, AsyncCallback callback); + + @SignInRequired + void abandonChange(PatchSet.Id patchSetId, String message, + AsyncCallback callback); } diff --git a/src/main/java/com/google/gerrit/public/gerrit2.cache.css b/src/main/java/com/google/gerrit/public/gerrit2.cache.css deleted file mode 100644 index 69512fe775..0000000000 --- a/src/main/java/com/google/gerrit/public/gerrit2.cache.css +++ /dev/null @@ -1,824 +0,0 @@ -#gerrit_topmenu { - font-size: 9pt; - padding-top: 5px; - padding-left: 5px; - padding-right: 5px; - height: 15px; -} -#gerrit_endtopmenu { - clear: both; - height: 5px; - border-bottom: 1px solid #B0BDCC; -} -#gerrit_body { - font-size: 11pt; - padding-left: 5px; - padding-right: 5px; - width: 98%; -} -#gerrit_pagefooter { - clear: both; - margin-top: 15px; - padding-top: 2px; - margin-bottom: 15px; -} -#gerrit_btmmenu { - clear: both; -} -#gerrit_btmmenu .gerrit-version { - color: #a0adcc; - right: 0; - padding-right: 10px; - text-align: right; -} -#gerrit_btmmenu .gerrit-version a, -#gerrit_btmmenu .gerrit-version a:visited, -#gerrit_btmmenu .gerrit-version a:hover { - color: #2a5db0; -} - - -/** Widgets **/ -.gerrit-Hyperlink { - text-decoration: underline; -} - -.gerrit-AccountName { - white-space: nowrap; -} - -.gerrit-visualtab { - color: red; - font-weight: bold; - font-size: 8pt; -} - -.gerrit-whitespaceerror { - background: red; -} - -.gerrit-InputFieldTypeHint { - color: grey; -} - -.gerrit-SmallHeading { - margin-top: 5px; - font-weight: bold; -} - - -/** Menu **/ -.gwt-MenuItem a, -.gwt-MenuItem a:visited, -.gwt-MenuItem a:hover { - color: #2a5db0; -} -.gerrit-LinkMenuBar .gwt-MenuItem { - font-size: 9pt; - color: #2a5db0; - text-decoration: underline; - padding-left: 5px; - padding-right: 5px; - white-space: nowrap; - cursor: pointer; - cursor: hand; -} -.gerrit-LinkMenuBar .gwt-MenuItem-NormalItem { - border-right: 1px solid black; -} -.gerrit-LinkMenuBar .gwt-MenuItem-LastItem { -} -.gerrit-FillMenuCenter { - width: 100%; -} -.gwt-MenuItem .gwt-Hyperlink { - font-size: 9pt; - white-space: nowrap; -} -.gerrit-MenuBarUserName { - font-size: 9pt; - font-weight: bold; - padding-left: 5px; - padding-right: 5px; - white-space: nowrap; -} - -/** RPC Status **/ -.gerrit-RpcStatusPanel { - position: absolute; - left: 50%; - float: left; - top: 6px; -} - -.gerrit-RpcStatus { - padding-top: 4px; - padding-bottom: 4px; - padding-left: 10px; - padding-right: 10px; - text-align: center; - font-weight: bold; -} - -.gerrit-RpcStatus-Loading { - background: #FFF1A8; -} - - -/** Error Dialog **/ -.gerrit-ErrorDialog { - margin: 10px 10px 10px 10px; -} - -.gerrit-ErrorDialog-ErrorType { - font-weight: bold; - white-space: nowrap; - margin-bottom: 15px; -} - -.gerrit-ErrorDialog-ErrorMessage { -} - -.gerrit-ErrorDialog-Buttons { - width: 100%; - margin-top: 15px; - text-align: right; -} - - -/** Screen **/ -.gerrit-Screen { -} - -.gerrit-Screen h1 { - white-space: nowrap; - font-size: 16pt; - margin: 3px 0 8px; - text-overflow: ellipsis; - overflow: hidden; -} - - -/** ChangeTable **/ -.gerrit-ChangeTable { - width: 100%; - border-collapse: separate; - border-spacing: 0; -} - -.gerrit-ChangeTable .IconCell { - width: 1px; - padding: 0px; - vertical-align: middle; - border-bottom: 1px solid #d4e9a9; -} - -.gerrit-ChangeTable .ChangeTypeCell { - width: 1px; - padding-left: 5px; - padding-right: 5px; - border-right: 1px solid #d4e9a9; - border-bottom: 1px solid #d4e9a9; - vertical-align: top; -} - -.gerrit-ChangeTable .CommentCell { - text-align: right; - font-weight: bold; - white-space: nowrap; -} -.gerrit-ChangeTable .CommentCell span.Drafts { - color: #ff5555; -} - -.gerrit-ChangeTable .FilePathCell { - white-space: nowrap; -} - -.gerrit-ChangeTable .FilePathCell .SourceFilePath { - font-style: italic; - font-size: 9pt; -} - -.gerrit-ChangeTable .DiffLinkCell { - white-space: nowrap; -} - -.gerrit-ChangeTable .LeftMostCell { - border-left: 1px solid #d4e9a9; -} - -.gerrit-ChangeTable .DataCell { - padding-left: 5px; - padding-right: 5px; - border-right: 1px solid #d4e9a9; - border-bottom: 1px solid #d4e9a9; -} - -.gerrit-ChangeTable .ActiveRow { - background: #ffffcc; -} - -.gerrit-ChangeTable .C_ID { - width: 3.5em; - text-align: right; -} - -.gerrit-ChangeTable .C_SUBJECT div { - text-overflow: ellipsis; - overflow: hidden; - white-space: nowrap; -} - -.gerrit-ChangeTable .C_PROJECT { - white-space: nowrap; -} - -.gerrit-ChangeTable .C_LAST_UPDATE { - white-space: nowrap; -} - -.gerrit-ChangeTable .IconHeader { - border-top: 1px solid white; - border-bottom: 1px solid white; - background-color: #d4e9a9; -} - -.gerrit-ChangeTable .DataHeader { - border: 1px solid white; - padding: 2px 6px 1px; - background-color: #d4e9a9; - font-style: italic; - white-space: nowrap; -} - -.gerrit-ChangeTable .SectionHeader { - border-top: 8px solid white; - padding: 2px 6px 1px; - background-color: #d4e9a9; - white-space: nowrap; - font-weight: bold; -} - -.gerrit-ChangeTable .EmptySection { - border-left: 1px solid #d4e9a9; - border-right: 1px solid #d4e9a9; - border-bottom: 1px solid #d4e9a9; - font-style: italic; - padding-left: 25px; -} - -.gerrit-ChangeTable-PrevNextLinks { - float: right; - padding-right: 5px; -} -.gerrit-ChangeTable-PrevNextLinks td { - width: 5em; - text-align: right; -} -.gerrit-ChangeTable-PrevNextLinks .gwt-Hyperlink { - font-size: 9pt; - color: #2a5db0; -} - - -/** PatchContentTable **/ -.gerrit-PatchContentTable { - width: 100%; - border-collapse: separate; - border-spacing: 0; -} -.gerrit-PatchContentTable td { - font-size: 8pt; - font-family: monospace; -} - -.gerrit-PatchContentTable .IconCell { - width: 1px; - padding: 0px; - vertical-align: middle; - border-top: 1px solid transparent; - border-bottom: 1px solid transparent; -} - -.gerrit-PatchContentTable .DiffText { - white-space: pre; - padding-left: 0.2em; -} - -.gerrit-PatchContentTable .DiffText-FILE_HEADER { - color: grey; - font-weight: bold; -} -.gerrit-PatchContentTable .DiffText-HUNK_HEADER { - color: blue; -} -.gerrit-PatchContentTable .DiffText-PRE_IMAGE { - color: #a00000; -} -.gerrit-PatchContentTable .DiffText-CONTEXT { - color: grey; -} -.gerrit-PatchContentTable .DiffText-POST_IMAGE { - color: #006000; -} - -.gerrit-PatchContentTable .Comment { - padding: 0px; -} -.gerrit-PatchContentTable .Comment table { - border-collapse: separate; - border-spacing: 0; -} -.gerrit-PatchContentTable .Comment td { - font-family: Arial Unicode MS,Arial,sans-serif; - font-size: 8pt; -} -.gerrit-PatchContentTable td.Comment { - vertical-align: top; - border-left: 5px solid orange; -} -.gerrit-PatchContentTable .gwt-DisclosurePanel { - background: #fef8cb; - padding-right: 5px; -} -.gerrit-PatchContentTable .Comment .header { - width: 35em; -} -.gerrit-PatchContentTable .Comment .gwt-DisclosurePanel .header td { - white-space: nowrap; -} -.gerrit-PatchContentTable .Comment .complexHeader { - white-space: nowrap; - width: 5em; -} -.gerrit-PatchContentTable .Comment .content { - border-top: 3px solid #e3e3e3; -} - -.gerrit-PatchContentTable .FileColumnHeader { - background: #d4e9a9; - font-family: Arial Unicode MS,Arial,sans-serif; - font-weight: bold; - text-align: center; -} - -.gerrit-PatchContentTable .LineNumber { - padding-left: 0.2em; - white-space: pre; - width: 3.5em; - text-align: right; - border-right: thin solid #b0bdcc; - padding-right: 0.2em; - border-top: 1px solid transparent; - border-bottom: 1px solid transparent; -} - -.gerrit-PatchContentTable .NoLineLineNumber { - font-family: monospace; - width: 3.5em; - padding-left: 0.2em; - padding-right: 0.2em; -} - -.gerrit-PatchContentTable .FileLine { - padding-left: 0.2em; - white-space: pre; - padding-right: 0.2em; - border-top: 1px solid transparent; - border-bottom: 1px solid transparent; -} - -.gerrit-PatchContentTable .FileLineNone { - background: #eeeeee; -} -.gerrit-PatchContentTable .FileLine-DELETE { - background: #ffeeee; -} -.gerrit-PatchContentTable .FileLine-EQUAL { -} -.gerrit-PatchContentTable .FileLine-INSERT { - background: #ddffdd; -} - -.gerrit-PatchContentTable .SkipLine { - font-family: Arial Unicode MS,Arial,sans-serif; - text-align: center; - font-style: italic; - background: lightblue; -} -.gerrit-PatchContentTable .SkipLine div { - display: inline; -} - -.gerrit-PatchContentTable .ActiveRow { - background: #ffffcc; -} -.gerrit-PatchContentTable .ActiveRow td.IconCell, -.gerrit-PatchContentTable .ActiveRow td.LineNumber, -.gerrit-PatchContentTable .ActiveRow td.FileLine, -.gerrit-PatchContentTable .ActiveRow td.DiffText { - border-top: 1px solid blue; - border-bottom: 1px solid blue; -} - - -/** Change **/ -.gerrit-ChangeScreen .gwt-DisclosurePanel .header td { - font-weight: bold; - white-space: nowrap; -} - -.gerrit-ChangeScreen .gwt-DisclosurePanel .complexHeader { - white-space: nowrap; -} - -.gerrit-ChangeScreen .gwt-DisclosurePanel .complexHeader .gerrit-PatchSetLink { - padding-left: 20px; - font-size: 8pt; -} - -.gerrit-ChangeScreen .gwt-DisclosurePanel .content { - margin-bottom: 10px; -} - -.gerrit-ChangeScreen-Description { - white-space: pre; - font-family: monospace; - font-size: small; -} - -.gerrit-ChangeScreen .gerrit-ChangeMessages .header { - width: 35em; -} -.gerrit-ChangeScreen .gerrit-ChangeMessages .complexHeader { - width: 5em; -} -.gerrit-ChangeScreen .gerrit-ChangeMessages .content { - border-top: 3px solid #e3e3e3; -} - -.gerrit-ChangeMessage-Message { - font-size: small; -} - -.gerrit-InfoTable { - border-collapse: collapse; - border-spacing: 0; -} - -.gerrit-InfoTable td { - border-left: 1px solid #d4e9a9; - border-bottom: 1px solid #d4e9a9; - padding: 2px 6px 1px; -} - -.gerrit-InfoTable td.header { - background-color: #d4e9a9; - border-left: 1px solid white; - font-weight: normal; - padding: 2px 4px 0 6px; - font-style: italic; - text-align: left; - vertical-align: top; - white-space: nowrap; -} - -.gerrit-InfoTable td.leftmost { -} - -.gerrit-InfoTable td.rightmost { - border-right: 1px solid #d4e9a9; -} - -.gerrit-InfoTable td.approvalrole { - width: 5em; - border-left: none; - font-style: italic; - white-space: nowrap; -} - -.gerrit-InfoTable td.approvalscore { - text-align: center; -} -.gerrit-InfoTable td.negscore { - color: red; -} -.gerrit-InfoTable td.posscore { - color: #08a400; -} - -.gerrit-InfoTable td.approvalhint { - white-space: nowrap; - background-left: 1px none; - background-bottom: 1px none; - border: none; - color: #444444; -} - -.gerrit-ChangeInfoBlock { -} - -.gerrit-InfoBlock { - border-collapse: collapse; - border-spacing: 0; -} - -.gerrit-InfoBlock td { - padding: 2px 4px 2px 6px; - border-right: 1px solid #d4e9a9; - border-bottom: 1px solid #d4e9a9; - text-align: left; - white-space: nowrap; -} - -.gerrit-InfoBlock td.topmost { - border-top: 1px solid #d4e9a9; -} - -.gerrit-InfoBlock td.header { - border-bottom: 1px solid white; - background-color: #d4e9a9; - font-style: italic; - text-align: right; -} - -.gerrit-InfoBlock td.bottomheader { - border-bottom: 1px solid #d4e9a9; -} - -.gerrit-InfoBlock td.closedstate { - font-weight: bold; -} - -.gerrit-InfoBlock td.permalink { - border-right: 1px none; - border-bottom: 1px none; - text-align: right; -} -.gerrit-InfoBlock td.permalink div div { - display: inline; -} - -.gerrit-InfoBlock td.command { - white-space: pre; - font-family: monospace; - font-size: 12px; -} - -.gerrit-InfoBlock td.useridentity { - white-space: nowrap; -} - -.gerrit-PatchSetInfoBlock { - margin-bottom: 10px; -} - -.gerrit-PatchSetActions { - margin-bottom: 10px; -} -.gerrit-PatchSetActions .gwt-Button { - margin-right: 5px; - font-size: 8pt; -} - -.gerrit-Change-MissingApprovalList { - margin-top: 5px; -} -.gerrit-Change-MissingApproval { - font-weight: bold; - white-space: nowrap; -} - -.gerrit-Change-AddReviewer { - margin-top: 5px; - white-space: nowrap; -} - - -/** SideBySideScreen **/ -.gerrit-SideBySideScreen-SideBySideTable { - width: 100%; - border: 1px solid #B0BDCC; - display: table; -} - -.gerrit-SideBySideScreen-SideBySideTable td.Comment { - border-left: 5px solid orange; - border-right: 5px solid orange; - padding-right: 5px; - background: #fef8cb; -} - -.gerrit-CommentEditor { - background: lightgrey; - padding-left: 5px; - padding-right: 5px; - padding-top: 5px; - padding-bottom: 5px; -} -.gerrit-CommentEditor textarea { - font-size: small; -} -.gerrit-CommentEditor-Buttons { - margin-top: 5px; -} -.gerrit-CommentEditor-Buttons .gwt-Button { - margin-right: 5px; - font-size: 8pt; -} - - -/** Patch History Table **/ -.gerrit-PatchHistoryTable { - width: auto; - margin-bottom: 10px; -} - -.gerrit-PatchHistoryTable .DataCell { - white-space: nowrap; -} - - -/** AccountSettings **/ -.gerrit-SshKeyPanel-EncodedKey { - white-space: nowrap; - text-overflow: ellipsis; - overflow: hidden; - font-family: monospace; - font-size: small; -} -.gerrit-SshKeyPanel-Invalid { - white-space: nowrap; - color: red; - font-weight: bold; -} -.gerrit-Identity-UntrustedExternalId { - white-space: nowrap; - color: red; - font-weight: bold; -} - -.gerrit-AccountInfoBlock { - margin-bottom: 10px; -} -.gerrit-AccountContactPrivacyDetails { - margin-left: 10px; - margin-top: 5px; - margin-bottom: 5px; - width: 40em; -} -.gerrit-AccountContactOnFile { - margin-left: 10px; - margin-top: 5px; - margin-bottom: 5px; - font-weight: bold; -} - -.gerrit-AddSshKeyPanel { - margin-top: 10px; - background-color: #d4e9a9; - padding: 5px 5px 5px 5px; -} - -.gerrit-WatchedProjectPanel { - margin-top: 10px; - padding: 5px 5px 5px 5px; - display: table; - border: 1px solid #b0bdcc; -} - -.gerrit-ContributorAgreement-Button { - font-weight: bold; -} - -.gerrit-ContributorAgreement-ShortDescription { - margin-left: 20px; - margin-right: 20px; - margin-bottom: 10px; - padding: 5px 5px 5px 5px; - border: 1px solid #b0bdcc; -} - -.gerrit-ContributorAgreement-AlreadySubmitted { - margin-left: 20px; - margin-right: 20px; - padding: 5px 5px 5px 5px; - color: red; -} - -.gerrit-ContributorAgreement-Legal { - margin-left: 20px; - margin-right: 20px; - padding: 5px 5px 5px 5px; - border: 1px solid #b0bdcc; -} - -.gerrit-ProjectAdmin-ApprovalCategoryRangeLine { - white-space: nowrap; -} -.gerrit-ProjectAdmin-ApprovalCategoryValue { - font-family: monospace; - font-size: small; -} - - -/** PublishCommentsScreen **/ - -.gerrit-PublishCommentsScreen .gwt-DisclosurePanel .header td { - font-weight: bold; - white-space: nowrap; -} - -.gerrit-PublishCommentsScreen .gerrit-SmallHeading { - font-size: small; - font-weight: bold; - white-space: nowrap; -} -.gerrit-PublishCommentsScreen .gerrit-ApprovalCategoryList { - margin-bottom: 10px; - margin-left: 10px; - background: #d4e9a9; - width: 25em; - white-space: nowrap; - padding-top: 2px; - padding-bottom: 2px; -} -.gerrit-PublishCommentsScreen .gerrit-CoverMessage { - margin-left: 10px; - background: #d4e9a9; - padding: 5px 5px 5px 5px; -} -.gerrit-PublishCommentsScreen .gerrit-CoverMessage textarea { - font-size: small; -} -.gerrit-PublishCommentsScreen .gerrit-ApprovalCategoryList .gwt-RadioButton { - font-size: smaller; -} -.gerrit-PublishCommentsScreen .gerrit-PatchComments { - margin-bottom: 10px; - margin-left: 10px; -} -.gerrit-PublishCommentsScreen .gwt-Hyperlink { - white-space: nowrap; - font-size: small; -} -.gerrit-PublishCommentsScreen .gerrit-LineHeader { - white-space: nowrap; - font-family: monospace; - font-size: small; - font-style: italic; - border-left: 3px solid #e3e3e3; - padding-left: 3px; -} -.gerrit-PublishCommentsScreen .gerrit-PatchLineComment { - border-left: 3px solid #e3e3e3; - padding-left: 6px; -} - - -/** OpenIdLoginPanel **/ -.gerrit-OpenID-loginform { - margin-left: 10px; -} - -.gerrit-OpenID-logobox { - width: 98%; - text-align: right; -} - -.gerrit-OpenID-loginline { - margin-bottom: 10px; -} - -.gerrit-OpenID-openid_identifier { - background: #ffffff url(openidlogin_bg1.cache.gif) no-repeat scroll 5px 50%; - padding-left: 25px; - border: 1px solid #999999; - margin-right: 5px; -} - -.gerrit-OpenID-directlink { - vertical-align: middle; - margin-right: 5px; - color: blue; -} -.gerrit-OpenID-directlink:hover { - text-decoration: underline; -} -.gerrit-OpenID-directlink img { - margin-right: 3px; - border: 0 none; -} - -.gerrit-OpenID-errorline { - padding-top: 5px; - padding-bottom: 5px; -} -.gerrit-OpenID-errorline span { - padding-top: 4px; - padding-bottom: 4px; - padding-left: 10px; - padding-right: 10px; - background: #fff1a8; -} diff --git a/src/main/java/com/google/gerrit/public/gerrit3.cache.css b/src/main/java/com/google/gerrit/public/gerrit3.cache.css new file mode 100644 index 0000000000..66c735e6f2 --- /dev/null +++ b/src/main/java/com/google/gerrit/public/gerrit3.cache.css @@ -0,0 +1,850 @@ +#gerrit_topmenu { + font-size: 9pt; + padding-top: 5px; + padding-left: 5px; + padding-right: 5px; + height: 15px; +} +#gerrit_endtopmenu { + clear: both; + height: 5px; + border-bottom: 1px solid #B0BDCC; +} +#gerrit_body { + font-size: 11pt; + padding-left: 5px; + padding-right: 5px; + width: 98%; +} +#gerrit_pagefooter { + clear: both; + margin-top: 15px; + padding-top: 2px; + margin-bottom: 15px; +} +#gerrit_btmmenu { + clear: both; +} +#gerrit_btmmenu .gerrit-version { + color: #a0adcc; + right: 0; + padding-right: 10px; + text-align: right; +} +#gerrit_btmmenu .gerrit-version a, +#gerrit_btmmenu .gerrit-version a:visited, +#gerrit_btmmenu .gerrit-version a:hover { + color: #2a5db0; +} + + +/** Widgets **/ +.gerrit-Hyperlink { + text-decoration: underline; +} + +.gerrit-AccountName { + white-space: nowrap; +} + +.gerrit-visualtab { + color: red; + font-weight: bold; + font-size: 8pt; +} + +.gerrit-whitespaceerror { + background: red; +} + +.gerrit-InputFieldTypeHint { + color: grey; +} + +.gerrit-SmallHeading { + margin-top: 5px; + font-weight: bold; +} + + +/** Menu **/ +.gwt-MenuItem a, +.gwt-MenuItem a:visited, +.gwt-MenuItem a:hover { + color: #2a5db0; +} +.gerrit-LinkMenuBar .gwt-MenuItem { + font-size: 9pt; + color: #2a5db0; + text-decoration: underline; + padding-left: 5px; + padding-right: 5px; + white-space: nowrap; + cursor: pointer; + cursor: hand; +} +.gerrit-LinkMenuBar .gwt-MenuItem-NormalItem { + border-right: 1px solid black; +} +.gerrit-LinkMenuBar .gwt-MenuItem-LastItem { +} +.gerrit-FillMenuCenter { + width: 100%; +} +.gwt-MenuItem .gwt-Hyperlink { + font-size: 9pt; + white-space: nowrap; +} +.gerrit-MenuBarUserName { + font-size: 9pt; + font-weight: bold; + padding-left: 5px; + padding-right: 5px; + white-space: nowrap; +} + +/** RPC Status **/ +.gerrit-RpcStatusPanel { + position: absolute; + left: 50%; + float: left; + top: 6px; +} + +.gerrit-RpcStatus { + padding-top: 4px; + padding-bottom: 4px; + padding-left: 10px; + padding-right: 10px; + text-align: center; + font-weight: bold; +} + +.gerrit-RpcStatus-Loading { + background: #FFF1A8; +} + + +/** Error Dialog **/ +.gerrit-ErrorDialog { + margin: 10px 10px 10px 10px; +} + +.gerrit-ErrorDialog-ErrorType { + font-weight: bold; + white-space: nowrap; + margin-bottom: 15px; +} + +.gerrit-ErrorDialog-ErrorMessage { +} + +.gerrit-ErrorDialog-Buttons { + width: 100%; + margin-top: 15px; + text-align: right; +} + + +/** Screen **/ +.gerrit-Screen { +} + +.gerrit-Screen h1 { + white-space: nowrap; + font-size: 16pt; + margin: 3px 0 8px; + text-overflow: ellipsis; + overflow: hidden; +} + + +/** ChangeTable **/ +.gerrit-ChangeTable { + width: 100%; + border-collapse: separate; + border-spacing: 0; +} + +.gerrit-ChangeTable .IconCell { + width: 1px; + padding: 0px; + vertical-align: middle; + border-bottom: 1px solid #d4e9a9; +} + +.gerrit-ChangeTable .ChangeTypeCell { + width: 1px; + padding-left: 5px; + padding-right: 5px; + border-right: 1px solid #d4e9a9; + border-bottom: 1px solid #d4e9a9; + vertical-align: top; +} + +.gerrit-ChangeTable .CommentCell { + text-align: right; + font-weight: bold; + white-space: nowrap; +} +.gerrit-ChangeTable .CommentCell span.Drafts { + color: #ff5555; +} + +.gerrit-ChangeTable .FilePathCell { + white-space: nowrap; +} + +.gerrit-ChangeTable .FilePathCell .SourceFilePath { + font-style: italic; + font-size: 9pt; +} + +.gerrit-ChangeTable .DiffLinkCell { + white-space: nowrap; +} + +.gerrit-ChangeTable .LeftMostCell { + border-left: 1px solid #d4e9a9; +} + +.gerrit-ChangeTable .DataCell { + padding-left: 5px; + padding-right: 5px; + border-right: 1px solid #d4e9a9; + border-bottom: 1px solid #d4e9a9; +} + +.gerrit-ChangeTable .ActiveRow { + background: #ffffcc; +} + +.gerrit-ChangeTable .C_ID { + width: 3.5em; + text-align: right; +} + +.gerrit-ChangeTable .C_SUBJECT div { + text-overflow: ellipsis; + overflow: hidden; + white-space: nowrap; +} + +.gerrit-ChangeTable .C_PROJECT { + white-space: nowrap; +} + +.gerrit-ChangeTable .C_LAST_UPDATE { + white-space: nowrap; +} + +.gerrit-ChangeTable .IconHeader { + border-top: 1px solid white; + border-bottom: 1px solid white; + background-color: #d4e9a9; +} + +.gerrit-ChangeTable .DataHeader { + border: 1px solid white; + padding: 2px 6px 1px; + background-color: #d4e9a9; + font-style: italic; + white-space: nowrap; +} + +.gerrit-ChangeTable .SectionHeader { + border-top: 8px solid white; + padding: 2px 6px 1px; + background-color: #d4e9a9; + white-space: nowrap; + font-weight: bold; +} + +.gerrit-ChangeTable .EmptySection { + border-left: 1px solid #d4e9a9; + border-right: 1px solid #d4e9a9; + border-bottom: 1px solid #d4e9a9; + font-style: italic; + padding-left: 25px; +} + +.gerrit-ChangeTable-PrevNextLinks { + float: right; + padding-right: 5px; +} +.gerrit-ChangeTable-PrevNextLinks td { + width: 5em; + text-align: right; +} +.gerrit-ChangeTable-PrevNextLinks .gwt-Hyperlink { + font-size: 9pt; + color: #2a5db0; +} + + +/** PatchContentTable **/ +.gerrit-PatchContentTable { + width: 100%; + border-collapse: separate; + border-spacing: 0; +} +.gerrit-PatchContentTable td { + font-size: 8pt; + font-family: monospace; +} + +.gerrit-PatchContentTable .IconCell { + width: 1px; + padding: 0px; + vertical-align: middle; + border-top: 1px solid transparent; + border-bottom: 1px solid transparent; +} + +.gerrit-PatchContentTable .DiffText { + white-space: pre; + padding-left: 0.2em; +} + +.gerrit-PatchContentTable .DiffText-FILE_HEADER { + color: grey; + font-weight: bold; +} +.gerrit-PatchContentTable .DiffText-HUNK_HEADER { + color: blue; +} +.gerrit-PatchContentTable .DiffText-PRE_IMAGE { + color: #a00000; +} +.gerrit-PatchContentTable .DiffText-CONTEXT { + color: grey; +} +.gerrit-PatchContentTable .DiffText-POST_IMAGE { + color: #006000; +} + +.gerrit-PatchContentTable .Comment { + padding: 0px; +} +.gerrit-PatchContentTable .Comment table { + border-collapse: separate; + border-spacing: 0; +} +.gerrit-PatchContentTable .Comment td { + font-family: Arial Unicode MS,Arial,sans-serif; + font-size: 8pt; +} +.gerrit-PatchContentTable td.Comment { + vertical-align: top; + border-left: 5px solid orange; +} +.gerrit-PatchContentTable .gwt-DisclosurePanel { + background: #fef8cb; + padding-right: 5px; +} +.gerrit-PatchContentTable .Comment .header { + width: 35em; +} +.gerrit-PatchContentTable .Comment .gwt-DisclosurePanel .header td { + white-space: nowrap; +} +.gerrit-PatchContentTable .Comment .complexHeader { + white-space: nowrap; + width: 5em; +} +.gerrit-PatchContentTable .Comment .content { + border-top: 3px solid #e3e3e3; +} + +.gerrit-PatchContentTable .FileColumnHeader { + background: #d4e9a9; + font-family: Arial Unicode MS,Arial,sans-serif; + font-weight: bold; + text-align: center; +} + +.gerrit-PatchContentTable .LineNumber { + padding-left: 0.2em; + white-space: pre; + width: 3.5em; + text-align: right; + border-right: thin solid #b0bdcc; + padding-right: 0.2em; + border-top: 1px solid transparent; + border-bottom: 1px solid transparent; +} + +.gerrit-PatchContentTable .NoLineLineNumber { + font-family: monospace; + width: 3.5em; + padding-left: 0.2em; + padding-right: 0.2em; +} + +.gerrit-PatchContentTable .FileLine { + padding-left: 0.2em; + white-space: pre; + padding-right: 0.2em; + border-top: 1px solid transparent; + border-bottom: 1px solid transparent; +} + +.gerrit-PatchContentTable .FileLineNone { + background: #eeeeee; +} +.gerrit-PatchContentTable .FileLine-DELETE { + background: #ffeeee; +} +.gerrit-PatchContentTable .FileLine-EQUAL { +} +.gerrit-PatchContentTable .FileLine-INSERT { + background: #ddffdd; +} + +.gerrit-PatchContentTable .SkipLine { + font-family: Arial Unicode MS,Arial,sans-serif; + text-align: center; + font-style: italic; + background: lightblue; +} +.gerrit-PatchContentTable .SkipLine div { + display: inline; +} + +.gerrit-PatchContentTable .ActiveRow { + background: #ffffcc; +} +.gerrit-PatchContentTable .ActiveRow td.IconCell, +.gerrit-PatchContentTable .ActiveRow td.LineNumber, +.gerrit-PatchContentTable .ActiveRow td.FileLine, +.gerrit-PatchContentTable .ActiveRow td.DiffText { + border-top: 1px solid blue; + border-bottom: 1px solid blue; +} + + +/** Change **/ +.gerrit-ChangeScreen .gwt-DisclosurePanel .header td { + font-weight: bold; + white-space: nowrap; +} + +.gerrit-ChangeScreen .gwt-DisclosurePanel .complexHeader { + white-space: nowrap; +} + +.gerrit-ChangeScreen .gwt-DisclosurePanel .complexHeader .gerrit-PatchSetLink { + padding-left: 20px; + font-size: 8pt; +} + +.gerrit-ChangeScreen .gwt-DisclosurePanel .content { + margin-bottom: 10px; +} + +.gerrit-ChangeScreen-Description { + white-space: pre; + font-family: monospace; + font-size: small; +} + +.gerrit-ChangeScreen .gerrit-ChangeMessages .header { + width: 35em; +} +.gerrit-ChangeScreen .gerrit-ChangeMessages .complexHeader { + width: 5em; +} +.gerrit-ChangeScreen .gerrit-ChangeMessages .content { + border-top: 3px solid #e3e3e3; +} + +.gerrit-ChangeMessage-Message { + font-size: small; +} + +.gerrit-InfoTable { + border-collapse: collapse; + border-spacing: 0; +} + +.gerrit-InfoTable td { + border-left: 1px solid #d4e9a9; + border-bottom: 1px solid #d4e9a9; + padding: 2px 6px 1px; +} + +.gerrit-InfoTable td.header { + background-color: #d4e9a9; + border-left: 1px solid white; + font-weight: normal; + padding: 2px 4px 0 6px; + font-style: italic; + text-align: left; + vertical-align: top; + white-space: nowrap; +} + +.gerrit-InfoTable td.leftmost { +} + +.gerrit-InfoTable td.rightmost { + border-right: 1px solid #d4e9a9; +} + +.gerrit-InfoTable td.approvalrole { + width: 5em; + border-left: none; + font-style: italic; + white-space: nowrap; +} + +.gerrit-InfoTable td.approvalscore { + text-align: center; +} +.gerrit-InfoTable td.negscore { + color: red; +} +.gerrit-InfoTable td.posscore { + color: #08a400; +} + +.gerrit-InfoTable td.approvalhint { + white-space: nowrap; + background-left: 1px none; + background-bottom: 1px none; + border: none; + color: #444444; +} + +.gerrit-ChangeInfoBlock { +} + +.gerrit-InfoBlock { + border-collapse: collapse; + border-spacing: 0; +} + +.gerrit-InfoBlock td { + padding: 2px 4px 2px 6px; + border-right: 1px solid #d4e9a9; + border-bottom: 1px solid #d4e9a9; + text-align: left; + white-space: nowrap; +} + +.gerrit-InfoBlock td.topmost { + border-top: 1px solid #d4e9a9; +} + +.gerrit-InfoBlock td.header { + border-bottom: 1px solid white; + background-color: #d4e9a9; + font-style: italic; + text-align: right; +} + +.gerrit-InfoBlock td.bottomheader { + border-bottom: 1px solid #d4e9a9; +} + +.gerrit-InfoBlock td.closedstate { + font-weight: bold; +} + +.gerrit-InfoBlock td.permalink { + border-right: 1px none; + border-bottom: 1px none; + text-align: right; +} +.gerrit-InfoBlock td.permalink div div { + display: inline; +} + +.gerrit-InfoBlock td.command { + white-space: pre; + font-family: monospace; + font-size: 12px; +} + +.gerrit-InfoBlock td.useridentity { + white-space: nowrap; +} + +.gerrit-PatchSetInfoBlock { + margin-bottom: 10px; +} + +.gerrit-PatchSetActions { + margin-bottom: 10px; +} +.gerrit-PatchSetActions .gwt-Button { + margin-right: 5px; + font-size: 8pt; +} + +.gerrit-Change-MissingApprovalList { + margin-top: 5px; +} +.gerrit-Change-MissingApproval { + font-weight: bold; + white-space: nowrap; +} + +.gerrit-Change-AddReviewer { + margin-top: 5px; + white-space: nowrap; +} + + +/** SideBySideScreen **/ +.gerrit-SideBySideScreen-SideBySideTable { + width: 100%; + border: 1px solid #B0BDCC; + display: table; +} + +.gerrit-SideBySideScreen-SideBySideTable td.Comment { + border-left: 5px solid orange; + border-right: 5px solid orange; + padding-right: 5px; + background: #fef8cb; +} + +.gerrit-CommentEditor { + background: lightgrey; + padding-left: 5px; + padding-right: 5px; + padding-top: 5px; + padding-bottom: 5px; +} +.gerrit-CommentEditor textarea { + font-size: small; +} +.gerrit-CommentEditor-Buttons { + margin-top: 5px; +} +.gerrit-CommentEditor-Buttons .gwt-Button { + margin-right: 5px; + font-size: 8pt; +} + + +/** Patch History Table **/ +.gerrit-PatchHistoryTable { + width: auto; + margin-bottom: 10px; +} + +.gerrit-PatchHistoryTable .DataCell { + white-space: nowrap; +} + + +/** AccountSettings **/ +.gerrit-SshKeyPanel-EncodedKey { + white-space: nowrap; + text-overflow: ellipsis; + overflow: hidden; + font-family: monospace; + font-size: small; +} +.gerrit-SshKeyPanel-Invalid { + white-space: nowrap; + color: red; + font-weight: bold; +} +.gerrit-Identity-UntrustedExternalId { + white-space: nowrap; + color: red; + font-weight: bold; +} + +.gerrit-AccountInfoBlock { + margin-bottom: 10px; +} +.gerrit-AccountContactPrivacyDetails { + margin-left: 10px; + margin-top: 5px; + margin-bottom: 5px; + width: 40em; +} +.gerrit-AccountContactOnFile { + margin-left: 10px; + margin-top: 5px; + margin-bottom: 5px; + font-weight: bold; +} + +.gerrit-AddSshKeyPanel { + margin-top: 10px; + background-color: #d4e9a9; + padding: 5px 5px 5px 5px; +} + +.gerrit-WatchedProjectPanel { + margin-top: 10px; + padding: 5px 5px 5px 5px; + display: table; + border: 1px solid #b0bdcc; +} + +.gerrit-ContributorAgreement-Button { + font-weight: bold; +} + +.gerrit-ContributorAgreement-ShortDescription { + margin-left: 20px; + margin-right: 20px; + margin-bottom: 10px; + padding: 5px 5px 5px 5px; + border: 1px solid #b0bdcc; +} + +.gerrit-ContributorAgreement-AlreadySubmitted { + margin-left: 20px; + margin-right: 20px; + padding: 5px 5px 5px 5px; + color: red; +} + +.gerrit-ContributorAgreement-Legal { + margin-left: 20px; + margin-right: 20px; + padding: 5px 5px 5px 5px; + border: 1px solid #b0bdcc; +} + +.gerrit-ProjectAdmin-ApprovalCategoryRangeLine { + white-space: nowrap; +} +.gerrit-ProjectAdmin-ApprovalCategoryValue { + font-family: monospace; + font-size: small; +} + + +/** PublishCommentsScreen **/ + +.gerrit-PublishCommentsScreen .gwt-DisclosurePanel .header td { + font-weight: bold; + white-space: nowrap; +} + +.gerrit-PublishCommentsScreen .gerrit-SmallHeading { + font-size: small; + font-weight: bold; + white-space: nowrap; +} +.gerrit-PublishCommentsScreen .gerrit-ApprovalCategoryList { + margin-bottom: 10px; + margin-left: 10px; + background: #d4e9a9; + width: 25em; + white-space: nowrap; + padding-top: 2px; + padding-bottom: 2px; +} +.gerrit-PublishCommentsScreen .gerrit-CoverMessage { + margin-left: 10px; + background: #d4e9a9; + padding: 5px 5px 5px 5px; +} +.gerrit-PublishCommentsScreen .gerrit-CoverMessage textarea { + font-size: small; +} +.gerrit-PublishCommentsScreen .gerrit-ApprovalCategoryList .gwt-RadioButton { + font-size: smaller; +} +.gerrit-PublishCommentsScreen .gerrit-PatchComments { + margin-bottom: 10px; + margin-left: 10px; +} +.gerrit-PublishCommentsScreen .gwt-Hyperlink { + white-space: nowrap; + font-size: small; +} +.gerrit-PublishCommentsScreen .gerrit-LineHeader { + white-space: nowrap; + font-family: monospace; + font-size: small; + font-style: italic; + border-left: 3px solid #e3e3e3; + padding-left: 3px; +} +.gerrit-PublishCommentsScreen .gerrit-PatchLineComment { + border-left: 3px solid #e3e3e3; + padding-left: 6px; +} + + +/** AbandonChangeDialog **/ + +.gerrit-AbandonChangeDialog .gwt-DisclosurePanel .header td { + font-weight: bold; + white-space: nowrap; +} + +.gerrit-AbandonChangeDialog .gerrit-SmallHeading { + font-size: small; + font-weight: bold; + white-space: nowrap; +} +.gerrit-AbandonChangeDialog .gerrit-AbandonMessage { + margin-left: 10px; + background: #d4e9a9; + padding: 5px 5px 5px 5px; +} +.gerrit-AbandonChangeDialog .gerrit-AbandonMessage textarea { + font-size: small; +} +.gerrit-AbandonChangeDialog .gwt-Hyperlink { + white-space: nowrap; + font-size: small; +} + + +/** OpenIdLoginPanel **/ +.gerrit-OpenID-loginform { + margin-left: 10px; +} + +.gerrit-OpenID-logobox { + width: 98%; + text-align: right; +} + +.gerrit-OpenID-loginline { + margin-bottom: 10px; +} + +.gerrit-OpenID-openid_identifier { + background: #ffffff url(openidlogin_bg1.cache.gif) no-repeat scroll 5px 50%; + padding-left: 25px; + border: 1px solid #999999; + margin-right: 5px; +} + +.gerrit-OpenID-directlink { + vertical-align: middle; + margin-right: 5px; + color: blue; +} +.gerrit-OpenID-directlink:hover { + text-decoration: underline; +} +.gerrit-OpenID-directlink img { + margin-right: 3px; + border: 0 none; +} + +.gerrit-OpenID-errorline { + padding-top: 5px; + padding-bottom: 5px; +} +.gerrit-OpenID-errorline span { + padding-top: 4px; + padding-bottom: 4px; + padding-left: 10px; + padding-right: 10px; + background: #fff1a8; +} diff --git a/src/main/java/com/google/gerrit/server/ChangeMail.java b/src/main/java/com/google/gerrit/server/ChangeMail.java index 4c77fd9af5..b0515e96e3 100644 --- a/src/main/java/com/google/gerrit/server/ChangeMail.java +++ b/src/main/java/com/google/gerrit/server/ChangeMail.java @@ -295,6 +295,41 @@ public class ChangeMail { } } + public void sendAbandoned() throws MessagingException { + if (begin("abandon")) { + final Account a = Common.getAccountCache().get(fromId); + if (a == null || a.getFullName() == null || a.getFullName().length() == 0) { + body.append("A Gerrit user"); + } else { + body.append(a.getFullName()); + } + + body.append(" has abandoned a change:\n\n"); + body.append(change.getChangeId()); + body.append(" - "); + body.append(change.getSubject()); + body.append("\n\n"); + + if (message != null) { + body.append(message.getMessage().trim()); + if (body.length() > 0) { + body.append("\n\n"); + } + } + + if (changeUrl() != null) { + openFooter(); + body.append("To view visit "); + body.append(changeUrl()); + body.append("\n"); + } + + initInReplyToChange(); + commentTo(); + send(); + } + } + private void newChangeTo() throws MessagingException { add(RecipientType.TO, reviewers); add(RecipientType.CC, extraCC); diff --git a/src/main/java/com/google/gerrit/server/patch/PatchDetailServiceImpl.java b/src/main/java/com/google/gerrit/server/patch/PatchDetailServiceImpl.java index db835cef62..d95bc139dd 100644 --- a/src/main/java/com/google/gerrit/server/patch/PatchDetailServiceImpl.java +++ b/src/main/java/com/google/gerrit/server/patch/PatchDetailServiceImpl.java @@ -15,6 +15,7 @@ package com.google.gerrit.server.patch; import com.google.gerrit.client.data.ApprovalType; +import com.google.gerrit.client.data.ProjectCache; import com.google.gerrit.client.data.SideBySidePatchDetail; import com.google.gerrit.client.data.UnifiedPatchDetail; import com.google.gerrit.client.patches.PatchDetailService; @@ -28,6 +29,7 @@ import com.google.gerrit.client.reviewdb.Patch; import com.google.gerrit.client.reviewdb.PatchLineComment; import com.google.gerrit.client.reviewdb.PatchSet; import com.google.gerrit.client.reviewdb.PatchSetInfo; +import com.google.gerrit.client.reviewdb.Project; import com.google.gerrit.client.reviewdb.ReviewDb; import com.google.gerrit.client.reviewdb.Account.Id; import com.google.gerrit.client.rpc.BaseServiceImplementation; @@ -355,4 +357,95 @@ public class PatchDetailServiceImpl extends BaseServiceImplementation implements } return VoidResult.INSTANCE; } + + public void abandonChange(final PatchSet.Id patchSetId, final String message, + final AsyncCallback callback) { + run(callback, new Action() { + public VoidResult run(final ReviewDb db) throws OrmException, Failure { + final Account.Id me = Common.getAccountId(); + final Change change = db.changes().get(patchSetId.getParentKey()); + if (change == null) { + throw new Failure(new NoSuchEntityException()); + } + final PatchSet patch = db.patchSets().get(patchSetId); + final ProjectCache.Entry projEnt = + Common.getProjectCache().get(change.getDest().getParentKey()); + if (me == null || patch == null || projEnt == null) { + throw new Failure(new NoSuchEntityException()); + } + final Project proj = projEnt.getProject(); + + if (!me.equals(change.getOwner()) && !me.equals(patch.getUploader()) + && !Common.getGroupCache().isAdministrator(me) + && !Common.getGroupCache().isInGroup(me, proj.getOwnerGroupId())) { + // The user doesn't have permission to abandon the change + throw new Failure(new NoSuchEntityException()); + } + + final ChangeMessage cmsg = + new ChangeMessage(new ChangeMessage.Key(change.getId(), ChangeUtil + .messageUUID(db)), me); + final StringBuilder msgBuf = + new StringBuilder("Patch Set " + change.currentPatchSetId().get() + + ": Abandoned"); + if (message != null && message.length() > 0) { + msgBuf.append("\n\n"); + msgBuf.append(message); + } + cmsg.setMessage(msgBuf.toString()); + + Boolean dbSuccess = db.run(new OrmRunnable() { + public Boolean run(ReviewDb db, Transaction txn, boolean retry) + throws OrmException { + return doAbandonChange(message, change, patchSetId, cmsg, db, txn); + } + }); + + if (dbSuccess) { + // Email the reviewers + try { + final ChangeMail cm = new ChangeMail(server, change); + cm.setFrom(me); + cm.setReviewDb(db); + cm.setChangeMessage(cmsg); + cm.setHttpServletRequest(GerritJsonServlet.getCurrentCall() + .getHttpServletRequest()); + cm.sendAbandoned(); + } catch (MessagingException e) { + log.error("Cannot send abandon change email for change " + + change.getChangeId(), e); + throw new Failure(e); + } + } + + return VoidResult.INSTANCE; + } + }); + } + + private Boolean doAbandonChange(final String message, final Change change, + final PatchSet.Id psid, final ChangeMessage cm, final ReviewDb db, + final Transaction txn) throws OrmException { + + // Check to make sure the change status and current patchset ID haven't + // changed while the user was typing an abandon message + if (change.getStatus() == Change.Status.NEW + && change.currentPatchSetId().equals(psid)) { + change.setStatus(Change.Status.ABANDONED); + ChangeUtil.updated(change); + + final List approvals = + db.changeApprovals().byChange(change.getId()).toList(); + for (ChangeApproval a : approvals) { + a.cache(change); + } + db.changeApprovals().update(approvals, txn); + + db.changeMessages().insert(Collections.singleton(cm), txn); + db.changes().update(Collections.singleton(change), txn); + return Boolean.TRUE; + } + + return Boolean.FALSE; + } } -- cgit v1.2.3