Merge "Add download commands to project pages"
This commit is contained in:
@@ -18,183 +18,207 @@ limitations under the License.
|
||||
<link rel="import" href="../../../bower_components/iron-autogrow-textarea/iron-autogrow-textarea.html">
|
||||
<link rel="import" href="../../../bower_components/iron-input/iron-input.html">
|
||||
|
||||
<link rel="import" href="../../shared/gr-download-commands/gr-download-commands.html">
|
||||
<link rel="import" href="../../shared/gr-rest-api-interface/gr-rest-api-interface.html">
|
||||
<link rel="import" href="../../shared/gr-select/gr-select.html">
|
||||
<link rel="import" href="../../../styles/gr-form-styles.html">
|
||||
<link rel="import" href="../../../styles/shared-styles.html">
|
||||
|
||||
|
||||
<dom-module id="gr-admin-project">
|
||||
<template>
|
||||
<style include="shared-styles">
|
||||
main {
|
||||
margin: 2em 1em;
|
||||
}
|
||||
|
||||
h1.edited:after {
|
||||
h2.edited:after {
|
||||
color: #444;
|
||||
content: ' *';
|
||||
}
|
||||
.loading,
|
||||
.hideDownload {
|
||||
display: none;
|
||||
}
|
||||
#loading.loading {
|
||||
display: block;
|
||||
}
|
||||
#loading:not(.loading) {
|
||||
display: none;
|
||||
}
|
||||
</style>
|
||||
<style include="gr-form-styles"></style>
|
||||
<main class="gr-form-styles read-only">
|
||||
<h1 id="Title" class$="[[_computeHeaderClass(_configChanged)]]">
|
||||
[[project]]</h1>
|
||||
<div id="loading" hidden$="[[!_loading]]" hidden>Loading...</div>
|
||||
<div id="form" hidden$="[[_loading]]" hidden>
|
||||
<h2 id="Description">Description</h2>
|
||||
<fieldset>
|
||||
<iron-autogrow-textarea
|
||||
id="descriptionInput"
|
||||
class="description"
|
||||
autocomplete="on"
|
||||
placeholder="<Insert project description here>"
|
||||
bind-value="{{_projectConfig.description}}"
|
||||
disabled$="[[_readOnly]]"></iron-autogrow-textarea>
|
||||
</fieldset>
|
||||
<h2 id="Options">Project Options</h2>
|
||||
<fieldset id="options">
|
||||
<section>
|
||||
<span class="title">State</span>
|
||||
<span class="value">
|
||||
<select
|
||||
id="stateSelect"
|
||||
is="gr-select"
|
||||
bind-value="{{_projectConfig.state}}"
|
||||
disabled$="[[_readOnly]]">
|
||||
<template is="dom-repeat" items=[[_states]]>
|
||||
<option value="[[item.value]]">[[item.label]]</option>
|
||||
</template>
|
||||
</select>
|
||||
</span>
|
||||
</section>
|
||||
<section>
|
||||
<span class="title">Submit type</span>
|
||||
<span class="value">
|
||||
<select
|
||||
id="submitTypeSelect"
|
||||
is="gr-select"
|
||||
bind-value="{{_projectConfig.submit_type}}"
|
||||
disabled$="[[_readOnly]]">>
|
||||
<template is="dom-repeat" items="[[_submitTypes]]">
|
||||
<option value="[[item.value]]">[[item.label]]</option>
|
||||
</template>
|
||||
</select>
|
||||
</span>
|
||||
</section>
|
||||
<section>
|
||||
<span class="title">Allow content merges</span>
|
||||
<span class="value">
|
||||
<select
|
||||
id="contentMergeSelect"
|
||||
is="gr-select"
|
||||
bind-value="{{_projectConfig.use_content_merge.configured_value}}"
|
||||
disabled$="[[_readOnly]]">>
|
||||
<template is="dom-repeat"
|
||||
items="[[_formatBooleanSelect(_projectConfig.use_content_merge)]]">
|
||||
<option value="[[item.value]]">[[item.label]]</option>
|
||||
</template>
|
||||
</select>
|
||||
</span>
|
||||
</section>
|
||||
<section>
|
||||
<span class="title">
|
||||
Create a new change for every commit not in the target branch
|
||||
</span>
|
||||
<span class="value">
|
||||
<select
|
||||
id="newChangeSelect"
|
||||
is="gr-select"
|
||||
bind-value="{{_projectConfig.create_new_change_for_all_not_in_target.configured_value}}"
|
||||
disabled$="[[_readOnly]]">>
|
||||
<template is="dom-repeat"
|
||||
items="[[_formatBooleanSelect(_projectConfig.create_new_change_for_all_not_in_target)]]">
|
||||
<option value="[[item.value]]">[[item.label]]</option>
|
||||
</template>
|
||||
</select>
|
||||
</span>
|
||||
</section>
|
||||
<section>
|
||||
<span class="title">Require Change-Id in commit message</span>
|
||||
<span class="value">
|
||||
<select
|
||||
id="requireChangeIdSelect"
|
||||
is="gr-select"
|
||||
bind-value="{{_projectConfig.require_change_id.configured_value}}"
|
||||
disabled$="[[_readOnly]]">>
|
||||
<template is="dom-repeat"
|
||||
items="[[_formatBooleanSelect(_projectConfig.require_change_id)]]">
|
||||
<option value="[[item.value]]">[[item.label]]</option>
|
||||
</template>
|
||||
</select>
|
||||
</span>
|
||||
</section>
|
||||
<section>
|
||||
<span class="title">
|
||||
Reject implicit merges when changes are pushed for review</span>
|
||||
<span class="value">
|
||||
<select
|
||||
id="rejectImplicitMergesSelect"
|
||||
is="gr-select"
|
||||
bind-value="{{_projectConfig.reject_implicit_merges.configured_value}}"
|
||||
disabled$="[[_readOnly]]">>
|
||||
<template is="dom-repeat"
|
||||
items="[[_formatBooleanSelect(_projectConfig.reject_implicit_merges)]]">
|
||||
<option value="[[item.value]]">[[item.label]]</option>
|
||||
</template>
|
||||
</select>
|
||||
</span>
|
||||
</section>
|
||||
<section>
|
||||
<span class="title">Maximum Git object size limit</span>
|
||||
<span class="value">
|
||||
<input
|
||||
id="maxGitObjSizeInput"
|
||||
bind-value="{{_projectConfig.max_object_size_limit.configured_value}}"
|
||||
is="iron-input"
|
||||
type="text"
|
||||
disabled$="[[_readOnly]]">
|
||||
</span>
|
||||
</section>
|
||||
</fieldset>
|
||||
<h2 id="Options">Contributor Agreements</h2>
|
||||
<fieldset id="agreements">
|
||||
<section>
|
||||
<span class="title">
|
||||
Require a valid contributor agreement to upload</span>
|
||||
<span class="value">
|
||||
<select
|
||||
id="contributorAgreementSelect"
|
||||
is="gr-select"
|
||||
bind-value="{{_projectConfig.use_contributor_agreements.configured_value}}"
|
||||
disabled$="[[_readOnly]]">>
|
||||
<template is="dom-repeat"
|
||||
items="[[_formatBooleanSelect(_projectConfig.use_contributor_agreements)]]">
|
||||
<option value="[[item.value]]">[[item.label]]</option>
|
||||
</template>
|
||||
</select>
|
||||
</span>
|
||||
</section>
|
||||
<section>
|
||||
<span class="title">Require Signed-off-by in commit message</span>
|
||||
<span class="value">
|
||||
<select
|
||||
id="useSignedOffBySelect"
|
||||
is="gr-select"
|
||||
bind-value="{{_projectConfig.use_signed_off_by.configured_value}}"
|
||||
disabled$="[[_readOnly]]">>
|
||||
<template is="dom-repeat"
|
||||
items="[[_formatBooleanSelect(_projectConfig.use_signed_off_by)]]">
|
||||
<option value="[[item.value]]">[[item.label]]</option>
|
||||
</template>
|
||||
</select>
|
||||
</span>
|
||||
</section>
|
||||
</fieldset>
|
||||
<!-- TODO @beckysiegel add plugin config widgets -->
|
||||
<gr-button
|
||||
on-tap="_handleSaveProjectConfig"
|
||||
disabled$="[[_computeButtonDisabled(_readOnly, _configChanged)]]">Save changes</gr-button>
|
||||
<h1 id="Title">[[project]]</h1>
|
||||
<div id="loading" class$="[[_computeLoadingClass(_loading)]]">Loading...</div>
|
||||
<div id="loadedContent" class$="[[_computeLoadingClass(_loading)]]">
|
||||
<div id="downloadContent" class$="[[_computeDownloadClass(_schemes)]]">
|
||||
<h2 id="download">Download</h2>
|
||||
<fieldset>
|
||||
<gr-download-commands
|
||||
id="downloadCommands"
|
||||
commands="[[_computeCommands(project, _schemesObj, _selectedScheme)]]"
|
||||
schemes="[[_schemes]]"
|
||||
selected-scheme="{{_selectedScheme}}"></gr-download-commands>
|
||||
</fieldset>
|
||||
</div>
|
||||
<h2 id="configurations"
|
||||
class$="[[_computeHeaderClass(_configChanged)]]">Configurations</h2>
|
||||
<div id="form">
|
||||
<fieldset>
|
||||
<h3 id="Description">Description</h3>
|
||||
<fieldset>
|
||||
<iron-autogrow-textarea
|
||||
id="descriptionInput"
|
||||
class="description"
|
||||
autocomplete="on"
|
||||
placeholder="<Insert project description here>"
|
||||
bind-value="{{_projectConfig.description}}"
|
||||
disabled$="[[_readOnly]]"></iron-autogrow-textarea>
|
||||
</fieldset>
|
||||
<h3 id="Options">Project Options</h3>
|
||||
<fieldset id="options">
|
||||
<section>
|
||||
<span class="title">State</span>
|
||||
<span class="value">
|
||||
<select
|
||||
id="stateSelect"
|
||||
is="gr-select"
|
||||
bind-value="{{_projectConfig.state}}"
|
||||
disabled$="[[_readOnly]]">
|
||||
<template is="dom-repeat" items=[[_states]]>
|
||||
<option value="[[item.value]]">[[item.label]]</option>
|
||||
</template>
|
||||
</select>
|
||||
</span>
|
||||
</section>
|
||||
<section>
|
||||
<span class="title">Submit type</span>
|
||||
<span class="value">
|
||||
<select
|
||||
id="submitTypeSelect"
|
||||
is="gr-select"
|
||||
bind-value="{{_projectConfig.submit_type}}"
|
||||
disabled$="[[_readOnly]]">>
|
||||
<template is="dom-repeat" items="[[_submitTypes]]">
|
||||
<option value="[[item.value]]">[[item.label]]</option>
|
||||
</template>
|
||||
</select>
|
||||
</span>
|
||||
</section>
|
||||
<section>
|
||||
<span class="title">Allow content merges</span>
|
||||
<span class="value">
|
||||
<select
|
||||
id="contentMergeSelect"
|
||||
is="gr-select"
|
||||
bind-value="{{_projectConfig.use_content_merge.configured_value}}"
|
||||
disabled$="[[_readOnly]]">>
|
||||
<template is="dom-repeat"
|
||||
items="[[_formatBooleanSelect(_projectConfig.use_content_merge)]]">
|
||||
<option value="[[item.value]]">[[item.label]]</option>
|
||||
</template>
|
||||
</select>
|
||||
</span>
|
||||
</section>
|
||||
<section>
|
||||
<span class="title">
|
||||
Create a new change for every commit not in the target branch
|
||||
</span>
|
||||
<span class="value">
|
||||
<select
|
||||
id="newChangeSelect"
|
||||
is="gr-select"
|
||||
bind-value="{{_projectConfig.create_new_change_for_all_not_in_target.configured_value}}"
|
||||
disabled$="[[_readOnly]]">>
|
||||
<template is="dom-repeat"
|
||||
items="[[_formatBooleanSelect(_projectConfig.create_new_change_for_all_not_in_target)]]">
|
||||
<option value="[[item.value]]">[[item.label]]</option>
|
||||
</template>
|
||||
</select>
|
||||
</span>
|
||||
</section>
|
||||
<section>
|
||||
<span class="title">Require Change-Id in commit message</span>
|
||||
<span class="value">
|
||||
<select
|
||||
id="requireChangeIdSelect"
|
||||
is="gr-select"
|
||||
bind-value="{{_projectConfig.require_change_id.configured_value}}"
|
||||
disabled$="[[_readOnly]]">>
|
||||
<template is="dom-repeat"
|
||||
items="[[_formatBooleanSelect(_projectConfig.require_change_id)]]">
|
||||
<option value="[[item.value]]">[[item.label]]</option>
|
||||
</template>
|
||||
</select>
|
||||
</span>
|
||||
</section>
|
||||
<section>
|
||||
<span class="title">
|
||||
Reject implicit merges when changes are pushed for review</span>
|
||||
<span class="value">
|
||||
<select
|
||||
id="rejectImplicitMergesSelect"
|
||||
is="gr-select"
|
||||
bind-value="{{_projectConfig.reject_implicit_merges.configured_value}}"
|
||||
disabled$="[[_readOnly]]">>
|
||||
<template is="dom-repeat"
|
||||
items="[[_formatBooleanSelect(_projectConfig.reject_implicit_merges)]]">
|
||||
<option value="[[item.value]]">[[item.label]]</option>
|
||||
</template>
|
||||
</select>
|
||||
</span>
|
||||
</section>
|
||||
<section>
|
||||
<span class="title">Maximum Git object size limit</span>
|
||||
<span class="value">
|
||||
<input
|
||||
id="maxGitObjSizeInput"
|
||||
bind-value="{{_projectConfig.max_object_size_limit.configured_value}}"
|
||||
is="iron-input"
|
||||
type="text"
|
||||
disabled$="[[_readOnly]]">
|
||||
</span>
|
||||
</section>
|
||||
</fieldset>
|
||||
<h3 id="Options">Contributor Agreements</h3>
|
||||
<fieldset id="agreements">
|
||||
<section>
|
||||
<span class="title">
|
||||
Require a valid contributor agreement to upload</span>
|
||||
<span class="value">
|
||||
<select
|
||||
id="contributorAgreementSelect"
|
||||
is="gr-select"
|
||||
bind-value="{{_projectConfig.use_contributor_agreements.configured_value}}"
|
||||
disabled$="[[_readOnly]]">>
|
||||
<template is="dom-repeat"
|
||||
items="[[_formatBooleanSelect(_projectConfig.use_contributor_agreements)]]">
|
||||
<option value="[[item.value]]">[[item.label]]</option>
|
||||
</template>
|
||||
</select>
|
||||
</span>
|
||||
</section>
|
||||
<section>
|
||||
<span class="title">Require Signed-off-by in commit message</span>
|
||||
<span class="value">
|
||||
<select
|
||||
id="useSignedOffBySelect"
|
||||
is="gr-select"
|
||||
bind-value="{{_projectConfig.use_signed_off_by.configured_value}}"
|
||||
disabled$="[[_readOnly]]">>
|
||||
<template is="dom-repeat"
|
||||
items="[[_formatBooleanSelect(_projectConfig.use_signed_off_by)]]">
|
||||
<option value="[[item.value]]">[[item.label]]</option>
|
||||
</template>
|
||||
</select>
|
||||
</span>
|
||||
</section>
|
||||
</fieldset>
|
||||
<!-- TODO @beckysiegel add plugin config widgets -->
|
||||
<gr-button
|
||||
on-tap="_handleSaveProjectConfig"
|
||||
disabled$="[[_computeButtonDisabled(_readOnly, _configChanged)]]">Save changes</gr-button>
|
||||
</fieldset>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
<gr-rest-api-interface id="restAPI"></gr-rest-api-interface>
|
||||
|
||||
@@ -58,6 +58,11 @@
|
||||
type: Boolean,
|
||||
value: true,
|
||||
},
|
||||
_loggedIn: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
observer: '_loggedInChanged',
|
||||
},
|
||||
_projectConfig: Object,
|
||||
_readOnly: {
|
||||
type: Boolean,
|
||||
@@ -75,13 +80,24 @@
|
||||
return Object.values(SUBMIT_TYPES);
|
||||
},
|
||||
},
|
||||
_schemes: {
|
||||
type: Array,
|
||||
value() { return []; },
|
||||
computed: '_computeSchemes(_schemesObj)',
|
||||
observer: '_schemesChanged',
|
||||
},
|
||||
_selectedCommand: {
|
||||
type: String,
|
||||
value: 'Clone',
|
||||
},
|
||||
_selectedScheme: String,
|
||||
_schemesObj: Object,
|
||||
},
|
||||
|
||||
observers: [
|
||||
'_handleConfigChanged(_projectConfig.*)',
|
||||
],
|
||||
|
||||
|
||||
attached() {
|
||||
this._loadProject();
|
||||
},
|
||||
@@ -109,9 +125,31 @@
|
||||
this._loading = false;
|
||||
}));
|
||||
|
||||
promises.push(this.$.restAPI.getConfig().then(config => {
|
||||
this._schemesObj = config.download.schemes;
|
||||
}));
|
||||
|
||||
return Promise.all(promises);
|
||||
},
|
||||
|
||||
_computeLoadingClass(loading) {
|
||||
return loading ? 'loading' : '';
|
||||
},
|
||||
|
||||
_computeDownloadClass(schemes) {
|
||||
return !schemes || !schemes.length ? 'hideDownload' : '';
|
||||
},
|
||||
|
||||
_loggedInChanged(_loggedIn) {
|
||||
if (!_loggedIn) { return; }
|
||||
this.$.restAPI.getPreferences().then(prefs => {
|
||||
if (prefs.download_scheme) {
|
||||
// Note (issue 5180): normalize the download scheme with lower-case.
|
||||
this._selectedScheme = prefs.download_scheme.toLowerCase();
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
_formatBooleanSelect(item) {
|
||||
if (!item) { return; }
|
||||
let inheritLabel = 'Inherit';
|
||||
@@ -174,5 +212,34 @@
|
||||
_computeHeaderClass(configChanged) {
|
||||
return configChanged ? 'edited' : '';
|
||||
},
|
||||
|
||||
_computeSchemes(schemesObj) {
|
||||
return Object.keys(schemesObj);
|
||||
},
|
||||
|
||||
_schemesChanged(schemes) {
|
||||
if (schemes.length === 0) { return; }
|
||||
if (!schemes.includes(this._selectedScheme)) {
|
||||
this._selectedScheme = schemes.sort()[0];
|
||||
}
|
||||
},
|
||||
|
||||
_computeCommands(project, schemesObj, _selectedScheme) {
|
||||
const commands = [];
|
||||
let commandObj;
|
||||
if (schemesObj.hasOwnProperty(_selectedScheme)) {
|
||||
commandObj = schemesObj[_selectedScheme].clone_commands;
|
||||
}
|
||||
for (const title in commandObj) {
|
||||
if (!commandObj.hasOwnProperty(title)) { continue; }
|
||||
commands.push({
|
||||
title,
|
||||
command: commandObj[title]
|
||||
.replace('${project}', project)
|
||||
.replace('${project-base-name}', project),
|
||||
});
|
||||
}
|
||||
return commands;
|
||||
},
|
||||
});
|
||||
})();
|
||||
|
||||
@@ -36,6 +36,7 @@ limitations under the License.
|
||||
let element;
|
||||
let sandbox;
|
||||
const PROJECT = 'test-project';
|
||||
const SCHEMES = {http: {}, repo: {}, ssh: {}};
|
||||
|
||||
function getFormFields() {
|
||||
const selects = Polymer.dom(element.root).querySelectorAll('select');
|
||||
@@ -80,6 +81,9 @@ limitations under the License.
|
||||
submit_type: 'MERGE_IF_NECESSARY',
|
||||
});
|
||||
},
|
||||
getConfig() {
|
||||
return Promise.resolve({download: {}});
|
||||
},
|
||||
});
|
||||
element = fixture('basic');
|
||||
});
|
||||
@@ -89,8 +93,26 @@ limitations under the License.
|
||||
});
|
||||
|
||||
test('loading displays before project config is loaded', () => {
|
||||
assert.isFalse(element.$.loading.hidden);
|
||||
assert.isTrue(element.$.form.hidden);
|
||||
assert.isTrue(element.$.loading.classList.contains('loading'));
|
||||
assert.isFalse(getComputedStyle(element.$.loading).display === 'none');
|
||||
assert.isTrue(element.$.loadedContent.classList.contains('loading'));
|
||||
assert.isTrue(getComputedStyle(element.$.loadedContent)
|
||||
.display === 'none');
|
||||
});
|
||||
|
||||
test('download commands visibility', () => {
|
||||
element._loading = false;
|
||||
flushAsynchronousOperations();
|
||||
assert.isTrue(element.$.downloadContent.classList
|
||||
.contains('hideDownload'));
|
||||
assert.isTrue(getComputedStyle(element.$.downloadContent)
|
||||
.display == 'none');
|
||||
element._schemesObj = SCHEMES;
|
||||
flushAsynchronousOperations();
|
||||
assert.isFalse(element.$.downloadContent.classList
|
||||
.contains('hideDownload'));
|
||||
assert.isFalse(getComputedStyle(element.$.downloadContent)
|
||||
.display == 'none');
|
||||
});
|
||||
|
||||
test('form defaults to read only', () => {
|
||||
@@ -237,7 +259,7 @@ limitations under the License.
|
||||
configInputObj.use_signed_off_by;
|
||||
|
||||
assert.isFalse(button.hasAttribute('disabled'));
|
||||
assert.isTrue(element.$.Title.classList.contains('edited'));
|
||||
assert.isTrue(element.$.configurations.classList.contains('edited'));
|
||||
|
||||
const formattedObj =
|
||||
element._formatProjectConfigForSave(element._projectConfig);
|
||||
|
||||
Reference in New Issue
Block a user