vitess.io/vitess@v0.16.2/web/vtadmin/src/components/routes/VTExplain.tsx (about) 1 /** 2 * Copyright 2021 The Vitess Authors. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 import React from 'react'; 17 import { orderBy } from 'lodash-es'; 18 19 import { vtadmin as pb } from '../../proto/vtadmin'; 20 import { useKeyspaces, useVTExplain } from '../../hooks/api'; 21 import { Select } from '../inputs/Select'; 22 import { ContentContainer } from '../layout/ContentContainer'; 23 import { WorkspaceHeader } from '../layout/WorkspaceHeader'; 24 import { WorkspaceTitle } from '../layout/WorkspaceTitle'; 25 import style from './VTExplain.module.scss'; 26 import { Code } from '../Code'; 27 import { useDocumentTitle } from '../../hooks/useDocumentTitle'; 28 import { Label } from '../inputs/Label'; 29 30 // TODO(doeg): persist form data in URL, error handling, loading state, um... hm. Most things still need doing. 31 // This whole component is the hastiest prototype ever. :') 32 export const VTExplain = () => { 33 useDocumentTitle('VTExplain'); 34 35 const { data: keyspaces = [] } = useKeyspaces(); 36 37 const [clusterID, updateCluster] = React.useState<string | null | undefined>(null); 38 const [keyspaceName, updateKeyspace] = React.useState<string | null | undefined>(null); 39 const [sql, updateSQL] = React.useState<string | null | undefined>(null); 40 41 const selectedKeyspace = 42 clusterID && keyspaceName 43 ? keyspaces?.find((k) => k.cluster?.id === clusterID && k.keyspace?.name === keyspaceName) 44 : null; 45 46 const { data, error, refetch } = useVTExplain( 47 { cluster: clusterID, keyspace: keyspaceName, sql }, 48 { 49 // Never cache, never refetch. 50 cacheTime: 0, 51 enabled: false, 52 refetchOnWindowFocus: false, 53 retry: false, 54 } 55 ); 56 57 const onChangeKeyspace = (selectedKeyspace: pb.Keyspace | null | undefined) => { 58 updateCluster(selectedKeyspace?.cluster?.id); 59 updateKeyspace(selectedKeyspace?.keyspace?.name); 60 }; 61 62 const onChangeSQL: React.ChangeEventHandler<HTMLTextAreaElement> = (e) => { 63 updateSQL(e.target.value); 64 }; 65 66 const onSubmit: React.FormEventHandler<HTMLFormElement> = (e) => { 67 e.preventDefault(); 68 refetch(); 69 }; 70 71 return ( 72 <div> 73 <WorkspaceHeader> 74 <WorkspaceTitle>VTExplain</WorkspaceTitle> 75 </WorkspaceHeader> 76 <ContentContainer className={style.container}> 77 <section className={style.panel}> 78 <form className={style.form} onSubmit={onSubmit}> 79 <div> 80 <Select 81 itemToString={(keyspace) => keyspace?.keyspace?.name || ''} 82 items={orderBy(keyspaces, ['keyspace.name', 'cluster.id'])} 83 label="Keyspace" 84 onChange={onChangeKeyspace} 85 placeholder="Choose a keyspace" 86 renderItem={(keyspace) => `${keyspace?.keyspace?.name} (${keyspace?.cluster?.id})`} 87 selectedItem={selectedKeyspace || null} 88 /> 89 </div> 90 <div> 91 <Label label="SQL"> 92 <textarea 93 className={style.sqlInput} 94 onChange={onChangeSQL} 95 rows={10} 96 value={sql || ''} 97 /> 98 </Label> 99 </div> 100 <div className={style.buttons}> 101 <button className="btn" type="submit"> 102 Run VTExplain 103 </button> 104 </div> 105 </form> 106 </section> 107 108 {error && ( 109 <section className={style.errorPanel}> 110 <Code code={JSON.stringify(error, null, 2)} /> 111 </section> 112 )} 113 114 {data?.response && ( 115 <section className={style.panel}> 116 <div className={style.codeContainer}> 117 <Code code={data?.response} /> 118 </div> 119 </section> 120 )} 121 </ContentContainer> 122 </div> 123 ); 124 };