| /** | |
| * @license | |
| * Copyright ( | |
| * ) 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 { | |
| CodeOwnersModel, | |
| CodeOwnersState, | |
| SuggestionsState, | |
| SuggestionsType, | |
| } from './code-owners-model.js'; | |
| import {ServerConfigurationError} from './code-owners-api.js'; | |
| import {CodeOwnerService} from './code-owners-service.js'; | |
| /** | |
| * ModelLoader provides a method for loading data into the model. | |
| * It is a bridge between an ownersModel and an ownersService. | |
| * When UI elements depends on a model property XXX, the element should | |
| * observe (or bind to) the property and call modelLoader.loadXXX method | |
| * to load the value. | |
| * It is recommended to use CodeOwnersModelMixin and call all load... methods | |
| * in the loadPropertiesAfterModelChanged method | |
| */ | |
| export class ModelLoader { | |
| private activeLoadSuggestionType?: SuggestionsType; | |
| constructor( | |
| private readonly ownersService: CodeOwnerService, | |
| private readonly ownersModel: CodeOwnersModel | |
| ) {} | |
| async _loadProperty<K extends keyof CodeOwnersState, T>( | |
| propertyName: K, | |
| propertyLoader: () => Promise<T>, | |
| propertySetter: (value: T) => void | |
| ) { | |
| if (this.ownersModel.state[propertyName] !== undefined) return; | |
| let newValue; | |
| try { | |
| newValue = await propertyLoader(); | |
| } catch (e) { | |
| if (e instanceof ServerConfigurationError) { | |
| this.ownersModel.setServerConfigurationError(e.message); | |
| return; | |
| } | |
| console.error(e); | |
| this.ownersModel.setPluginFailed((e as Error).message); | |
| return; | |
| } | |
| // It is possible, that several requests is made in parallel. | |
| // Store only the first result and discard all other results. | |
| // (also, due to the CodeOwnersCacheApi all result must be identical) | |
| if (this.ownersModel.state[propertyName] !== undefined) return; | |
| propertySetter(newValue); | |
| } | |
| async loadBranchConfig() { | |
| await this._loadProperty( | |
| 'branchConfig', | |
| () => this.ownersService.getBranchConfig(), | |
| value => this.ownersModel.setBranchConfig(value) | |
| ); | |
| } | |
| async loadStatus() { | |
| await this._loadProperty( | |
| 'status', | |
| () => this.ownersService.getStatus(), | |
| value => this.ownersModel.setStatus(value) | |
| ); | |
| } | |
| async loadOwnedPaths() { | |
| await this._loadProperty( | |
| 'ownedPaths', | |
| () => this.ownersService.getOwnedPaths(), | |
| paths => this.ownersModel.setOwnedPaths(paths) | |
| ); | |
| } | |
| async loadUserRole() { | |
| await this._loadProperty( | |
| 'userRole', | |
| () => this.ownersService.getLoggedInUserInitialRole(), | |
| value => this.ownersModel.setUserRole(value) | |
| ); | |
| } | |
| async loadPluginStatus() { | |
| await this._loadProperty( | |
| 'pluginStatus', | |
| () => this.ownersService.isCodeOwnerEnabled(), | |
| value => this.ownersModel.setPluginEnabled(value) | |
| ); | |
| } | |
| async loadAreAllFilesApproved() { | |
| await this._loadProperty( | |
| 'areAllFilesApproved', | |
| () => this.ownersService.areAllFilesApproved(), | |
| value => this.ownersModel.setAreAllFilesApproved(value) | |
| ); | |
| } | |
| async loadSuggestions(suggestionsType: SuggestionsType) { | |
| // NOTE: This line is necessary to avoid an infinite loop with | |
| // SuggestOwners.onShowSuggestionsTypeChanged | |
| if (this.activeLoadSuggestionType === suggestionsType) return; | |
| this.pauseActiveSuggestedOwnersLoading(); | |
| this.activeLoadSuggestionType = suggestionsType; | |
| if ( | |
| this.ownersModel.getSuggestionsByType(suggestionsType)!.state === | |
| SuggestionsState.Loading | |
| ) { | |
| this.ownersService.resumeSuggestedOwnersLoading(suggestionsType); | |
| return; | |
| } | |
| // If a loading has been started already, do nothing | |
| if ( | |
| this.ownersModel.getSuggestionsByType(suggestionsType)!.state !== | |
| SuggestionsState.NotLoaded | |
| ) | |
| return; | |
| this.ownersModel.setSuggestionsState( | |
| suggestionsType, | |
| SuggestionsState.Loading | |
| ); | |
| let suggestedOwners; | |
| try { | |
| suggestedOwners = await this.ownersService.getSuggestedOwners( | |
| suggestionsType | |
| ); | |
| } catch (e) { | |
| console.error(e); | |
| this.ownersModel.setSuggestionsState( | |
| suggestionsType, | |
| SuggestionsState.LoadFailed | |
| ); | |
| // The selectedSuggestionsType can be changed while getSuggestedOwners | |
| // is executed. The plugin should fail only if the selectedSuggestionsType | |
| // is the same. | |
| if (this.ownersModel.state.selectedSuggestionsType === suggestionsType) { | |
| this.ownersModel.setPluginFailed((e as Error).message); | |
| } | |
| return; | |
| } | |
| this.ownersModel.setSuggestionsFiles( | |
| suggestionsType, | |
| suggestedOwners.files | |
| ); | |
| this.ownersModel.setSuggestionsState( | |
| suggestionsType, | |
| SuggestionsState.Loaded | |
| ); | |
| } | |
| pauseActiveSuggestedOwnersLoading() { | |
| if (!this.activeLoadSuggestionType) return; | |
| this.ownersService.pauseSuggestedOwnersLoading( | |
| this.activeLoadSuggestionType | |
| ); | |
| } | |
| async updateLoadSelectedSuggestionsProgress() { | |
| const suggestionsType = this.ownersModel.state.selectedSuggestionsType; | |
| let suggestedOwners; | |
| try { | |
| suggestedOwners = await this.ownersService.getSuggestedOwnersProgress( | |
| suggestionsType | |
| ); | |
| } catch { | |
| // Ignore any error, keep progress unchanged. | |
| return; | |
| } | |
| this.ownersModel.setSuggestionsLoadProgress( | |
| suggestionsType, | |
| suggestedOwners.progress | |
| ); | |
| this.ownersModel.setSuggestionsFiles( | |
| suggestionsType, | |
| suggestedOwners.files | |
| ); | |
| } | |
| } |