vitess.io/vitess@v0.16.2/web/vtadmin/src/components/routes/schema/Schema.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 * as React from 'react';
    17  import { Link, useParams } from 'react-router-dom';
    18  
    19  import style from './Schema.module.scss';
    20  import { useSchema, useVSchema } from '../../../hooks/api';
    21  import { Code } from '../../Code';
    22  import { useDocumentTitle } from '../../../hooks/useDocumentTitle';
    23  import { getVindexesForTable } from '../../../util/vschemas';
    24  import { ContentContainer } from '../../layout/ContentContainer';
    25  import { NavCrumbs } from '../../layout/NavCrumbs';
    26  import { WorkspaceHeader } from '../../layout/WorkspaceHeader';
    27  import { WorkspaceTitle } from '../../layout/WorkspaceTitle';
    28  import { Tooltip } from '../../tooltip/Tooltip';
    29  import { KeyspaceLink } from '../../links/KeyspaceLink';
    30  
    31  interface RouteParams {
    32      clusterID: string;
    33      keyspace: string;
    34      table: string;
    35  }
    36  
    37  export const Schema = () => {
    38      const { clusterID, keyspace, table } = useParams<RouteParams>();
    39      useDocumentTitle(`${table} (${keyspace})`);
    40  
    41      const { data, error, isError, isLoading, isSuccess } = useSchema({ clusterID, keyspace, table });
    42      const vschemaQuery = useVSchema({ clusterID, keyspace });
    43  
    44      const tableDefinition = React.useMemo(
    45          () =>
    46              data && Array.isArray(data.table_definitions)
    47                  ? data?.table_definitions.find((t) => t.name === table)
    48                  : null,
    49          [data, table]
    50      );
    51  
    52      const tableVindexes = React.useMemo(
    53          () => (vschemaQuery.data ? getVindexesForTable(vschemaQuery.data, table) : []),
    54          [vschemaQuery.data, table]
    55      );
    56  
    57      const is404 = isSuccess && !tableDefinition;
    58  
    59      return (
    60          <div>
    61              {!is404 && !isError && (
    62                  <WorkspaceHeader>
    63                      <NavCrumbs>
    64                          <Link to="/schemas">Schemas</Link>
    65                      </NavCrumbs>
    66  
    67                      <WorkspaceTitle className="font-mono">{table}</WorkspaceTitle>
    68  
    69                      <div className={style.headingMeta}>
    70                          <span>
    71                              Cluster: <code>{clusterID}</code>
    72                          </span>
    73                          <span>
    74                              Keyspace:{' '}
    75                              <KeyspaceLink clusterID={clusterID} name={keyspace}>
    76                                  <code>{keyspace}</code>
    77                              </KeyspaceLink>
    78                          </span>
    79                      </div>
    80                  </WorkspaceHeader>
    81              )}
    82  
    83              <ContentContainer>
    84                  {/* TODO: skeleton placeholder */}
    85                  {isLoading && <div className={style.loadingPlaceholder}>Loading...</div>}
    86  
    87                  {isError && (
    88                      <div className={style.errorPlaceholder}>
    89                          <span className={style.errorEmoji}>😰</span>
    90                          <h1>An error occurred</h1>
    91                          <code>{(error as any).response?.error?.message || error?.message}</code>
    92                          <p>
    93                              <Link to="/schemas">← All schemas</Link>
    94                          </p>
    95                      </div>
    96                  )}
    97  
    98                  {is404 && (
    99                      <div className={style.errorPlaceholder}>
   100                          <span className={style.errorEmoji}>😖</span>
   101                          <h1>Schema not found</h1>
   102                          <p>
   103                              No schema found with table <code>{table}</code> in keyspace <code>{keyspace}</code> (cluster{' '}
   104                              <code>{clusterID}</code>).
   105                          </p>
   106                          <p>
   107                              <Link to="/schemas">← All schemas</Link>
   108                          </p>
   109                      </div>
   110                  )}
   111  
   112                  {!is404 && !isError && tableDefinition && (
   113                      <div className={style.container}>
   114                          <section className={style.panel}>
   115                              <h3 className="my-8">Table Definition</h3>
   116                              <Code code={tableDefinition.schema} />
   117                          </section>
   118  
   119                          {!!tableVindexes.length && (
   120                              <section className={style.panel}>
   121                                  <h3 className="my-8">Vindexes</h3>
   122                                  <p>
   123                                      A Vindex provides a way to map a column value to a keyspace ID. Since each shard in
   124                                      Vitess covers a range of keyspace ID values, this mapping can be used to identify
   125                                      which shard contains a row.{' '}
   126                                      <a
   127                                          href="https://vitess.io/docs/reference/features/vindexes/"
   128                                          target="_blank"
   129                                          rel="noopen noreferrer"
   130                                      >
   131                                          Learn more about Vindexes in the Vitess documentation.
   132                                      </a>
   133                                  </p>
   134  
   135                                  <table>
   136                                      <thead>
   137                                          <tr>
   138                                              <th>Vindex</th>
   139                                              <th>Columns</th>
   140                                              <th>Type</th>
   141                                              <th>Params</th>
   142                                          </tr>
   143                                      </thead>
   144                                      <tbody className="font-mono">
   145                                          {tableVindexes.map((v, vdx) => {
   146                                              const columns = v.column ? [v.column] : v.columns;
   147                                              return (
   148                                                  <tr key={v.name}>
   149                                                      <td>
   150                                                          {v.name}
   151  
   152                                                          {vdx === 0 && (
   153                                                              <Tooltip text="A table's Primary Vindex maps a column value to a keyspace ID.">
   154                                                                  <span className={style.skBadge}>Primary</span>
   155                                                              </Tooltip>
   156                                                          )}
   157                                                      </td>
   158                                                      <td>{(columns || []).join(', ')}</td>
   159                                                      <td>{v.meta?.type}</td>
   160                                                      <td>
   161                                                          {v.meta?.params ? (
   162                                                              Object.entries(v.meta.params).map(([k, val]) => (
   163                                                                  <div key={k}>
   164                                                                      <strong>{k}: </strong> {val}
   165                                                                  </div>
   166                                                              ))
   167                                                          ) : (
   168                                                              <span className="text-sm text-secondary">N/A</span>
   169                                                          )}
   170                                                      </td>
   171                                                  </tr>
   172                                              );
   173                                          })}
   174                                      </tbody>
   175                                  </table>
   176                              </section>
   177                          )}
   178                      </div>
   179                  )}
   180              </ContentContainer>
   181          </div>
   182      );
   183  };