|  | // 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 m from 'mithril'; | 
|  |  | 
|  | import {Disposable} from '../base/disposable'; | 
|  | import {SimpleResizeObserver} from '../base/resize_observer'; | 
|  | import {undoCommonChatAppReplacements} from '../base/string_utils'; | 
|  | import {QueryResponse, runQuery} from '../common/queries'; | 
|  | import {raf} from '../core/raf_scheduler'; | 
|  | import {EngineProxy} from '../trace_processor/engine'; | 
|  | import {Callout} from '../widgets/callout'; | 
|  | import {Editor} from '../widgets/editor'; | 
|  |  | 
|  | import {globals} from './globals'; | 
|  | import {createPage} from './pages'; | 
|  | import {QueryHistoryComponent, queryHistoryStorage} from './query_history'; | 
|  | import {addQueryResultsTab} from './query_result_tab'; | 
|  | import {QueryTable} from './query_table'; | 
|  |  | 
|  | interface QueryPageState { | 
|  | enteredText: string; | 
|  | executedQuery?: string; | 
|  | queryResult?: QueryResponse; | 
|  | heightPx: string; | 
|  | generation: number; | 
|  | } | 
|  |  | 
|  | const state: QueryPageState = { | 
|  | enteredText: '', | 
|  | heightPx: '100px', | 
|  | generation: 0, | 
|  | }; | 
|  |  | 
|  | function runManualQuery(query: string) { | 
|  | state.executedQuery = query; | 
|  | state.queryResult = undefined; | 
|  | const engine = getEngine(); | 
|  | if (engine) { | 
|  | runQuery(undoCommonChatAppReplacements(query), engine) | 
|  | .then((resp: QueryResponse) => { | 
|  | addQueryResultsTab( | 
|  | { | 
|  | query: query, | 
|  | title: 'Standalone Query', | 
|  | prefetchedResponse: resp, | 
|  | }, | 
|  | 'analyze_page_query', | 
|  | ); | 
|  | // We might have started to execute another query. Ignore it in that | 
|  | // case. | 
|  | if (state.executedQuery !== query) { | 
|  | return; | 
|  | } | 
|  | state.queryResult = resp; | 
|  | raf.scheduleFullRedraw(); | 
|  | }); | 
|  | } | 
|  | raf.scheduleDelayedFullRedraw(); | 
|  | } | 
|  |  | 
|  | function getEngine(): EngineProxy|undefined { | 
|  | const engineId = globals.getCurrentEngine()?.id; | 
|  | if (engineId === undefined) { | 
|  | return undefined; | 
|  | } | 
|  | const engine = globals.engines.get(engineId)?.getProxy('QueryPage'); | 
|  | return engine; | 
|  | } | 
|  |  | 
|  | class QueryInput implements m.ClassComponent { | 
|  | private resize?: Disposable; | 
|  |  | 
|  | oncreate({dom}: m.CVnodeDOM): void { | 
|  | this.resize = new SimpleResizeObserver(dom, () => { | 
|  | state.heightPx = (dom as HTMLElement).style.height; | 
|  | }); | 
|  | (dom as HTMLElement).style.height = state.heightPx; | 
|  | } | 
|  |  | 
|  | onremove(): void { | 
|  | if (this.resize) { | 
|  | this.resize.dispose(); | 
|  | this.resize = undefined; | 
|  | } | 
|  | } | 
|  |  | 
|  | view() { | 
|  | return m(Editor, { | 
|  | generation: state.generation, | 
|  | initialText: state.enteredText, | 
|  |  | 
|  | onExecute: (text: string) => { | 
|  | if (!text) { | 
|  | return; | 
|  | } | 
|  | queryHistoryStorage.saveQuery(text); | 
|  | runManualQuery(text); | 
|  | }, | 
|  |  | 
|  | onUpdate: (text: string) => { | 
|  | state.enteredText = text; | 
|  | }, | 
|  |  | 
|  | }); | 
|  | } | 
|  | } | 
|  |  | 
|  | export const QueryPage = createPage({ | 
|  | view() { | 
|  | return m( | 
|  | '.query-page', | 
|  | m(Callout, 'Enter query and press Cmd/Ctrl + Enter'), | 
|  | m(QueryInput), | 
|  | state.executedQuery === undefined ? null : m(QueryTable, { | 
|  | query: state.executedQuery, | 
|  | resp: state.queryResult, | 
|  | onClose: () => { | 
|  | state.executedQuery = undefined; | 
|  | state.queryResult = undefined; | 
|  | raf.scheduleFullRedraw(); | 
|  | }, | 
|  | fillParent: false, | 
|  | }), | 
|  | m(QueryHistoryComponent, { | 
|  | runQuery: runManualQuery, | 
|  | setQuery: (q: string) => { | 
|  | state.enteredText = q; | 
|  | state.generation++; | 
|  | raf.scheduleFullRedraw(); | 
|  | }, | 
|  | })); | 
|  | }, | 
|  | }); |