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  };