Introduce gr-edit-file-controls
Component is a simple `edit` button and a `more` menu for taking
per-file edit related actions, like reverting, renaming, and deleting
files.
Clicking any button will fire an event that will be caught and handled
by a higher-level component that has yet to be implemented.
Bug: Issue 4437
Change-Id: I1ded6d261562039b094ac2bafa60d7aa9603444b
diff --git a/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list.html b/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list.html
index f31841f..f80ff0a 100644
--- a/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list.html
+++ b/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list.html
@@ -23,6 +23,7 @@
<link rel="import" href="../../diff/gr-comment-api/gr-comment-api.html">
<link rel="import" href="../../diff/gr-diff/gr-diff.html">
<link rel="import" href="../../diff/gr-diff-cursor/gr-diff-cursor.html">
+<link rel="import" href="../../edit/gr-edit-file-controls/gr-edit-file-controls.html">
<link rel="import" href="../../shared/gr-button/gr-button.html">
<link rel="import" href="../../shared/gr-cursor-manager/gr-cursor-manager.html">
<link rel="import" href="../../shared/gr-linked-text/gr-linked-text.html">
@@ -50,6 +51,12 @@
:host(.editLoaded) .hideOnEdit {
display: none;
}
+ .showOnEdit {
+ display: none;
+ }
+ :host(.editLoaded) .showOnEdit {
+ display: initial;
+ }
.reviewed,
.status {
align-items: center;
@@ -184,6 +191,10 @@
display: initial;
opacity: 100;
}
+ .editFileControls {
+ margin-left: 1em;
+ width: 4em;
+ }
@media screen and (max-width: 50em) {
.desktop {
display: none;
@@ -299,6 +310,12 @@
<span class="markReviewed" title="Mark as reviewed (shortcut: r)">[[_computeReviewedText(file.isReviewed)]]</span>
</label>
</div>
+ <div class="editFileControls showOnEdit">
+ <gr-edit-file-controls
+ class$="[[_computeClass('', file.__path)]]"
+ file-path="[[file.__path]]"
+ on-edit-tap="_handleEditTap"></gr-edit-file-controls>
+ </div>
</div>
<template is="dom-if"
if="[[_isFileExpanded(file.__path, _expandedFilePaths.*)]]">
@@ -338,6 +355,7 @@
</div>
<!-- Empty div here exists to keep spacing in sync with file rows. -->
<div class="reviewed hideOnEdit" hidden$="[[!_loggedIn]]" hidden></div>
+ <div class="editFileControls showOnEdit"></div>
</div>
<div
class$="row totalChanges [[_computeExpandInlineClass(_userPrefs)]]"
diff --git a/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list.js b/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list.js
index 11a4a29..70f1d4d 100644
--- a/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list.js
+++ b/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list.js
@@ -926,5 +926,10 @@
_computeReviewedText(isReviewed) {
return isReviewed ? 'MARK UNREVIEWED' : 'MARK REVIEWED';
},
+
+ _handleEditTap(e) {
+ const url = Gerrit.Nav.getEditUrlForDiff(this.change, e.detail.path);
+ Gerrit.Nav.navigateToRelativeUrl(url);
+ },
});
})();
diff --git a/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list_test.html b/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list_test.html
index b80a20f..b01c105 100644
--- a/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list_test.html
+++ b/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list_test.html
@@ -1238,6 +1238,20 @@
});
});
});
+
+ test('editing actions', () => {
+ element.editLoaded = true;
+ element.change = {_number: '42', project: 'test'};
+ const navStub = sandbox.stub(Gerrit.Nav, 'navigateToRelativeUrl');
+ const editControls =
+ Polymer.dom(element.root).querySelectorAll('.row:not(.header)')
+ .map(row => row.querySelector('gr-edit-file-controls'));
+
+ // Commit message should not have edit controls.
+ assert.isTrue(editControls[0].classList.contains('invisible'));
+ MockInteractions.tap(editControls[1].$.edit);
+ assert.isTrue(navStub.called);
+ });
});
a11ySuite('basic');
</script>
diff --git a/polygerrit-ui/app/elements/core/gr-navigation/gr-navigation.html b/polygerrit-ui/app/elements/core/gr-navigation/gr-navigation.html
index b03f2e5..8453da9 100644
--- a/polygerrit-ui/app/elements/core/gr-navigation/gr-navigation.html
+++ b/polygerrit-ui/app/elements/core/gr-navigation/gr-navigation.html
@@ -57,6 +57,7 @@
console.warn('Use of uninitialized routing');
};
+ const EDIT_PATCHNUM = 'edit';
const PARENT_PATCHNUM = 'PARENT';
window.Gerrit.Nav = {
@@ -277,6 +278,7 @@
changeNum,
project,
path,
+ patchNum: EDIT_PATCHNUM,
});
},
diff --git a/polygerrit-ui/app/elements/core/gr-router/gr-router.js b/polygerrit-ui/app/elements/core/gr-router/gr-router.js
index 98a0ae5..708cb17 100644
--- a/polygerrit-ui/app/elements/core/gr-router/gr-router.js
+++ b/polygerrit-ui/app/elements/core/gr-router/gr-router.js
@@ -191,8 +191,9 @@
_generateUrl(params) {
const base = this.getBaseUrl();
let url = '';
+ const Views = Gerrit.Nav.View;
- if (params.view === Gerrit.Nav.View.SEARCH) {
+ if (params.view === Views.SEARCH) {
const operators = [];
if (params.owner) {
operators.push('owner:' + this.encodeURL(params.owner, false));
@@ -223,7 +224,7 @@
}
}
url = '/q/' + operators.join('+');
- } else if (params.view === Gerrit.Nav.View.CHANGE) {
+ } else if (params.view === Views.CHANGE) {
let range = this._getPatchRangeExpression(params);
if (range.length) { range = '/' + range; }
if (params.project) {
@@ -231,7 +232,7 @@
} else {
url = `/c/${params.changeNum}${range}`;
}
- } else if (params.view === Gerrit.Nav.View.DASHBOARD) {
+ } else if (params.view === Views.DASHBOARD) {
if (params.sections) {
// Custom dashboard.
const queryParams = params.sections.map(section => {
@@ -247,11 +248,14 @@
// User dashboard.
url = `/dashboard/${params.user || 'self'}`;
}
- } else if (params.view === Gerrit.Nav.View.DIFF) {
+ } else if (params.view === Views.DIFF || params.view === Views.EDIT) {
let range = this._getPatchRangeExpression(params);
if (range.length) { range = '/' + range; }
let suffix = `${range}/${this.encodeURL(params.path, true)}`;
+
+ if (params.view === Views.EDIT) { suffix += ',edit'; }
+
if (params.lineNum) {
suffix += '#';
if (params.leftSide) { suffix += 'b'; }
@@ -263,9 +267,6 @@
} else {
url = `/c/${params.changeNum}${suffix}`;
}
- if (params.edit) {
- url += ',edit';
- }
} else {
throw new Error('Can\'t generate');
}
diff --git a/polygerrit-ui/app/elements/core/gr-router/gr-router_test.html b/polygerrit-ui/app/elements/core/gr-router/gr-router_test.html
index 823c701..4aae65f 100644
--- a/polygerrit-ui/app/elements/core/gr-router/gr-router_test.html
+++ b/polygerrit-ui/app/elements/core/gr-router/gr-router_test.html
@@ -280,6 +280,17 @@
'/c/test/+/42/2/file.cpp#b123');
});
+ test('edit', () => {
+ const params = {
+ view: Gerrit.Nav.View.EDIT,
+ changeNum: '42',
+ project: 'test',
+ path: 'x+y/path.cpp',
+ };
+ assert.equal(element._generateUrl(params),
+ '/c/test/+/42/x%252By/path.cpp,edit');
+ });
+
test('_getPatchRangeExpression', () => {
const params = {};
let actual = element._getPatchRangeExpression(params);
diff --git a/polygerrit-ui/app/elements/edit/gr-edit-file-controls/gr-edit-file-controls.html b/polygerrit-ui/app/elements/edit/gr-edit-file-controls/gr-edit-file-controls.html
new file mode 100644
index 0000000..bfbe11a
--- /dev/null
+++ b/polygerrit-ui/app/elements/edit/gr-edit-file-controls/gr-edit-file-controls.html
@@ -0,0 +1,48 @@
+<!--
+Copyright (C) 2017 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.
+-->
+
+<link rel="import" href="../../../bower_components/polymer/polymer.html">
+
+<link rel="import" href="../../shared/gr-button/gr-button.html">
+<link rel="import" href="../../shared/gr-dropdown/gr-dropdown.html">
+
+<link rel="import" href="../../../styles/shared-styles.html">
+
+<dom-module id="gr-edit-file-controls">
+ <template>
+ <style include="shared-styles">
+ :host {
+ align-items: center;
+ display: flex;
+ justify-content: flex-end;
+ }
+ #edit {
+ margin-right: .5em;
+ text-decoration: none;
+ }
+ </style>
+ <gr-button
+ id="edit"
+ link
+ on-tap="_handleEditTap">Edit</gr-button>
+ <!-- TODO(kaspern): implement more menu. -->
+ <gr-dropdown
+ id="more"
+ hidden
+ link>More</gr-dropdown>
+ </template>
+ <script src="gr-edit-file-controls.js"></script>
+</dom-module>
\ No newline at end of file
diff --git a/polygerrit-ui/app/elements/edit/gr-edit-file-controls/gr-edit-file-controls.js b/polygerrit-ui/app/elements/edit/gr-edit-file-controls/gr-edit-file-controls.js
new file mode 100644
index 0000000..1c87621
--- /dev/null
+++ b/polygerrit-ui/app/elements/edit/gr-edit-file-controls/gr-edit-file-controls.js
@@ -0,0 +1,34 @@
+// Copyright (C) 2017 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.
+(function() {
+ 'use strict';
+
+ Polymer({
+ is: 'gr-edit-file-controls',
+
+ /**
+ * Fired when the edit button is pressed.
+ *
+ * @event edit-tap
+ */
+
+ properties: {
+ filePath: String,
+ },
+
+ _handleEditTap() {
+ this.fire('edit-tap', {path: this.filePath});
+ },
+ });
+})();
\ No newline at end of file
diff --git a/polygerrit-ui/app/elements/edit/gr-edit-file-controls/gr-edit-file-controls_test.html b/polygerrit-ui/app/elements/edit/gr-edit-file-controls/gr-edit-file-controls_test.html
new file mode 100644
index 0000000..250e208
--- /dev/null
+++ b/polygerrit-ui/app/elements/edit/gr-edit-file-controls/gr-edit-file-controls_test.html
@@ -0,0 +1,56 @@
+<!--
+Copyright (C) 2017 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.
+-->
+
+<meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1.0, user-scalable=yes">
+<title>gr-edit-file-controls</title>
+
+<script src="../../../bower_components/webcomponentsjs/webcomponents-lite.min.js"></script>
+<script src="../../../bower_components/web-component-tester/browser.js"></script>
+<link rel="import" href="../../../test/common-test-setup.html"/>
+
+<link rel="import" href="gr-edit-file-controls.html">
+
+<script>void(0);</script>
+
+<test-fixture id="basic">
+ <template>
+ <gr-edit-file-controls></gr-edit-file-controls>
+ </template>
+</test-fixture>
+
+<script>
+suite('gr-edit-file-controls tests', () => {
+ let element;
+ let sandbox;
+
+ setup(() => {
+ sandbox = sinon.sandbox.create();
+ element = fixture('basic');
+ });
+
+ teardown(() => { sandbox.restore(); });
+
+ test('edit tap emits event', () => {
+ const handler = sandbox.stub();
+ element.addEventListener('edit-tap', handler);
+ element.filePath = 'foo';
+
+ MockInteractions.tap(element.$.edit);
+ assert.isTrue(handler.called);
+ assert.equal(handler.lastCall.args[0].detail.path, 'foo');
+ });
+});
+</script>
\ No newline at end of file
diff --git a/polygerrit-ui/app/elements/edit/gr-editor-view/gr-editor-view.html b/polygerrit-ui/app/elements/edit/gr-editor-view/gr-editor-view.html
index ff144c3..df2ac93 100644
--- a/polygerrit-ui/app/elements/edit/gr-editor-view/gr-editor-view.html
+++ b/polygerrit-ui/app/elements/edit/gr-editor-view/gr-editor-view.html
@@ -36,7 +36,7 @@
gr-fixed-panel {
background-color: #fff;
border-bottom: 1px #eee solid;
- z-index: 1;
+ z-index: 10;
}
header,
.subHeader {
@@ -94,7 +94,7 @@
</header>
</gr-fixed-panel>
<div class="textareaWrapper">
- <textarea id="file">{{_newContent}}</textarea>
+ <textarea value="{{_newContent::input}}" id="file"></textarea>
</div>
<gr-rest-api-interface id="restAPI"></gr-rest-api-interface>
</template>
diff --git a/polygerrit-ui/app/elements/edit/gr-editor-view/gr-editor-view.js b/polygerrit-ui/app/elements/edit/gr-editor-view/gr-editor-view.js
index b8a3f9d..86594d3 100644
--- a/polygerrit-ui/app/elements/edit/gr-editor-view/gr-editor-view.js
+++ b/polygerrit-ui/app/elements/edit/gr-editor-view/gr-editor-view.js
@@ -111,11 +111,11 @@
if (res.status === 404) {
// No edits have been made yet.
return this.$.restAPI.getFileInChangeEdit(changeNum, path, true)
- .then(res => res.text().then(text => atob(text)));
+ .then(res => res.text);
}
return '';
}
- return res.text().then(text => atob(text));
+ return res.text;
});
},
diff --git a/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-api-interface.js b/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-api-interface.js
index c124e54..c206b20 100644
--- a/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-api-interface.js
+++ b/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-api-interface.js
@@ -1265,7 +1265,14 @@
const e = '/edit/' + encodeURIComponent(path);
let payload = null;
if (opt_base) { payload = {base: true}; }
- return this.getChangeURLAndSend(changeNum, 'GET', null, e, payload);
+ return this.getChangeURLAndSend(changeNum, 'GET', null, e, payload)
+ .then(res => {
+ if (!res.ok) { return res; }
+ return res.text().then(text => {
+ res.text = atob(text);
+ return res;
+ });
+ });
},
rebaseChangeEdit(changeNum) {
diff --git a/polygerrit-ui/app/test/index.html b/polygerrit-ui/app/test/index.html
index ace6a2d..ee3111e 100644
--- a/polygerrit-ui/app/test/index.html
+++ b/polygerrit-ui/app/test/index.html
@@ -102,6 +102,7 @@
'diff/gr-selection-action-box/gr-selection-action-box_test.html',
'diff/gr-syntax-layer/gr-syntax-layer_test.html',
'diff/gr-syntax-lib-loader/gr-syntax-lib-loader_test.html',
+ 'edit/gr-edit-file-controls/gr-edit-file-controls_test.html',
'edit/gr-editor-view/gr-editor-view_test.html',
'plugins/gr-attribute-helper/gr-attribute-helper_test.html',
'plugins/gr-endpoint-decorator/gr-endpoint-decorator_test.html',