| class CustomAnalysisTaskConfigurator extends ComponentBase { |
| |
| constructor() |
| { |
| super('custom-analysis-task-configurator'); |
| |
| this._selectedTests = []; |
| this._triggerablePlatforms = []; |
| this._selectedPlatform = null; |
| this._showComparison = false; |
| this._commitSetMap = {}; |
| this._specifiedRevisions = {'Baseline': new Map, 'Comparison': new Map}; |
| this._patchUploaders = {'Baseline': new Map, 'Comparison': new Map}; |
| this._customRootUploaders = {'Baseline': null, 'Comparison': null}; |
| this._fetchedCommits = {'Baseline': new Map, 'Comparison': new Map}; |
| this._repositoryGroupByConfiguration = {'Baseline': null, 'Comparison': null}; |
| this._invalidRevisionsByConfiguration = {'Baseline': new Map, 'Comparison': new Map}; |
| |
| this._updateTriggerableLazily = new LazilyEvaluatedFunction(this._updateTriggerable.bind(this)); |
| this._renderTriggerableTestsLazily = new LazilyEvaluatedFunction(this._renderTriggerableTests.bind(this)); |
| this._renderTriggerablePlatformsLazily = new LazilyEvaluatedFunction(this._renderTriggerablePlatforms.bind(this)); |
| this._renderRepositoryPanesLazily = new LazilyEvaluatedFunction(this._renderRepositoryPanes.bind(this)); |
| } |
| |
| tests() { return this._selectedTests; } |
| platform() { return this._selectedPlatform; } |
| commitSets() |
| { |
| const map = this._commitSetMap; |
| if (!map['Baseline'] || !map['Comparison']) |
| return null; |
| return [map['Baseline'], map['Comparison']]; |
| } |
| |
| selectTests(selectedTests) |
| { |
| this._selectedTests = selectedTests; |
| |
| this._triggerablePlatforms = Triggerable.triggerablePlatformsForTests(this._selectedTests); |
| if (this._selectedTests.length && !this._triggerablePlatforms.includes(this._selectedPlatform)) |
| this._selectedPlatform = null; |
| |
| this._didUpdateSelectedPlatforms(); |
| } |
| |
| selectPlatform(selectedPlatform) |
| { |
| this._selectedPlatform = selectedPlatform; |
| |
| const [triggerable, error] = this._updateTriggerableLazily.evaluate(this._selectedTests, this._selectedPlatform); |
| this._updateRepositoryGroups(triggerable); |
| |
| this._didUpdateSelectedPlatforms(); |
| } |
| |
| _didUpdateSelectedPlatforms() |
| { |
| for (const configuration of ['Baseline', 'Comparison']) { |
| this._updateMapFromSpecifiedRevisionsForConfiguration(this._fetchedCommits, configuration); |
| this._updateMapFromSpecifiedRevisionsForConfiguration(this._invalidRevisionsByConfiguration, configuration); |
| } |
| this._updateCommitSetMap(); |
| this.dispatchAction('testConfigChange'); |
| this.enqueueToRender(); |
| } |
| |
| _updateMapFromSpecifiedRevisionsForConfiguration(map, configuration) |
| { |
| const referenceMap = this._specifiedRevisions[configuration]; |
| const newValue = new Map; |
| for (const [key, value] of map[configuration].entries()) { |
| if (!referenceMap.has(key)) |
| continue; |
| newValue.set(key, value); |
| } |
| if (newValue.size !== map[configuration].size) |
| map[configuration] = newValue; |
| } |
| |
| setCommitSets(baselineCommitSet, comparisonCommitSet) |
| { |
| const [triggerable, error] = this._updateTriggerableLazily.evaluate(this._selectedTests, this._selectedPlatform); |
| |
| if (!triggerable) |
| return; |
| |
| const baselineRepositoryGroup = triggerable.repositoryGroups().find((repositoryGroup) => repositoryGroup.accepts(baselineCommitSet)); |
| if (baselineRepositoryGroup) { |
| this._repositoryGroupByConfiguration['Baseline'] = baselineRepositoryGroup; |
| this._setUploadedFilesToUploader(this._customRootUploaders['Baseline'], baselineCommitSet.customRoots()); |
| this._specifiedRevisions['Baseline'] = this._revisionMapFromCommitSet(baselineCommitSet); |
| this._setPatchFiles('Baseline', baselineCommitSet); |
| } |
| |
| const comparisonRepositoryGroup = triggerable.repositoryGroups().find((repositoryGroup) => repositoryGroup.accepts(baselineCommitSet)); |
| if (comparisonRepositoryGroup) { |
| this._repositoryGroupByConfiguration['Comparison'] = comparisonRepositoryGroup; |
| this._setUploadedFilesToUploader(this._customRootUploaders['Comparison'], comparisonCommitSet.customRoots()); |
| this._specifiedRevisions['Comparison'] = this._revisionMapFromCommitSet(comparisonCommitSet); |
| this._setPatchFiles('Comparison', comparisonCommitSet); |
| } |
| |
| this._showComparison = true; |
| this._updateCommitSetMap(); |
| } |
| |
| _setUploadedFilesToUploader(uploader, files) |
| { |
| if (!uploader || uploader.hasFileToUpload() || uploader.uploadedFiles().length) |
| return; |
| uploader.clearUploads(); |
| for (const uploadedFile of files) |
| uploader.addUploadedFile(uploadedFile); |
| } |
| |
| _setPatchFiles(configurationName, commitSet) |
| { |
| for (const repository of commitSet.repositories()) { |
| const patch = commitSet.patchForRepository(repository); |
| if (patch) |
| this._setUploadedFilesToUploader(this._ensurePatchUploader(configurationName, repository), [patch]); |
| } |
| } |
| |
| _revisionMapFromCommitSet(commitSet) |
| { |
| const revisionMap = new Map; |
| for (const repository of commitSet.repositories()) |
| revisionMap.set(repository, commitSet.revisionForRepository(repository)); |
| return revisionMap; |
| } |
| |
| didConstructShadowTree() |
| { |
| this.content('specify-comparison-button').onclick = this.createEventHandler(() => this._configureComparison()); |
| |
| const createRootUploader = () => { |
| const uploader = new InstantFileUploader; |
| uploader.allowMultipleFiles(); |
| uploader.element().textContent = 'Add a new root'; |
| uploader.listenToAction('removedFile', () => this._updateCommitSetMap()); |
| return uploader; |
| } |
| |
| const baselineRootsUploader = createRootUploader(); |
| baselineRootsUploader.listenToAction('uploadedFile', (uploadedFile) => this._updateCommitSetMap()); |
| this._customRootUploaders['Baseline'] = baselineRootsUploader; |
| |
| const comparisonRootsUploader = createRootUploader(); |
| comparisonRootsUploader.listenToAction('uploadedFile', () => this._updateCommitSetMap()); |
| this._customRootUploaders['Comparison'] = comparisonRootsUploader; |
| } |
| |
| _ensurePatchUploader(configurationName, repository) |
| { |
| const uploaderMap = this._patchUploaders[configurationName]; |
| let uploader = uploaderMap.get(repository); |
| if (uploader) |
| return uploader; |
| |
| uploader = new InstantFileUploader; |
| uploader.element().textContent = 'Apply a patch'; |
| uploader.listenToAction('uploadedFile', () => this._updateCommitSetMap()); |
| uploader.listenToAction('removedFile', () => this._updateCommitSetMap()); |
| uploaderMap.set(repository, uploader); |
| |
| return uploader; |
| } |
| |
| _configureComparison() |
| { |
| this._showComparison = true; |
| this._repositoryGroupByConfiguration['Comparison'] = this._repositoryGroupByConfiguration['Baseline']; |
| |
| const specifiedBaselineRevisions = this._specifiedRevisions['Baseline']; |
| const specifiedComparisonRevisions = new Map; |
| for (let key of specifiedBaselineRevisions.keys()) |
| specifiedComparisonRevisions.set(key, specifiedBaselineRevisions.get(key)); |
| this._specifiedRevisions['Comparison'] = specifiedComparisonRevisions; |
| |
| for (const [repository, patchUploader] of this._patchUploaders['Baseline']) { |
| const files = patchUploader.uploadedFiles(); |
| if (!files.length) |
| continue; |
| const comparisonPatchUploader = this._ensurePatchUploader('Comparison', repository); |
| for (const uploadedFile of files) |
| comparisonPatchUploader.addUploadedFile(uploadedFile); |
| } |
| |
| const comparisonRootUploader = this._customRootUploaders['Comparison']; |
| for (const uploadedFile of this._customRootUploaders['Baseline'].uploadedFiles()) |
| comparisonRootUploader.addUploadedFile(uploadedFile); |
| |
| this.enqueueToRender(); |
| } |
| |
| render() |
| { |
| super.render(); |
| |
| const updateSelectedTestsLazily = this._renderTriggerableTestsLazily.evaluate(); |
| updateSelectedTestsLazily.evaluate(...this._selectedTests); |
| const updateSelectedPlatformsLazily = this._renderTriggerablePlatformsLazily.evaluate(this._selectedTests, this._triggerablePlatforms); |
| if (updateSelectedPlatformsLazily) |
| updateSelectedPlatformsLazily.evaluate(this._selectedPlatform); |
| |
| const [triggerable, error] = this._updateTriggerableLazily.evaluate(this._selectedTests, this._selectedPlatform); |
| |
| this._renderRepositoryPanesLazily.evaluate(triggerable, error, this._selectedPlatform, this._repositoryGroupByConfiguration, this._showComparison); |
| |
| this.renderReplace(this.content('baseline-testability'), this._buildTestabilityList(this._commitSetMap['Baseline'], |
| 'Baseline', this._invalidRevisionsByConfiguration['Baseline'])); |
| |
| this.renderReplace(this.content('comparison-testability'), !this._showComparison ? null : |
| this._buildTestabilityList(this._commitSetMap['Comparison'], 'Comparison', this._invalidRevisionsByConfiguration['Comparison'])); |
| } |
| |
| _renderTriggerableTests() |
| { |
| const enabledTriggerables = Triggerable.all().filter((triggerable) => !triggerable.isDisabled()); |
| |
| const acceptedTests = new Set; |
| for (const triggerable of enabledTriggerables) { |
| for (const test of triggerable.acceptedTests()) |
| acceptedTests.add(test); |
| } |
| const tests = [...acceptedTests].sort((testA, testB) => { |
| if (testA.fullName() == testB.fullName()) |
| return 0; |
| return testA.fullName() < testB.fullName() ? -1 : 1; |
| }); |
| return this._renderRadioButtonList(this.content('test-list'), 'test', tests, this.selectTests.bind(this), (test) => test.fullName()); |
| } |
| |
| _renderTriggerablePlatforms(selectedTests, triggerablePlatforms) |
| { |
| if (!selectedTests.length) { |
| this.content('platform-pane').style.display = 'none'; |
| return null; |
| } |
| this.content('platform-pane').style.display = null; |
| |
| return this._renderRadioButtonList(this.content('platform-list'), 'platform', triggerablePlatforms, (selectedPlatforms) => { |
| this.selectPlatform(selectedPlatforms.length ? selectedPlatforms[0] : null); |
| }); |
| } |
| |
| _renderRadioButtonList(listContainer, name, objects, callback, labelForObject = (object) => object.label()) |
| { |
| const listItems = []; |
| let selectedListItems = []; |
| const checkSelectedRadioButtons = (newSelectedListItems) => { |
| selectedListItems.forEach((item) => { |
| item.label.classList.remove('selected'); |
| item.radioButton.checked = false; |
| }); |
| selectedListItems = newSelectedListItems; |
| selectedListItems.forEach((item) => { |
| item.label.classList.add('selected'); |
| item.radioButton.checked = true; |
| }); |
| } |
| |
| const element = ComponentBase.createElement; |
| this.renderReplace(listContainer, objects.map((object) => { |
| const radioButton = element('input', {type: 'radio', name: name, onchange: () => { |
| checkSelectedRadioButtons(listItems.filter((item) => item.radioButton.checked)); |
| callback(selectedListItems.map((item) => item.object)); |
| this.enqueueToRender(); |
| }}); |
| const label = element('label', [radioButton, labelForObject(object)]); |
| listItems.push({radioButton, label, object}); |
| return element('li', label); |
| })); |
| |
| return new LazilyEvaluatedFunction((...selectedObjects) => { |
| const objects = new Set(selectedObjects); |
| checkSelectedRadioButtons(listItems.filter((item) => objects.has(item.object))); |
| }); |
| } |
| |
| _updateTriggerable(tests, platform) |
| { |
| let triggerable = null; |
| let error = null; |
| if (tests.length && platform) { |
| triggerable = Triggerable.findByTestConfiguration(tests[0], platform); |
| let matchingTests = new Set; |
| let mismatchingTests = new Set; |
| for (let test of tests) { |
| if (Triggerable.findByTestConfiguration(test, platform) == triggerable) |
| matchingTests.add(test); |
| else |
| mismatchingTests.add(test); |
| } |
| if (matchingTests.size < tests.length) { |
| const matchingTestNames = [...matchingTests].map((test) => test.fullName()).sort().join('", "'); |
| const mismathingTestNames = [...mismatchingTests].map((test) => test.fullName()).sort().join('", "'); |
| error = `Tests "${matchingTestNames}" and "${mismathingTestNames}" cannot be scheduled |
| simultenosuly on "${platform.name()}". Please select one of them at a time.`; |
| } |
| } |
| |
| return [triggerable, error]; |
| } |
| |
| _updateRepositoryGroups(triggerable) |
| { |
| const repositoryGroups = triggerable ? TriggerableRepositoryGroup.sortByNamePreferringSmallerRepositories(triggerable.repositoryGroups()) : []; |
| for (let name in this._repositoryGroupByConfiguration) { |
| const currentGroup = this._repositoryGroupByConfiguration[name]; |
| let matchingGroup = null; |
| if (currentGroup) { |
| if (repositoryGroups.includes(currentGroup)) |
| matchingGroup = currentGroup; |
| else |
| matchingGroup = repositoryGroups.find((group) => group.name() == currentGroup.name()); |
| } |
| if (!matchingGroup && repositoryGroups.length) |
| matchingGroup = repositoryGroups[0]; |
| this._repositoryGroupByConfiguration[name] = matchingGroup; |
| } |
| } |
| |
| _updateCommitSetMap() |
| { |
| const newBaseline = this._computeCommitSet('Baseline'); |
| let newComparison = this._computeCommitSet('Comparison'); |
| if (newBaseline && newComparison && newBaseline.equals(newComparison)) |
| newComparison = null; |
| |
| const currentBaseline = this._commitSetMap['Baseline']; |
| const currentComparison = this._commitSetMap['Comparison']; |
| const areCommitSetsEqual = (commitSetA, commitSetB) => commitSetA == commitSetB || (commitSetA && commitSetB && commitSetA.equals(commitSetB)); |
| const sameBaselineConfig = areCommitSetsEqual(currentBaseline, newBaseline); |
| const sameComparisionConfig = areCommitSetsEqual(currentComparison, newComparison); |
| |
| if (sameBaselineConfig && sameComparisionConfig) |
| return; |
| |
| this._commitSetMap = {'Baseline': newBaseline, 'Comparison': newComparison}; |
| |
| this.dispatchAction('testConfigChange'); |
| this.enqueueToRender(); |
| } |
| |
| _computeCommitSet(configurationName) |
| { |
| const repositoryGroup = this._repositoryGroupByConfiguration[configurationName]; |
| if (!repositoryGroup) |
| return null; |
| |
| const fileUploader = this._customRootUploaders[configurationName]; |
| if (!fileUploader || fileUploader.hasFileToUpload()) |
| return null; |
| |
| const commitSet = new CustomCommitSet; |
| for (let repository of repositoryGroup.repositories()) { |
| let revision = this._specifiedRevisions[configurationName].get(repository); |
| const commit = this._fetchedCommits[configurationName].get(repository); |
| if (commit) { |
| const commitLabel = commit.label(); |
| if (!revision || commit.revision().startsWith(revision) || commitLabel.startsWith(revision) || revision.startsWith(commitLabel)) |
| revision = commit.revision(); |
| } |
| if (!revision) |
| return null; |
| let patch = null; |
| if (repositoryGroup.acceptsPatchForRepository(repository)) { |
| const uploaderMap = this._patchUploaders[configurationName]; |
| const uploader = uploaderMap.get(repository); |
| if (uploader) { |
| const files = uploader.uploadedFiles(); |
| console.assert(files.length <= 1); |
| if (files.length) |
| patch = files[0]; |
| } |
| } |
| commitSet.setRevisionForRepository(repository, revision, patch); |
| } |
| |
| for (let uploadedFile of fileUploader.uploadedFiles()) |
| commitSet.addCustomRoot(uploadedFile); |
| |
| return commitSet; |
| } |
| |
| async _fetchCommitsForConfiguration(configurationName) |
| { |
| const commitSet = this._commitSetMap[configurationName]; |
| if (!commitSet) |
| return; |
| |
| const specifiedRevisions = this._specifiedRevisions[configurationName]; |
| const fetchedCommits = this._fetchedCommits[configurationName]; |
| const invalidRevisionForRepository = this._invalidRevisionsByConfiguration[configurationName]; |
| |
| await Promise.all(Array.from(commitSet.repositories()).map((repository) => { |
| const revision = commitSet.revisionForRepository(repository); |
| return this._resolveRevision(repository, revision, specifiedRevisions, invalidRevisionForRepository, fetchedCommits); |
| })); |
| |
| const latestCommitSet = this._commitSetMap[configurationName]; |
| if (commitSet != latestCommitSet) |
| return; |
| this.enqueueToRender(); |
| } |
| |
| async _resolveRevision(repository, revision, specifiedRevisions, invalidRevisionForRepository, fetchedCommits) |
| { |
| const fetchedCommit = fetchedCommits.get(repository); |
| const specifiedRevision = specifiedRevisions.get(repository); |
| if (fetchedCommit && fetchedCommit.revision() == revision && (!specifiedRevision || specifiedRevision == revision)) |
| return; |
| |
| fetchedCommits.delete(repository); |
| let commits = []; |
| const revisionToFetch = specifiedRevision || revision; |
| try { |
| commits = await CommitLog.fetchForSingleRevision(repository, revisionToFetch, true); |
| } catch (error) { |
| console.assert(error == 'UnknownCommit' || error == 'AmbiguousRevisionPrefix'); |
| if (revisionToFetch != specifiedRevisions.get(repository)) |
| return; |
| invalidRevisionForRepository.set(repository, `"${revisionToFetch}": ${error == 'UnknownCommit' ? 'Invalid revision' : 'Ambiguous revision prefix'}`); |
| return; |
| } |
| console.assert(commits.length, 1); |
| if (revisionToFetch != specifiedRevisions.get(repository)) |
| return; |
| invalidRevisionForRepository.delete(repository); |
| fetchedCommits.set(repository, commits[0]); |
| if (revisionToFetch != commits[0].revision()) |
| this._updateCommitSetMap(); |
| } |
| |
| _renderRepositoryPanes(triggerable, error, platform, repositoryGroupByConfiguration, showComparison) |
| { |
| this.content('repository-configuration-error-pane').style.display = error ? null : 'none'; |
| this.content('error').textContent = error; |
| |
| this.content('baseline-configuration-pane').style.display = triggerable ? null : 'none'; |
| this.content('specify-comparison-pane').style.display = triggerable && !showComparison ? null : 'none'; |
| this.content('comparison-configuration-pane').style.display = triggerable && showComparison ? null : 'none'; |
| |
| if (!triggerable) |
| return; |
| |
| const visibleRepositoryGroups = triggerable.repositoryGroups().filter((group) => !group.isHidden()); |
| const repositoryGroups = TriggerableRepositoryGroup.sortByNamePreferringSmallerRepositories(visibleRepositoryGroups); |
| |
| const repositorySet = new Set; |
| for (let group of repositoryGroups) { |
| for (let repository of group.repositories()) |
| repositorySet.add(repository); |
| } |
| |
| const repositories = Repository.sortByNamePreferringOnesWithURL([...repositorySet]); |
| const requiredRepositories = repositories.filter((repository) => { |
| return repositoryGroups.every((group) => group.repositories().includes(repository)); |
| }); |
| const alwaysAcceptsCustomRoots = repositoryGroups.every((group) => group.acceptsCustomRoots()); |
| |
| this._renderBaselineRevisionTable(platform, repositoryGroups, requiredRepositories, repositoryGroupByConfiguration, alwaysAcceptsCustomRoots); |
| |
| if (showComparison) |
| this._renderComparisonRevisionTable(platform, repositoryGroups, requiredRepositories, repositoryGroupByConfiguration, alwaysAcceptsCustomRoots); |
| } |
| |
| _renderBaselineRevisionTable(platform, repositoryGroups, requiredRepositories, repositoryGroupByConfiguration, alwaysAcceptsCustomRoots) |
| { |
| let currentGroup = repositoryGroupByConfiguration['Baseline']; |
| const optionalRepositoryList = this._optionalRepositoryList(currentGroup, requiredRepositories); |
| this.renderReplace(this.content('baseline-revision-table'), |
| this._buildRevisionTable('Baseline', repositoryGroups, currentGroup, platform, requiredRepositories, optionalRepositoryList, alwaysAcceptsCustomRoots)); |
| } |
| |
| _renderComparisonRevisionTable(platform, repositoryGroups, requiredRepositories, repositoryGroupByConfiguration, alwaysAcceptsCustomRoots) |
| { |
| let currentGroup = repositoryGroupByConfiguration['Comparison']; |
| const optionalRepositoryList = this._optionalRepositoryList(currentGroup, requiredRepositories); |
| this.renderReplace(this.content('comparison-revision-table'), |
| this._buildRevisionTable('Comparison', repositoryGroups, currentGroup, platform, requiredRepositories, optionalRepositoryList, alwaysAcceptsCustomRoots)); |
| } |
| |
| _optionalRepositoryList(currentGroup, requiredRepositories) |
| { |
| if (!currentGroup) |
| return []; |
| return Repository.sortByNamePreferringOnesWithURL(currentGroup.repositories().filter((repository) => !requiredRepositories.includes(repository))); |
| } |
| |
| _buildRevisionTable(configurationName, repositoryGroups, currentGroup, platform, requiredRepositories, optionalRepositoryList, alwaysAcceptsCustomRoots) |
| { |
| const element = ComponentBase.createElement; |
| |
| const customRootsTBody = element('tbody', [ |
| element('tr', [ |
| element('th', 'Roots'), |
| element('td', this._customRootUploaders[configurationName]), |
| ]), |
| ]); |
| |
| return [ |
| element('tbody', |
| requiredRepositories.map((repository) => { |
| return element('tr', [ |
| element('th', repository.name()), |
| element('td', this._buildRevisionInput(configurationName, repository, platform)) |
| ]); |
| })), |
| alwaysAcceptsCustomRoots ? customRootsTBody : [], |
| element('tbody', [ |
| element('tr', {'class': 'group-row'}, |
| element('td', {colspan: 2}, this._buildRepositoryGroupList(repositoryGroups, currentGroup, configurationName))), |
| ]), |
| !alwaysAcceptsCustomRoots && currentGroup && currentGroup.acceptsCustomRoots() ? customRootsTBody : [], |
| element('tbody', |
| optionalRepositoryList.map((repository) => { |
| let uploader = currentGroup.acceptsPatchForRepository(repository) |
| ? this._ensurePatchUploader(configurationName, repository) : null; |
| |
| return element('tr',[ |
| element('th', repository.name()), |
| element('td', [ |
| this._buildRevisionInput(configurationName, repository, platform), |
| uploader || [], |
| ]) |
| ]); |
| }) |
| )]; |
| } |
| |
| _buildTestabilityList(commitSet, configurationName, invalidRevisionForRepository) |
| { |
| const element = ComponentBase.createElement; |
| const entries = []; |
| |
| if (!commitSet || !commitSet.repositories().length) |
| return []; |
| |
| for (const repository of commitSet.repositories()) { |
| const commit = this._fetchedCommits[configurationName].get(repository); |
| if (commit && commit.testability() && !invalidRevisionForRepository.has(repository)) |
| entries.push(element('li', `${commit.repository().name()} - "${commit.label()}": ${commit.testability()}`)); |
| if (invalidRevisionForRepository.has(repository)) |
| entries.push(element('li', `${repository.name()} - ${invalidRevisionForRepository.get(repository)}`)); |
| } |
| |
| return entries; |
| } |
| |
| _buildRepositoryGroupList(repositoryGroups, currentGroup, configurationName) |
| { |
| const element = ComponentBase.createElement; |
| return repositoryGroups.map((group) => { |
| const input = element('input', { |
| type: 'radio', |
| name: 'repositoryGroup-for-' + configurationName.toLowerCase(), |
| checked: currentGroup == group, |
| onchange: () => this._selectRepositoryGroup(configurationName, group) |
| }); |
| return [element('label', [input, group.description()])]; |
| }); |
| } |
| |
| _selectRepositoryGroup(configurationName, group) |
| { |
| const source = this._repositoryGroupByConfiguration; |
| const clone = {}; |
| for (let key in source) |
| clone[key] = source[key]; |
| clone[configurationName] = group; |
| this._repositoryGroupByConfiguration = clone; |
| this._updateCommitSetMap(); |
| this._fetchCommitsForConfiguration(configurationName); |
| this.enqueueToRender(); |
| } |
| |
| _buildRevisionInput(configurationName, repository, platform) |
| { |
| const revision = this._specifiedRevisions[configurationName].get(repository) || ''; |
| const element = ComponentBase.createElement; |
| let scheduledUpdate = null; |
| const input = element('input', {value: revision, oninput: () => { |
| unmodifiedInput = null; |
| const revisionToFetch = input.value; |
| this._specifiedRevisions[configurationName].set(repository, revisionToFetch); |
| this._updateCommitSetMap(); |
| if (scheduledUpdate) |
| clearTimeout(scheduledUpdate); |
| scheduledUpdate = setTimeout(() => { |
| if (revisionToFetch == input.value) |
| this._fetchCommitsForConfiguration(configurationName); |
| scheduledUpdate = null; |
| }, CustomAnalysisTaskConfigurator.commitFetchInterval); |
| }}); |
| let unmodifiedInput = input; |
| |
| if (!revision) { |
| CommitLog.fetchLatestCommitForPlatform(repository, platform).then((commit) => { |
| if (commit && unmodifiedInput) { |
| unmodifiedInput.value = commit.revision(); |
| this._fetchedCommits[configurationName].set(repository, commit); |
| this._updateCommitSetMap(); |
| } |
| }); |
| } |
| |
| return input; |
| } |
| |
| static htmlTemplate() |
| { |
| return ` |
| <section id="test-pane" class="pane"> |
| <h2>1. Select a Test</h2> |
| <ul id="test-list" class="config-list"></ul> |
| </section> |
| <section id="platform-pane" class="pane"> |
| <h2>2. Select a Platform</h2> |
| <ul id="platform-list" class="config-list"></ul> |
| </section> |
| <section id="repository-configuration-error-pane" class="pane"> |
| <h2>Incompatible tests</h2> |
| <p id="error"></p> |
| </section> |
| <section id="baseline-configuration-pane" class="pane"> |
| <h2>3. Configure Baseline</h2> |
| <table id="baseline-revision-table" class="revision-table"></table> |
| <ul id="baseline-testability"></ul> |
| </section> |
| <section id="specify-comparison-pane" class="pane"> |
| <button id="specify-comparison-button">Configure to Compare</button> |
| </section> |
| <section id="comparison-configuration-pane" class="pane"> |
| <h2>4. Configure Comparison</h2> |
| <table id="comparison-revision-table" class="revision-table"></table> |
| <ul id="comparison-testability"></ul> |
| </section>`; |
| } |
| |
| static cssTemplate() |
| { |
| return ` |
| :host { |
| display: flex !important; |
| flex-direction: row !important; |
| } |
| .pane { |
| margin-right: 1rem; |
| padding: 0; |
| } |
| .pane h2 { |
| padding: 0; |
| margin: 0; |
| margin-bottom: 0.5rem; |
| font-size: 1.2rem; |
| font-weight: inherit; |
| text-align: center; |
| white-space: nowrap; |
| } |
| |
| .config-list { |
| height: 20rem; |
| overflow: scroll; |
| display: block; |
| margin: 0; |
| padding: 0; |
| list-style: none; |
| font-size: inherit; |
| font-weight: inherit; |
| border: none; |
| border-top: solid 1px #ddd; |
| border-bottom: solid 1px #ddd; |
| white-space: nowrap; |
| } |
| |
| #platform-list:empty:before { |
| content: "No matching platform"; |
| display: block; |
| margin: 1rem 0.5rem; |
| text-align: center; |
| } |
| |
| .config-list label { |
| display: block; |
| padding: 0.1rem 0.2rem; |
| } |
| |
| .config-list label:hover, |
| .config-list a:hover { |
| background: rgba(204, 153, 51, 0.1); |
| } |
| |
| .config-list label.selected, |
| .config-list a.selected { |
| background: #eee; |
| } |
| |
| .config-list a { |
| display: block; |
| padding: 0.1rem 0.2rem; |
| text-decoration: none; |
| color: inherit; |
| } |
| |
| #repository-configuration-pane { |
| position: relative; |
| } |
| |
| #repository-configuration-pane > button { |
| margin-left: 19.5rem; |
| } |
| |
| .revision-table { |
| border: none; |
| border-collapse: collapse; |
| font-size: 1rem; |
| } |
| |
| .revision-table thead { |
| font-size: 1.2rem; |
| } |
| |
| .revision-table tbody:empty { |
| display: none; |
| } |
| |
| .revision-table tbody td, |
| .revision-table tbody th { |
| border-top: solid 1px #ddd; |
| padding-top: 0.5rem; |
| padding-bottom: 0.5rem; |
| } |
| |
| .revision-table td, |
| .revision-table th { |
| width: 15rem; |
| height: 1.8rem; |
| padding: 0 0.2rem; |
| border: none; |
| font-weight: inherit; |
| } |
| |
| .revision-table thead th { |
| text-align: center; |
| } |
| |
| .revision-table th close-button { |
| vertical-align: bottom; |
| } |
| |
| .revision-table td:first-child, |
| .revision-table th:first-child { |
| width: 6rem; |
| } |
| |
| .revision-table tr.group-row td { |
| padding-left: 5rem; |
| } |
| |
| label { |
| white-space: nowrap; |
| display: block; |
| } |
| |
| input:not([type=radio]) { |
| width: calc(100% - 0.6rem); |
| padding: 0.1rem 0.2rem; |
| font-size: 0.9rem; |
| font-weight: inherit; |
| } |
| |
| #specify-comparison-pane button { |
| margin-top: 1.5rem; |
| font-size: 1.1rem; |
| font-weight: inherit; |
| } |
| |
| #start-pane button { |
| margin-top: 1.5rem; |
| font-size: 1.2rem; |
| font-weight: inherit; |
| } |
| |
| #baseline-testability li, |
| #comparison-testability li { |
| color: #c33; |
| width: 20rem; |
| } |
| `; |
| } |
| } |
| |
| CustomAnalysisTaskConfigurator.commitFetchInterval = 100; |
| |
| ComponentBase.defineElement('custom-analysis-task-configurator', CustomAnalysisTaskConfigurator); |