Skip to content

Commit

Permalink
VTAdmin(web): Better visualization for JSON screens (#17459)
Browse files Browse the repository at this point in the history
Signed-off-by: Noble Mittal <[email protected]>
  • Loading branch information
beingnoble03 authored Jan 7, 2025
1 parent 69e0224 commit 68861b1
Show file tree
Hide file tree
Showing 8 changed files with 209 additions and 9 deletions.
68 changes: 66 additions & 2 deletions web/vtadmin/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions web/vtadmin/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-flow-renderer": "^10.3.17",
"react-json-tree": "^0.19.0",
"react-query": "^3.5.9",
"react-router-dom": "^5.3.4",
"react-tiny-popover": "^6.0.5",
Expand Down
95 changes: 95 additions & 0 deletions web/vtadmin/src/components/jsonViewTree/JSONViewTree.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
/**
* Copyright 2025 The Vitess Authors.
*
* 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 React, { useState } from 'react';
import { JSONTree } from 'react-json-tree';

const vtAdminTheme = {
scheme: 'vtadmin',
author: 'custom',
base00: '#ffffff',
base01: '#f6f8fa',
base02: '#e6e8eb',
base03: '#8c8c8c',
base04: '#3c3c3c',
base05: '#2c2c2c',
base06: '#0057b8',
base07: '#000000',
base08: '#00875a',
base09: '#2c2c2c',
base0A: '#e44d26',
base0B: '#2c2c2c',
base0C: '#1a73e8',
base0D: '#3d5afe',
base0E: '#3cba54',
base0F: '#ff6f61',
};

interface JSONViewTreeProps {
data: any;
}

const JSONViewTree: React.FC<JSONViewTreeProps> = ({ data }) => {
const [expandAll, setExpandAll] = useState(false);
const [treeKey, setTreeKey] = useState(0);

const handleExpand = () => {
setExpandAll(true);
setTreeKey((prev) => prev + 1);
};

const handleCollapse = () => {
setExpandAll(false);
setTreeKey((prev) => prev + 1);
};

const getItemString = (type: string, data: any) => {
if (Array.isArray(data)) {
return `${type}[${data.length}]`;
}
return type;
};

if (!data) return null;
return (
<div className="p-1">
<div className="flex mt-2 gap-2">
<button onClick={handleExpand} className="btn btn-secondary btn-sm">
Expand All
</button>
<button onClick={handleCollapse} className="btn btn-danger bg-transparent text-red-500 btn-sm">
Collapse All
</button>
</div>
<JSONTree
key={treeKey}
data={data}
theme={{
extend: vtAdminTheme,
nestedNodeItemString: {
color: vtAdminTheme.base0C,
},
}}
invertTheme={false}
hideRoot={true}
getItemString={getItemString}
shouldExpandNodeInitially={() => expandAll}
/>
</div>
);
};

export default JSONViewTree;
9 changes: 8 additions & 1 deletion web/vtadmin/src/components/routes/keyspace/Keyspace.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ import { Link, Redirect, Route } from 'react-router-dom';
import { useKeyspace } from '../../../hooks/api';
import { useDocumentTitle } from '../../../hooks/useDocumentTitle';
import { isReadOnlyMode } from '../../../util/env';
import { Code } from '../../Code';
import { ContentContainer } from '../../layout/ContentContainer';
import { NavCrumbs } from '../../layout/NavCrumbs';
import { WorkspaceHeader } from '../../layout/WorkspaceHeader';
Expand All @@ -32,6 +31,8 @@ import { Advanced } from './Advanced';
import style from './Keyspace.module.scss';
import { KeyspaceShards } from './KeyspaceShards';
import { KeyspaceVSchema } from './KeyspaceVSchema';
import JSONViewTree from '../../jsonViewTree/JSONViewTree';
import { Code } from '../../Code';

interface RouteParams {
clusterID: string;
Expand Down Expand Up @@ -94,6 +95,7 @@ export const Keyspace = () => {
<Tab text="Shards" to={`${url}/shards`} />
<Tab text="VSchema" to={`${url}/vschema`} />
<Tab text="JSON" to={`${url}/json`} />
<Tab text="JSON Tree" to={`${url}/json_tree`} />

<ReadOnlyGate>
<Tab text="Advanced" to={`${url}/advanced`} />
Expand All @@ -114,6 +116,11 @@ export const Keyspace = () => {
<Code code={JSON.stringify(keyspace, null, 2)} />
</Route>

<Route path={`${path}/json_tree`}>
<QueryLoadingPlaceholder query={kq} />
<JSONViewTree data={keyspace} />
</Route>

{!isReadOnlyMode() && (
<Route path={`${path}/advanced`}>
<Advanced clusterID={clusterID} name={name} />
Expand Down
5 changes: 4 additions & 1 deletion web/vtadmin/src/components/routes/shard/Shard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,13 @@ import { WorkspaceTitle } from '../../layout/WorkspaceTitle';
import { ContentContainer } from '../../layout/ContentContainer';
import { Tab } from '../../tabs/Tab';
import { TabContainer } from '../../tabs/TabContainer';
import { Code } from '../../Code';
import { useDocumentTitle } from '../../../hooks/useDocumentTitle';
import { KeyspaceLink } from '../../links/KeyspaceLink';
import { useKeyspace } from '../../../hooks/api';
import { ShardTablets } from './ShardTablets';
import Advanced from './Advanced';
import JSONViewTree from '../../jsonViewTree/JSONViewTree';
import { Code } from '../../Code';

interface RouteParams {
clusterID: string;
Expand Down Expand Up @@ -114,6 +115,7 @@ export const Shard = () => {
<TabContainer>
<Tab text="Tablets" to={`${url}/tablets`} />
<Tab text="JSON" to={`${url}/json`} />
<Tab text="JSON Tree" to={`${url}/json_tree`} />
<Tab text="Advanced" to={`${url}/advanced`} />
</TabContainer>

Expand All @@ -123,6 +125,7 @@ export const Shard = () => {
</Route>

<Route path={`${path}/json`}>{shard && <Code code={JSON.stringify(shard, null, 2)} />}</Route>
<Route path={`${path}/json_tree`}>{shard && <JSONViewTree data={shard} />}</Route>
<Route path={`${path}/advanced`}>
<Advanced />
</Route>
Expand Down
20 changes: 17 additions & 3 deletions web/vtadmin/src/components/routes/stream/Stream.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,20 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { Link, useParams } from 'react-router-dom';
import { Link, Redirect, Route, Switch, useParams, useRouteMatch } from 'react-router-dom';

import { useWorkflow } from '../../../hooks/api';
import { useDocumentTitle } from '../../../hooks/useDocumentTitle';
import { formatStreamKey, getStream } from '../../../util/workflows';
import { Code } from '../../Code';
import { ContentContainer } from '../../layout/ContentContainer';
import { NavCrumbs } from '../../layout/NavCrumbs';
import { WorkspaceHeader } from '../../layout/WorkspaceHeader';
import { WorkspaceTitle } from '../../layout/WorkspaceTitle';
import style from './Stream.module.scss';
import JSONViewTree from '../../jsonViewTree/JSONViewTree';
import { TabContainer } from '../../tabs/TabContainer';
import { Tab } from '../../tabs/Tab';
import { Code } from '../../Code';

interface RouteParams {
clusterID: string;
Expand All @@ -36,6 +39,7 @@ interface RouteParams {

export const Stream = () => {
const params = useParams<RouteParams>();
const { path, url } = useRouteMatch();
const { data: workflow } = useWorkflow({
clusterID: params.clusterID,
keyspace: params.keyspace,
Expand Down Expand Up @@ -72,7 +76,17 @@ export const Stream = () => {
</div>
</WorkspaceHeader>
<ContentContainer>
<Code code={JSON.stringify(stream, null, 2)} />
<TabContainer>
<Tab text="JSON" to={`${url}/json`} />
<Tab text="JSON Tree" to={`${url}/json_tree`} />
</TabContainer>

<Switch>
<Route path={`${path}/json`}>{stream && <Code code={JSON.stringify(stream, null, 2)} />}</Route>
<Route path={`${path}/json_tree`}>{stream && <JSONViewTree data={stream} />}</Route>

<Redirect exact from={path} to={`${path}/json`} />
</Switch>
</ContentContainer>
</div>
);
Expand Down
12 changes: 11 additions & 1 deletion web/vtadmin/src/components/routes/tablet/Tablet.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ import { useExperimentalTabletDebugVars, useTablet } from '../../../hooks/api';
import { useDocumentTitle } from '../../../hooks/useDocumentTitle';
import { isReadOnlyMode } from '../../../util/env';
import { formatDisplayType, formatState } from '../../../util/tablets';
import { Code } from '../../Code';
import { ContentContainer } from '../../layout/ContentContainer';
import { NavCrumbs } from '../../layout/NavCrumbs';
import { WorkspaceHeader } from '../../layout/WorkspaceHeader';
Expand All @@ -34,6 +33,8 @@ import style from './Tablet.module.scss';
import { TabletCharts } from './TabletCharts';
import { env } from '../../../util/env';
import FullStatus from './FullStatus';
import JSONViewTree from '../../jsonViewTree/JSONViewTree';
import { Code } from '../../Code';

interface RouteParams {
alias: string;
Expand Down Expand Up @@ -108,6 +109,7 @@ export const Tablet = () => {
<Tab text="QPS" to={`${url}/qps`} />
<Tab text="Full Status" to={`${url}/full-status`} />
<Tab text="JSON" to={`${url}/json`} />
<Tab text="JSON Tree" to={`${url}/json_tree`} />
<ReadOnlyGate>
<Tab text="Advanced" to={`${url}/advanced`} />
</ReadOnlyGate>
Expand All @@ -128,6 +130,14 @@ export const Tablet = () => {
</div>
</Route>

<Route path={`${path}/json_tree`}>
<div>
<JSONViewTree data={tablet} />

{env().VITE_ENABLE_EXPERIMENTAL_TABLET_DEBUG_VARS && <JSONViewTree data={debugVars} />}
</div>
</Route>

<Route path={`${url}/full-status`}>{tablet && <FullStatus tablet={tablet} />}</Route>

{!isReadOnlyMode() && (
Expand Down
Loading

0 comments on commit 68861b1

Please sign in to comment.