1// Copyright (C) 2023 The Android Open Source Project 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// http://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14 15import m from 'mithril'; 16 17import {raf} from '../../core/raf_scheduler'; 18import {Engine} from '../../trace_processor/engine'; 19import {STR} from '../../trace_processor/query_result'; 20import { 21 constraintsToQueryPrefix, 22 constraintsToQuerySuffix, 23 SQLConstraints, 24} from '../../trace_processor/sql_utils'; 25import {FilterableSelect} from '../../widgets/select'; 26import {Spinner} from '../../widgets/spinner'; 27 28import {argColumn} from './column'; 29import {ArgSetIdColumn} from './table_description'; 30 31const MAX_ARGS_TO_DISPLAY = 15; 32 33interface ArgumentSelectorAttrs { 34 engine: Engine; 35 argSetId: ArgSetIdColumn; 36 tableName: string; 37 constraints: SQLConstraints; 38 // List of aliases for existing columns by the table. 39 alreadySelectedColumns: Set<string>; 40 onArgumentSelected: (argument: string) => void; 41} 42 43// A widget which allows the user to select a new argument to display. 44// Dinamically queries Trace Processor to find the relevant set of arg_set_ids 45// and which args are present in these arg sets. 46export class ArgumentSelector 47 implements m.ClassComponent<ArgumentSelectorAttrs> 48{ 49 argList?: string[]; 50 51 constructor({attrs}: m.Vnode<ArgumentSelectorAttrs>) { 52 this.load(attrs); 53 } 54 55 private async load(attrs: ArgumentSelectorAttrs) { 56 const queryResult = await attrs.engine.query(` 57 -- Encapsulate the query in a CTE to avoid clashes between filters 58 -- and columns of the 'args' table. 59 WITH arg_sets AS ( 60 ${constraintsToQueryPrefix(attrs.constraints)} 61 SELECT DISTINCT ${attrs.tableName}.${attrs.argSetId.name} as arg_set_id 62 FROM ${attrs.tableName} 63 ${constraintsToQuerySuffix(attrs.constraints)} 64 ) 65 SELECT 66 DISTINCT args.key as key 67 FROM arg_sets 68 JOIN args USING (arg_set_id) 69 `); 70 this.argList = []; 71 const it = queryResult.iter({key: STR}); 72 for (; it.valid(); it.next()) { 73 const arg = argColumn(attrs.tableName, attrs.argSetId, it.key); 74 if (attrs.alreadySelectedColumns.has(arg.alias)) continue; 75 this.argList.push(it.key); 76 } 77 raf.scheduleFullRedraw(); 78 } 79 80 view({attrs}: m.Vnode<ArgumentSelectorAttrs>) { 81 if (this.argList === undefined) return m(Spinner); 82 return m(FilterableSelect, { 83 values: this.argList, 84 onSelected: (value: string) => attrs.onArgumentSelected(value), 85 maxDisplayedItems: MAX_ARGS_TO_DISPLAY, 86 autofocusInput: true, 87 }); 88 } 89} 90