Skip to content

Commit

Permalink
VTAdmin(web): Init transactions screen
Browse files Browse the repository at this point in the history
Signed-off-by: Noble Mittal <noblemittal@outlook.com>
  • Loading branch information
beingnoble03 committed Sep 18, 2024
1 parent a1dd579 commit ad867ac
Show file tree
Hide file tree
Showing 6 changed files with 175 additions and 0 deletions.
14 changes: 14 additions & 0 deletions web/vtadmin/src/api/http.ts
Original file line number Diff line number Diff line change
Expand Up @@ -421,6 +421,20 @@ export const fetchVSchema = async ({ clusterID, keyspace }: FetchVSchemaParams)
return pb.VSchema.create(result);
};

export interface FetchTransactionsParams {
clusterID: string;
keyspace: string;
}

export const fetchTransactions = async ({ clusterID, keyspace }: FetchTransactionsParams) => {
const { result } = await vtfetch(`/api/transactions/${clusterID}/${keyspace}`);

const err = vtctldata.GetUnresolvedTransactionsResponse.verify(result);
if (err) throw Error(err);

return vtctldata.GetUnresolvedTransactionsResponse.create(result);
};

export const fetchWorkflows = async () => {
const { result } = await vtfetch(`/api/workflows`);

Expand Down
5 changes: 5 additions & 0 deletions web/vtadmin/src/components/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ import { isReadOnlyMode } from '../util/env';
import { CreateKeyspace } from './routes/createKeyspace/CreateKeyspace';
import { Topology } from './routes/topology/Topology';
import { ClusterTopology } from './routes/topology/ClusterTopology';
import { Transactions } from './routes/Transactions';

export const App = () => {
return (
Expand Down Expand Up @@ -117,6 +118,10 @@ export const App = () => {
<Workflow />
</Route>

<Route path="/transactions">
<Transactions />
</Route>

<Route path="/topology/:clusterID">
<ClusterTopology />
</Route>
Expand Down
3 changes: 3 additions & 0 deletions web/vtadmin/src/components/NavRail.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,9 @@ export const NavRail = () => {
</ul>

<ul className={style.navList}>
<li>
<NavRailLink hotkey="T" text="Transactions" to="/transactions" />
</li>
<li>
<NavRailLink icon={Icons.download} text="Backups" to="/backups" />
</li>
Expand Down
113 changes: 113 additions & 0 deletions web/vtadmin/src/components/routes/Transactions.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
/**
* Copyright 2024 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 { useState } from 'react';
import { useKeyspaces, useTransactions } from '../../hooks/api';
import { DataCell } from '../dataTable/DataCell';
import { DataTable } from '../dataTable/DataTable';
import { ContentContainer } from '../layout/ContentContainer';
import { WorkspaceHeader } from '../layout/WorkspaceHeader';
import { WorkspaceTitle } from '../layout/WorkspaceTitle';
import { QueryLoadingPlaceholder } from '../placeholders/QueryLoadingPlaceholder';
import { useDocumentTitle } from '../../hooks/useDocumentTitle';
import { query } from '../../proto/vtadmin';
import { Select } from '../inputs/Select';
import { FetchTransactionsParams } from '../../api/http';
import { formatTransactionState } from '../../util/transactions';
import { TABLET_TYPES } from '../../util/tablets';
import { ShardLink } from '../links/ShardLink';

const COLUMNS = ['ID', 'State', 'Participants'];

export const Transactions = () => {
useDocumentTitle('Transactions');

const keyspacesQuery = useKeyspaces();

const { data: keyspaces = [] } = keyspacesQuery;

const [params, setParams] = useState<FetchTransactionsParams>({ clusterID: '', keyspace: '' });

const selectedKeyspace = keyspaces.find(
(ks) => ks.keyspace?.name === params.keyspace && ks.cluster?.id === params.clusterID
);

const transactionsQuery = useTransactions(params, {
enabled: !!params.keyspace,
});

const transactions = (transactionsQuery.data && transactionsQuery.data.transactions) || [];

const renderRows = (rows: query.ITransactionMetadata[]) => {
return rows.map((row) => {
return (
<tr key={row.dtid}>
<DataCell>
<div>{row.dtid}</div>
</DataCell>
<DataCell>
<div>{formatTransactionState(row)}</div>
</DataCell>
<DataCell>
{row.participants?.map((participant) => {
const shard = `${participant.keyspace}/${participant.shard}`;
const tabletType = TABLET_TYPES[participant.tablet_type!];
return (
<div>
<ShardLink
clusterID={params.clusterID}
keyspace={participant.keyspace}
shard={participant.shard}
>
{shard}
</ShardLink>
<span className="ml-2 text-sm">{tabletType}</span>
</div>
);
})}
</DataCell>
</tr>
);
});
};

return (
<div>
<WorkspaceHeader className="mb-0">
<WorkspaceTitle>Transactions</WorkspaceTitle>
</WorkspaceHeader>

<ContentContainer>
<Select
className="block w-[740px]"
disabled={keyspacesQuery.isLoading}
inputClassName="block w-full"
items={keyspaces}
label="Keyspace"
onChange={(ks) => setParams({ clusterID: ks?.cluster?.id!, keyspace: ks?.keyspace?.name! })}
placeholder={
keyspacesQuery.isLoading
? 'Loading keyspaces...'
: 'Select a keyspace to view unresolved transactions'
}
renderItem={(ks) => `${ks?.keyspace?.name} (${ks?.cluster?.id})`}
selectedItem={selectedKeyspace}
/>
<DataTable columns={COLUMNS} data={transactions} renderRows={renderRows} />
<QueryLoadingPlaceholder query={transactionsQuery} />
</ContentContainer>
</div>
);
};
12 changes: 12 additions & 0 deletions web/vtadmin/src/hooks/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,8 @@ import {
ValidateVersionShardParams,
startWorkflow,
stopWorkflow,
FetchTransactionsParams,
fetchTransactions,
} from '../api/http';
import { vtadmin as pb, vtctldata } from '../proto/vtadmin';
import { formatAlias } from '../util/tablets';
Expand Down Expand Up @@ -405,6 +407,16 @@ export const useVSchema = (params: FetchVSchemaParams, options?: UseQueryOptions
return useQuery(['vschema', params], () => fetchVSchema(params));
};

/**
* useTransactions is a query hook that fetches unresolved transactions for the given keyspace.
*/
export const useTransactions = (
params: FetchTransactionsParams,
options?: UseQueryOptions<vtctldata.GetUnresolvedTransactionsResponse, Error> | undefined
) => {
return useQuery(['transactions', params], () => fetchTransactions(params), { ...options });
};

export const useVTExplain = (
params: Parameters<typeof fetchVTExplain>[0],
options?: UseQueryOptions<pb.VTExplainResponse, Error> | undefined
Expand Down
28 changes: 28 additions & 0 deletions web/vtadmin/src/util/transactions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/**
* Copyright 2024 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 { invertBy } from 'lodash-es';
import { query } from '../proto/vtadmin';

/**
* TRANSACTION_STATES maps numeric transaction state back to human readable strings.
*/
export const TRANSACTION_STATES = Object.entries(invertBy(query.TransactionState)).reduce((acc, [k, vs]) => {
acc[k] = vs[0];
return acc;
}, {} as { [k: string]: string });

export const formatTransactionState = (transaction: query.ITransactionMetadata) =>
transaction.state && TRANSACTION_STATES[transaction.state];

0 comments on commit ad867ac

Please sign in to comment.