From 2f102bff07875b10e9e2791c0da5bf0761ccba58 Mon Sep 17 00:00:00 2001 From: Ciaran Morinan Date: Mon, 16 Sep 2024 19:33:37 +0100 Subject: [PATCH 1/7] wip: visualize types as graph --- apps/hash-api/src/graph/context-types.ts | 2 +- apps/hash-frontend/package.json | 4 + .../src/pages/shared/entities-table.tsx | 96 +--- .../src/pages/shared/table-header-toggle.tsx | 77 ++++ .../src/pages/shared/table-views.tsx | 34 ++ .../src/pages/shared/types-graph.tsx | 28 ++ .../shared/types-graph/types-graph-loader.tsx | 24 + .../[[...type-kind]].page/types-table.tsx | 87 ++-- yarn.lock | 409 +++++++++++++++--- 9 files changed, 581 insertions(+), 180 deletions(-) create mode 100644 apps/hash-frontend/src/pages/shared/table-header-toggle.tsx create mode 100644 apps/hash-frontend/src/pages/shared/table-views.tsx create mode 100644 apps/hash-frontend/src/pages/shared/types-graph.tsx create mode 100644 apps/hash-frontend/src/pages/shared/types-graph/types-graph-loader.tsx diff --git a/apps/hash-api/src/graph/context-types.ts b/apps/hash-api/src/graph/context-types.ts index 32efca2d504..5c42b6173db 100644 --- a/apps/hash-api/src/graph/context-types.ts +++ b/apps/hash-api/src/graph/context-types.ts @@ -25,7 +25,7 @@ export type ImpureGraphFunction< ReturnType, WithUpload extends boolean = false, WithTemporal extends boolean = false, -> = ( +> = ( context: ImpureGraphContext, authentication: AuthenticationContext, params: Parameters, diff --git a/apps/hash-frontend/package.json b/apps/hash-frontend/package.json index c37dd470d9e..d1463677025 100644 --- a/apps/hash-frontend/package.json +++ b/apps/hash-frontend/package.json @@ -52,6 +52,7 @@ "@ory/client": "1.1.41", "@ory/integrations": "1.1.4", "@popperjs/core": "2.11.8", + "@react-sigma/core": "4.0.3", "@sentry/nextjs": "7.119.0", "@sentry/react": "7.119.0", "@svgr/webpack": "8.1.0", @@ -69,6 +70,7 @@ "emoji-mart": "5.2.1", "fractional-indexing": "2.1.0", "framer-motion": "6.5.1", + "graphology": "0.25.4", "graphql": "16.9.0", "iframe-resizer": "4.4.5", "immer": "9.0.21", @@ -106,6 +108,7 @@ "rooks": "7.14.1", "safe-stable-stringify": "2.5.0", "setimmediate": "1.0.5", + "sigma": "3.0.0-beta.29", "signia": "0.1.5", "signia-react": "0.1.5", "url-regex-safe": "4.0.0", @@ -145,3 +148,4 @@ "node": ">= v20" } } + diff --git a/apps/hash-frontend/src/pages/shared/entities-table.tsx b/apps/hash-frontend/src/pages/shared/entities-table.tsx index 2c1bf14ccc2..cd4d65367a0 100644 --- a/apps/hash-frontend/src/pages/shared/entities-table.tsx +++ b/apps/hash-frontend/src/pages/shared/entities-table.tsx @@ -2,7 +2,6 @@ import type { VersionedUrl } from "@blockprotocol/type-system/slim"; import type { CustomCell, Item, TextCell } from "@glideapps/glide-data-grid"; import { GridCellKind } from "@glideapps/glide-data-grid"; import { EntitiesGraphChart } from "@hashintel/block-design-system"; -import { ListRegularIcon } from "@hashintel/design-system"; import type { EntityId } from "@local/hash-graph-types/entity"; import { gridRowHeight } from "@local/hash-isomorphic-utils/data-grid"; import { systemEntityTypes } from "@local/hash-isomorphic-utils/ontology-type-ids"; @@ -16,16 +15,9 @@ import { type Subgraph, } from "@local/hash-subgraph"; import { extractBaseUrl } from "@local/hash-subgraph/type-system-patch"; -import { - Box, - ToggleButton, - toggleButtonClasses, - ToggleButtonGroup, - Tooltip, - useTheme, -} from "@mui/material"; +import { Box, useTheme } from "@mui/material"; import { useRouter } from "next/router"; -import type { FunctionComponent, ReactNode } from "react"; +import type { FunctionComponent } from "react"; import { useCallback, useEffect, useMemo, useRef, useState } from "react"; import type { GridProps } from "../../components/grid/grid"; @@ -40,8 +32,6 @@ import type { CustomIcon } from "../../components/grid/utils/custom-grid-icons"; import type { ColumnFilter } from "../../components/grid/utils/filtering"; import { useEntityTypeEntitiesContext } from "../../shared/entity-type-entities-context"; import { useEntityTypesContextRequired } from "../../shared/entity-types-context/hooks/use-entity-types-context-required"; -import { ChartNetworkRegularIcon } from "../../shared/icons/chart-network-regular-icon"; -import { GridSolidIcon } from "../../shared/icons/grid-solid-icon"; import { HEADER_HEIGHT } from "../../shared/layout/layout-with-header/page-header"; import type { FilterState } from "../../shared/table-header"; import { TableHeader, tableHeaderHeight } from "../../shared/table-header"; @@ -59,7 +49,9 @@ import { useEntitiesTable } from "./entities-table/use-entities-table"; import { useGetEntitiesTableAdditionalCsvData } from "./entities-table/use-get-entities-table-additional-csv-data"; import { TypeSlideOverStack } from "./entity-type-page/type-slide-over-stack"; import { generateEntityRootedSubgraph } from "./subgraphs"; +import { TableHeaderToggle } from "./table-header-toggle"; import { TOP_CONTEXT_BAR_HEIGHT } from "./top-context-bar"; +import { tableViewIcons, TableView } from "./table-views"; /** * @todo: avoid having to maintain this list, potentially by @@ -83,16 +75,6 @@ const allFileEntityTypeBaseUrl = allFileEntityTypeOntologyIds.map( ({ entityTypeBaseUrl }) => entityTypeBaseUrl, ); -const entitiesTableViews = ["Table", "Graph", "Grid"] as const; - -type EntityTableView = (typeof entitiesTableViews)[number]; - -const entitiesTableViewIcons: Record = { - Table: , - Graph: , - Grid: , -}; - export const EntitiesTable: FunctionComponent<{ hideEntityTypeVersionColumn?: boolean; hidePropertiesColumns?: boolean; @@ -144,7 +126,7 @@ export const EntitiesTable: FunctionComponent<{ const supportGridView = isDisplayingFilesOnly; - const [view, setView] = useState( + const [view, setView] = useState( isDisplayingFilesOnly ? "Grid" : "Table", ); @@ -665,65 +647,21 @@ export const EntitiesTable: FunctionComponent<{ currentlyDisplayedRowsRef={currentlyDisplayedRowsRef} getAdditionalCsvData={getEntitiesTableAdditionalCsvData} endAdornment={ - { - if (updatedView) { - setView(updatedView); - } - }} - aria-label="view" - size="small" - sx={{ - [`.${toggleButtonClasses.root}`]: { - backgroundColor: ({ palette }) => palette.common.white, - "&:not(:last-of-type)": { - borderRightColor: ({ palette }) => palette.gray[20], - borderRightStyle: "solid", - borderRightWidth: 2, - }, - "&:hover": { - backgroundColor: ({ palette }) => palette.common.white, - svg: { - color: ({ palette }) => palette.gray[80], - }, - }, - [`&.${toggleButtonClasses.selected}`]: { - backgroundColor: ({ palette }) => palette.common.white, - svg: { - color: ({ palette }) => palette.gray[90], - }, - }, - svg: { - transition: ({ transitions }) => - transitions.create("color"), - color: ({ palette }) => palette.gray[50], - }, - }, - }} - > - {( + setValue={setView} + options={( [ "Table", ...(supportGridView ? (["Grid"] as const) : []), "Graph", - ] satisfies EntityTableView[] - ).map((viewName) => ( - - - - {entitiesTableViewIcons[viewName]} - - - - ))} - + ] as const satisfies TableView[] + ).map((optionValue) => ({ + icon: tableViewIcons[optionValue], + label: `${optionValue} view`, + value: optionValue, + }))} + /> } filterState={filterState} setFilterState={setFilterState} @@ -740,8 +678,8 @@ export const EntitiesTable: FunctionComponent<{ ? extractBaseUrl(entity.metadata.entityTypeId) === entityTypeBaseUrl : entityTypeId - ? entityTypeId === entity.metadata.entityTypeId - : true + ? entityTypeId === entity.metadata.entityTypeId + : true } filterEntity={(entity) => filterState.includeGlobal diff --git a/apps/hash-frontend/src/pages/shared/table-header-toggle.tsx b/apps/hash-frontend/src/pages/shared/table-header-toggle.tsx new file mode 100644 index 00000000000..72da470ee0b --- /dev/null +++ b/apps/hash-frontend/src/pages/shared/table-header-toggle.tsx @@ -0,0 +1,77 @@ +import { + Box, + ToggleButton, + toggleButtonClasses, + ToggleButtonGroup, + Tooltip, +} from "@mui/material"; +import type { ReactElement } from "react"; + +type TableHeaderToggleProps