diff --git a/web/vtadmin/src/components/App.tsx b/web/vtadmin/src/components/App.tsx index 553770cdaca..e7f284a6fcc 100644 --- a/web/vtadmin/src/components/App.tsx +++ b/web/vtadmin/src/components/App.tsx @@ -83,14 +83,14 @@ export const App = () => { - - - - + + + + diff --git a/web/vtadmin/src/components/routes/workflow/Workflow.module.scss b/web/vtadmin/src/components/routes/workflow/Workflow.module.scss index da8763346d0..251e412c23f 100644 --- a/web/vtadmin/src/components/routes/workflow/Workflow.module.scss +++ b/web/vtadmin/src/components/routes/workflow/Workflow.module.scss @@ -32,7 +32,3 @@ content: none; } } - -.streamTable { - margin: 0 0 48px 0; -} diff --git a/web/vtadmin/src/components/routes/workflow/Workflow.tsx b/web/vtadmin/src/components/routes/workflow/Workflow.tsx index 69b64b7fc0b..6bcb51cbef8 100644 --- a/web/vtadmin/src/components/routes/workflow/Workflow.tsx +++ b/web/vtadmin/src/components/routes/workflow/Workflow.tsx @@ -13,25 +13,22 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { useMemo } from 'react'; -import { groupBy, orderBy } from 'lodash-es'; -import { Link, useParams } from 'react-router-dom'; +import { Link, Redirect, Route, Switch, useParams, useRouteMatch } from 'react-router-dom'; import style from './Workflow.module.scss'; + import { useWorkflow } from '../../../hooks/api'; -import { formatStreamKey, getStreams, getStreamSource, getStreamTarget } from '../../../util/workflows'; -import { DataCell } from '../../dataTable/DataCell'; -import { DataTable } from '../../dataTable/DataTable'; -import { ContentContainer } from '../../layout/ContentContainer'; import { NavCrumbs } from '../../layout/NavCrumbs'; import { WorkspaceHeader } from '../../layout/WorkspaceHeader'; import { WorkspaceTitle } from '../../layout/WorkspaceTitle'; -import { StreamStatePip } from '../../pips/StreamStatePip'; -import { formatAlias } from '../../../util/tablets'; import { useDocumentTitle } from '../../../hooks/useDocumentTitle'; -import { formatDateTime } from '../../../util/time'; import { KeyspaceLink } from '../../links/KeyspaceLink'; -import { TabletLink } from '../../links/TabletLink'; +import { WorkflowStreams } from './WorkflowStreams'; +import { ContentContainer } from '../../layout/ContentContainer'; +import { TabContainer } from '../../tabs/TabContainer'; +import { Tab } from '../../tabs/Tab'; +import { getStreams } from '../../../util/workflows'; +import { Code } from '../../Code'; interface RouteParams { clusterID: string; @@ -39,77 +36,14 @@ interface RouteParams { name: string; } -const COLUMNS = ['Stream', 'Source', 'Target', 'Tablet']; - export const Workflow = () => { const { clusterID, keyspace, name } = useParams(); + const { path, url } = useRouteMatch(); + useDocumentTitle(`${name} (${keyspace})`); const { data } = useWorkflow({ clusterID, keyspace, name }, { refetchInterval: 1000 }); - - const streams = useMemo(() => { - const rows = getStreams(data).map((stream) => ({ - key: formatStreamKey(stream), - ...stream, - })); - - return orderBy(rows, 'streamKey'); - }, [data]); - - const streamsByState = groupBy(streams, 'state'); - - const renderRows = (rows: typeof streams) => { - return rows.map((row) => { - const href = - row.tablet && row.id - ? `/workflow/${clusterID}/${keyspace}/${name}/stream/${row.tablet.cell}/${row.tablet.uid}/${row.id}` - : null; - - const source = getStreamSource(row); - const target = getStreamTarget(row, keyspace); - - return ( - - - {' '} - - {row.key} - -
- Updated {formatDateTime(row.time_updated?.seconds)} -
-
- - {source ? ( - - {source} - - ) : ( - N/A - )} - - - {target ? ( - - {source} - - ) : ( - N/A - )} - - - - {formatAlias(row.tablet)} - - - - ); - }); - }; + const streams = getStreams(data); return (
@@ -131,26 +65,24 @@ export const Workflow = () => {
+ - {/* TODO(doeg): add a protobuf enum for this (https://github.com/vitessio/vitess/projects/12#card-60190340) */} - {['Error', 'Copying', 'Running', 'Stopped'].map((streamState) => { - if (!Array.isArray(streamsByState[streamState])) { - return null; - } + + + + + + + + + + + + + - return ( -
- -
- ); - })} + +
); diff --git a/web/vtadmin/src/components/routes/workflow/WorkflowStreams.module.scss b/web/vtadmin/src/components/routes/workflow/WorkflowStreams.module.scss new file mode 100644 index 00000000000..d3ba1aef1cb --- /dev/null +++ b/web/vtadmin/src/components/routes/workflow/WorkflowStreams.module.scss @@ -0,0 +1,19 @@ +/** + * Copyright 2021 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. + */ + +.streamTable { + margin: 24px 0; +} diff --git a/web/vtadmin/src/components/routes/workflow/WorkflowStreams.tsx b/web/vtadmin/src/components/routes/workflow/WorkflowStreams.tsx new file mode 100644 index 00000000000..81272cb7d43 --- /dev/null +++ b/web/vtadmin/src/components/routes/workflow/WorkflowStreams.tsx @@ -0,0 +1,131 @@ +/** + * Copyright 2021 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 { orderBy, groupBy } from 'lodash-es'; +import React, { useMemo } from 'react'; +import { Link } from 'react-router-dom'; + +import style from './WorkflowStreams.module.scss'; + +import { useWorkflow } from '../../../hooks/api'; +import { formatAlias } from '../../../util/tablets'; +import { formatDateTime } from '../../../util/time'; +import { getStreams, formatStreamKey, getStreamSource, getStreamTarget } from '../../../util/workflows'; +import { DataCell } from '../../dataTable/DataCell'; +import { DataTable } from '../../dataTable/DataTable'; +import { KeyspaceLink } from '../../links/KeyspaceLink'; +import { TabletLink } from '../../links/TabletLink'; +import { StreamStatePip } from '../../pips/StreamStatePip'; + +interface Props { + clusterID: string; + keyspace: string; + name: string; +} + +const COLUMNS = ['Stream', 'Source', 'Target', 'Tablet']; + +export const WorkflowStreams = ({ clusterID, keyspace, name }: Props) => { + const { data } = useWorkflow({ clusterID, keyspace, name }, { refetchInterval: 1000 }); + + const streams = useMemo(() => { + const rows = getStreams(data).map((stream) => ({ + key: formatStreamKey(stream), + ...stream, + })); + + return orderBy(rows, 'streamKey'); + }, [data]); + + const streamsByState = groupBy(streams, 'state'); + + const renderRows = (rows: typeof streams) => { + return rows.map((row) => { + const href = + row.tablet && row.id + ? `/workflow/${clusterID}/${keyspace}/${name}/stream/${row.tablet.cell}/${row.tablet.uid}/${row.id}` + : null; + + const source = getStreamSource(row); + const target = getStreamTarget(row, keyspace); + + return ( + + + {' '} + + {row.key} + +
+ Updated {formatDateTime(row.time_updated?.seconds)} +
+
+ + {source ? ( + + {source} + + ) : ( + N/A + )} + + + {target ? ( + + {source} + + ) : ( + N/A + )} + + + + {formatAlias(row.tablet)} + + + + ); + }); + }; + + return ( +
+ {/* TODO(doeg): add a protobuf enum for this (https://github.com/vitessio/vitess/projects/12#card-60190340) */} + {['Error', 'Copying', 'Running', 'Stopped'].map((streamState) => { + if (!Array.isArray(streamsByState[streamState])) { + return null; + } + + return ( +
+ +
+ ); + })} +
+ ); +};