Add support for file uploads in the UI

The UI for uploading is from @Thomas Dräbing

Screenshot: https://imgur.com/a/dL91kwI

Change-Id: Ia19d38d96aeb946faacc7c5d62505186e2e6f4c5
This commit is contained in:
Paladox none
2019-11-20 15:52:35 +00:00
parent 816cb61036
commit a669b899d3
4 changed files with 95 additions and 1 deletions

View File

@@ -216,6 +216,21 @@ class GrEditControls extends mixinBehaviors( [
this._closeDialog(this._getDialogFromEvent(e), true);
}
_handleUploadConfirm(path, fileData) {
if (!this.change || !path || !fileData) {
this._closeDialog(this.$.openDialog, true);
return;
}
this.$.restAPI.saveFileUploadChangeEdit(this.change._number, path,
fileData).then(res => {
if (!res.ok) { return; }
this._closeDialog(this.$.openDialog, true);
const url = Gerrit.Nav.getUrlForChange(this.change, this.patchNum);
Gerrit.Nav.navigateToRelativeUrl(url);
});
}
_handleDeleteConfirm(e) {
// Get the dialog before the api call as the event will change during bubbling
// which will make Polymer.dom(e).path an emtpy array in polymer 2
@@ -258,6 +273,39 @@ class GrEditControls extends mixinBehaviors( [
_computeIsInvisible(id, hiddenActions) {
return hiddenActions.includes(id) ? 'invisible' : '';
}
_handleDragAndDropUpload(event) {
// We prevent the default clicking.
event.preventDefault();
event.stopPropagation();
this._fileUpload(event);
}
_handleFileUploadChanged(event) {
this._fileUpload(event);
}
_fileUpload(event) {
const e = event.target.files || event.dataTransfer.files;
for (const file of e) {
if (!file) continue;
let path = this._path;
if (!path) {
path = file.name;
}
const fr = new FileReader();
fr.file = file;
fr.onload = fileLoadEvent => {
if (!fileLoadEvent) return;
const fileData = fileLoadEvent.target.result;
this._handleUploadConfirm(path, fileData);
};
fr.readAsDataURL(file);
}
}
}
customElements.define(GrEditControls.is, GrEditControls);

View File

@@ -47,6 +47,20 @@ export const htmlTemplate = html`
width: 100%;
box-sizing: content-box;
}
#fileUploadBrowse {
margin-left: 0;
}
#dragDropArea {
border: 2px dashed var(--border-color);
border-radius: var(--border-radius);
margin-top: var(--spacing-l);
padding: var(--spacing-xxl) var(--spacing-xxl);
text-align: center;
}
#dragDropArea > p {
font-weight: var(--font-weight-bold);
padding: var(--spacing-s);
}
@media screen and (max-width: 50em) {
gr-dialog {
width: 100vw;
@@ -63,6 +77,25 @@ export const htmlTemplate = html`
</div>
<div class="main" slot="main">
<gr-autocomplete placeholder="Enter an existing or new full file path." query="[[_query]]" text="{{_path}}"></gr-autocomplete>
<div id="dragDropArea"
contenteditable="true"
on-drop="_handleDragAndDropUpload">
<p>Drag and drop a file here</p>
<p>or</p>
<p>
<iron-input>
<input id="fileUploadInput"
type="file"
on-change="_handleFileUploadChanged"
slot="input">
</iron-input>
<label for="fileUploadInput">
<gr-button id="fileUploadBrowse">
Browse
</gr-button>
</label>
</p>
</div>
</div>
</gr-dialog>
<gr-dialog id="deleteDialog" class="invisible dialog" disabled\$="[[!_isValidPath(_path)]]" confirm-label="Delete" confirm-on-enter="" on-confirm="_handleDeleteConfirm" on-cancel="_handleDialogCancel">

View File

@@ -56,7 +56,10 @@ suite('gr-edit-controls tests', () => {
teardown(() => { sandbox.restore(); });
test('all actions exist', () => {
assert.equal(dom(element.root).querySelectorAll('gr-button').length,
// We take 1 away from the total found, due to an extra button being
// added for the file uploads (browse).
assert.equal(
dom(element.root).querySelectorAll('gr-button').length - 1,
element._actions.length);
});

View File

@@ -1855,6 +1855,16 @@ class GrRestApiInterface extends mixinBehaviors( [
});
}
saveFileUploadChangeEdit(changeNum, path, content) {
return this._getChangeURLAndSend({
changeNum,
method: 'PUT',
endpoint: '/edit/' + encodeURIComponent(path),
body: {binary_content: content},
anonymizedEndpoint: '/edit/*',
});
}
getRobotCommentFixPreview(changeNum, patchNum, fixId) {
return this._getChangeURLAndFetch({
changeNum,