blob: ace3e77556dd039902a50efd2cd0fd225dae7b05 [file] [log] [blame]
/**
* @license
* Copyright (C) 2020 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.
*/
import './gr-repo-chip.js';
import {htmlTemplate} from './gr-create-checkers-dialog_html.js';
const REPOS_PER_PAGE = 6;
const CREATE_CHECKER_URL = '/plugins/checks/checkers/';
const SCHEME_PATTERN = /^[\w-_.]*$/;
class GrCreateCheckersDialog extends Polymer.GestureEventListeners(
Polymer.LegacyElementMixin(
Polymer.Element)) {
/** @returns {string} name of the component */
static get is() { return 'gr-create-checkers-dialog'; }
/** @returns {?} template for this component */
static get template() { return htmlTemplate; }
/**
* Fired when the cancel button is pressed.
*
* @event cancel
*/
/**
* Defines properties of the component
*
* @returns {?}
*/
static get properties() {
return {
checker: {
type: Object,
observer: '_checkerChanged',
},
_name: String,
_scheme: String,
_id: String,
_uuid: {
type: String,
value: '',
},
pluginRestApi: Object,
_url: String,
_description: String,
_getRepoSuggestions: {
type: Function,
value() {
return this._repoSuggestions.bind(this);
},
},
// The backend might support multiple repos in the future
// which is why I decided to keep it as an array.
_repos: {
type: Array,
value: [],
notify: true,
},
_repositorySelected: {
type: Boolean,
value: false,
},
_handleOnRemove: Function,
_errorMsg: {
type: String,
value: '',
},
_statuses: {
type: Array,
value: [
{
text: 'ENABLED',
value: 'ENABLED',
},
{
text: 'DISABLED',
value: 'DISABLED',
},
],
readOnly: true,
},
_required: {
type: Boolean,
value: false,
},
_status: String,
_edit: {
type: Boolean,
value: false,
},
_query: String,
};
}
static get observers() {
return [
'_updateUUID(_scheme, _id)',
];
}
_checkerChanged() {
if (!this.checker) {
console.warn('checker not set');
return;
}
this._edit = true;
this._scheme = this.checker.uuid.split(':')[0];
this._id = this.checker.uuid.split(':')[1];
this._name = this.checker.name;
this._description = this.checker.description || '';
this._url = this.checker.url || '';
this._query = this.checker.query || '';
this._required = this.checker.blocking &&
this.checker.blocking.length > 0;
if (this.checker.repository) {
this._repositorySelected = true;
this.set('_repos', [{name: this.checker.repository}]);
}
this._status = this.checker.status;
}
_updateUUID(_scheme, _id) {
this._uuid = _scheme + ':' + _id;
}
_handleStatusChange(e) {
this._status = e.detail.value;
}
_validateRequest() {
if (!this._name) {
this._errorMsg = 'Name cannot be empty';
return false;
}
if (this._description && this._description.length > 1000) {
this._errorMsg = 'Description should be less than 1000 characters';
return false;
}
if (!this._repositorySelected) {
this._errorMsg = 'Select a repository';
return false;
}
if (!this._scheme) {
this._errorMsg = 'Scheme cannot be empty.';
return false;
}
if (this._scheme.match(SCHEME_PATTERN) == null) {
this._errorMsg =
'Scheme must contain [A-Z], [a-z], [0-9] or {"-" , "_" , "."}';
return false;
}
if (this._scheme.length > 100) {
this._errorMsg = 'Scheme must be shorter than 100 characters';
return false;
}
if (!this._id) {
this._errorMsg = 'ID cannot be empty.';
return false;
}
if (this._id.match(SCHEME_PATTERN) == null) {
this._errorMsg =
'ID must contain [A-Z], [a-z], [0-9] or {"-" , "_" , "."}';
return false;
}
return true;
}
// TODO(dhruvsri): make sure dialog is scrollable.
_createChecker(checker) {
return this.pluginRestApi.send(
'POST',
CREATE_CHECKER_URL,
checker
);
}
_editChecker(checker) {
const url = CREATE_CHECKER_URL + checker.uuid;
return this.pluginRestApi.send(
'POST',
url,
checker
);
}
handleEditChecker() {
if (!this._validateRequest()) return;
this._editChecker(this._getCheckerRequestObject()).then(
res => {
if (res) {
this._errorMsg = '';
this.dispatchEvent(new CustomEvent('cancel',
{
detail: {reload: true},
bubbles: true,
composed: true,
}
));
}
},
error => {
this._errorMsg = error;
}
);
}
_getCheckerRequestObject() {
return {
name: this._name,
description: this._description || '',
uuid: this._uuid,
repository: this._repos[0].name,
url: this._url,
status: this._status,
blocking: this._required ? ['STATE_NOT_PASSING'] : [],
query: this._query,
};
}
handleCreateChecker() {
if (!this._validateRequest()) return;
// Currently after creating checker there is no reload happening (as
// this would result in the user exiting the screen).
this._createChecker(this._getCheckerRequestObject()).then(
res => {
if (res) this._cleanUp();
},
error => {
this._errorMsg = error;
}
);
}
_cleanUp() {
this._name = '';
this._scheme = '';
this._id = '';
this._uuid = '';
this._description = '';
this._repos = [];
this._repositorySelected = false;
this._errorMsg = '';
this._required = false;
this._query = '';
this._status = '';
this.dispatchEvent(new CustomEvent('cancel',
{
detail: {reload: true},
bubbles: true,
composed: true,
}
));
}
_repoSuggestions(filter) {
const _makeSuggestion = repo => {
return {name: repo.name, value: repo};
};
return this.pluginRestApi.getRepos(filter, REPOS_PER_PAGE).then(
repos => repos.map(repo => _makeSuggestion(repo))
);
}
_handleRepositorySelected(e) {
this.push('_repos', e.detail.value);
this._repositorySelected = true;
}
_handleRequiredCheckBoxClicked() {
this._required = !this._required;
}
_handleOnRemove(e) {
const idx = this._repos.indexOf(e.detail.repo);
if (idx == -1) return;
this.splice('_repos', idx, 1);
if (this._repos.length == 0) {
this._repositorySelected = false;
}
}
}
customElements.define(GrCreateCheckersDialog.is, GrCreateCheckersDialog);