From 3c622cd395f06d5a2e987160002338963badb479 Mon Sep 17 00:00:00 2001
From: Elliot Winkler
Date: Thu, 16 Mar 2023 20:03:12 -0600
Subject: [PATCH] [TS dashboard] Draw dependencies between files (#17338)
If you're thinking about converting a file to TypeScript, you might want
to know what files import that file and what files it imports. This
commit makes it so that if you click on a box in the visualization, it
will draw lines between that box and the other boxes which represent its
dependents and dependencies.
Co-authored-by: legobeat <109787230+legobeat@users.noreply.github.com>
---
.../app/components/App.tsx | 166 ++++++++++----
.../app/components/Box.tsx | 69 ++++++
.../app/components/Connections.tsx | 143 ++++++++++++
.../app/components/types.ts | 15 ++
.../app/styles/custom-elements.scss | 60 ++++-
.../common/build-module-partitions.ts | 217 +++++++++++-------
6 files changed, 543 insertions(+), 127 deletions(-)
create mode 100644 development/ts-migration-dashboard/app/components/Box.tsx
create mode 100644 development/ts-migration-dashboard/app/components/Connections.tsx
create mode 100644 development/ts-migration-dashboard/app/components/types.ts
diff --git a/development/ts-migration-dashboard/app/components/App.tsx b/development/ts-migration-dashboard/app/components/App.tsx
index 317856a1f..e5ee1f3d0 100644
--- a/development/ts-migration-dashboard/app/components/App.tsx
+++ b/development/ts-migration-dashboard/app/components/App.tsx
@@ -1,7 +1,9 @@
-import React from 'react';
-import classnames from 'classnames';
-import { Tooltip as ReactTippy } from 'react-tippy';
+import React, { useState } from 'react';
import { readPartitionsFile } from '../../common/partitions-file';
+import type { ModulePartitionChild } from '../../common/build-module-partitions';
+import Box from './Box';
+import Connections from './Connections';
+import type { BoxRect, BoxModel } from './types';
type Summary = {
numConvertedModules: number;
@@ -12,16 +14,85 @@ function calculatePercentageComplete(summary: Summary) {
return ((summary.numConvertedModules / summary.numModules) * 100).toFixed(1);
}
-export default function App() {
- const partitions = readPartitionsFile();
+const partitions = readPartitionsFile();
+const allModules = partitions.flatMap((partition) => {
+ return partition.children;
+});
+const modulesById = allModules.reduce>(
+ (obj, module) => {
+ return { ...obj, [module.id]: module };
+ },
+ {},
+);
+const overallTotal = {
+ numConvertedModules: allModules.filter((module) => module.hasBeenConverted)
+ .length,
+ numModules: allModules.length,
+};
- const allModules = partitions.flatMap((partition) => {
- return partition.children;
- });
- const overallTotal = {
- numConvertedModules: allModules.filter((module) => module.hasBeenConverted)
- .length,
- numModules: allModules.length,
+export default function App() {
+ const [boxRectsByModuleId, setBoxRectsById] = useState | null>(null);
+ const boxesByModuleId =
+ boxRectsByModuleId === null
+ ? {}
+ : Object.values(boxRectsByModuleId).reduce>(
+ (obj, boxRect) => {
+ const module = modulesById[boxRect.moduleId];
+
+ const dependencyBoxRects = module.dependencyIds.reduce(
+ (dependencyBoxes, dependencyId) => {
+ if (boxRectsByModuleId[dependencyId] === undefined) {
+ return dependencyBoxes;
+ }
+ return [...dependencyBoxes, boxRectsByModuleId[dependencyId]];
+ },
+ [],
+ );
+
+ const dependentBoxRects = module.dependentIds.reduce(
+ (dependentBoxes, dependentId) => {
+ if (boxRectsByModuleId[dependentId] === undefined) {
+ return dependentBoxes;
+ }
+ return [...dependentBoxes, boxRectsByModuleId[dependentId]];
+ },
+ [],
+ );
+
+ return {
+ ...obj,
+ [boxRect.moduleId]: {
+ rect: boxRect,
+ dependencyBoxRects,
+ dependentBoxRects,
+ },
+ };
+ },
+ {},
+ );
+ const [activeBoxRectId, setActiveBoxRectId] = useState(null);
+ const activeBoxRect =
+ boxRectsByModuleId === null || activeBoxRectId === null
+ ? null
+ : boxRectsByModuleId[activeBoxRectId];
+
+ const registerBox = (id: string, boxRect: BoxRect) => {
+ setBoxRectsById((existingBoxRectsById) => {
+ if (existingBoxRectsById === undefined) {
+ return { [id]: boxRect };
+ }
+ return { ...existingBoxRectsById, [id]: boxRect };
+ });
+ };
+ const toggleConnectionsFor = (id: string) => {
+ if (activeBoxRectId !== undefined && activeBoxRectId === id) {
+ setActiveBoxRectId(null);
+ } else {
+ setActiveBoxRectId(id);
+ }
};
return (
@@ -50,17 +121,35 @@ export default function App() {
- Each box
-
+ Each box on this page represents a file in the codebase. Gray boxes
+
-
- on this page represents a file that either we want to convert or
- we've already converted to TypeScript (hover over a box to see the
- filename). Boxes that are
-
+
+ represent files that need to be converted to TypeScript. Green boxes
+
-
- greyed out are test or Storybook files.
+
+ are files that have already been converted. Faded boxes
+
+
+
+
+
+
+ are test or Storybook files.
+
+
+
+ You can hover over a box to see the name of the file that it
+ represents. You can also click on a box to see connections between
+ other files;{' '}
+ red lines
+ lead to dependencies (other files that import the file);{' '}
+ blue lines
+ lead to dependents (other files that are imported by the file).
@@ -103,36 +192,25 @@ export default function App() {