diff --git a/dashboard/components/Layout.tsx b/dashboard/components/Layout.tsx index 6d6b17cdc7d80..663e30367c110 100644 --- a/dashboard/components/Layout.tsx +++ b/dashboard/components/Layout.tsx @@ -115,7 +115,7 @@ function Layout({ children }: { children: React.ReactNode }) { Catalog - Data Sources + Sources Tables Materialized Views @@ -123,6 +123,7 @@ function Layout({ children }: { children: React.ReactNode }) { Indexes Internal Tables Sinks + Views Streaming diff --git a/dashboard/components/Relations.tsx b/dashboard/components/Relations.tsx index 118a335549e13..4aafbac75d905 100644 --- a/dashboard/components/Relations.tsx +++ b/dashboard/components/Relations.tsx @@ -209,7 +209,7 @@ export function Relations( ))} {r.columns - .filter((col) => !col.isHidden) + .filter((col) => ("isHidden" in col ? !col.isHidden : true)) .map((col) => extractColumnInfo(col)) .join(", ")} diff --git a/dashboard/lib/extractInfo.ts b/dashboard/lib/extractInfo.ts index fc6eccf669eed..2ae779eb44887 100644 --- a/dashboard/lib/extractInfo.ts +++ b/dashboard/lib/extractInfo.ts @@ -15,8 +15,14 @@ * */ -import { ColumnCatalog } from "../proto/gen/plan_common" +import { ColumnCatalog, Field } from "../proto/gen/plan_common" -export default function extractColumnInfo(col: ColumnCatalog) { - return `${col.columnDesc?.name} (${col.columnDesc?.columnType?.typeName})` +export default function extractColumnInfo(col: ColumnCatalog | Field) { + if ("columnDesc" in col) { + // ColumnCatalog + return `${col.columnDesc?.name} (${col.columnDesc?.columnType?.typeName})` + } else { + // Field + return `${col.name} (${col.dataType?.typeName})` + } } diff --git a/dashboard/pages/api/streaming.ts b/dashboard/pages/api/streaming.ts index 879c02a5ccfcd..67e43ffc858ca 100644 --- a/dashboard/pages/api/streaming.ts +++ b/dashboard/pages/api/streaming.ts @@ -17,9 +17,9 @@ import _ from "lodash" import sortBy from "lodash/sortBy" -import { Sink, Source, Table } from "../../proto/gen/catalog" +import { Sink, Source, Table, View } from "../../proto/gen/catalog" import { ActorLocation, TableFragments } from "../../proto/gen/meta" -import { ColumnCatalog } from "../../proto/gen/plan_common" +import { ColumnCatalog, Field } from "../../proto/gen/plan_common" import api from "./api" export async function getActors(): Promise { @@ -38,7 +38,7 @@ export interface Relation { id: number name: string owner: number - columns: ColumnCatalog[] + columns: (ColumnCatalog | Field)[] properties: { [key: string]: string } } @@ -67,7 +67,7 @@ export async function getRelations() { await getTables(), await getIndexes(), await getSinks(), - await getDataSources() + await getSources() ) relations = sortBy(relations, (x) => x.id) return relations @@ -103,10 +103,16 @@ export async function getSinks() { return sinkList } -export async function getDataSources() { +export async function getSources() { let sourceList: Source[] = (await api.get("/api/sources")).map( Source.fromJSON ) sourceList = sortBy(sourceList, (x) => x.id) return sourceList } + +export async function getViews() { + let views: View[] = (await api.get("/api/views")).map(View.fromJSON) + views = sortBy(views, (x) => x.id) + return views +} diff --git a/dashboard/pages/data_sources.tsx b/dashboard/pages/sources.tsx similarity index 90% rename from dashboard/pages/data_sources.tsx rename to dashboard/pages/sources.tsx index 568d2da9dcc75..f86a11815e835 100644 --- a/dashboard/pages/data_sources.tsx +++ b/dashboard/pages/sources.tsx @@ -22,7 +22,7 @@ import { Relations, } from "../components/Relations" import { Source } from "../proto/gen/catalog" -import { getDataSources } from "./api/streaming" +import { getSources } from "./api/streaming" export default function DataSources() { const rowFormatColumn: Column = { @@ -31,7 +31,7 @@ export default function DataSources() { content: (s) => s.info?.rowFormat ?? "unknown", } - return Relations("Data Sources", getDataSources, [ + return Relations("Sources", getSources, [ connectorColumn, rowFormatColumn, dependentsColumn, diff --git a/dashboard/pages/views.tsx b/dashboard/pages/views.tsx new file mode 100644 index 0000000000000..d60db3d0c5537 --- /dev/null +++ b/dashboard/pages/views.tsx @@ -0,0 +1,23 @@ +/* + * Copyright 2023 RisingWave Labs + * + * 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 { Relations } from "../components/Relations" +import { getViews } from "./api/streaming" + +export default function Views() { + return Relations("Views", getViews, []) +} diff --git a/src/meta/src/dashboard/mod.rs b/src/meta/src/dashboard/mod.rs index f8878b4afdb25..f4fa21437fc1b 100644 --- a/src/meta/src/dashboard/mod.rs +++ b/src/meta/src/dashboard/mod.rs @@ -59,7 +59,7 @@ pub(super) mod handlers { use risingwave_common::bail; use risingwave_common_heap_profiling::COLLAPSED_SUFFIX; use risingwave_pb::catalog::table::TableType; - use risingwave_pb::catalog::{Sink, Source, Table}; + use risingwave_pb::catalog::{Sink, Source, Table, View}; use risingwave_pb::common::{WorkerNode, WorkerType}; use risingwave_pb::meta::{ActorLocation, PbTableFragments}; use risingwave_pb::monitor_service::{ @@ -162,6 +162,13 @@ pub(super) mod handlers { Ok(Json(sinks)) } + pub async fn list_views(Extension(srv): Extension) -> Result>> { + use crate::model::MetadataModel; + + let sinks = View::list(&srv.meta_store).await.map_err(err)?; + Ok(Json(sinks)) + } + pub async fn list_actors( Extension(srv): Extension, ) -> Result>> { @@ -339,6 +346,7 @@ impl DashboardService { .route("/clusters/:ty", get(list_clusters)) .route("/actors", get(list_actors)) .route("/fragments2", get(list_fragments)) + .route("/views", get(list_views)) .route("/materialized_views", get(list_materialized_views)) .route("/tables", get(list_tables)) .route("/indexes", get(list_indexes))