docs(nxdev): graph widget loads json from file (#13717)

This commit is contained in:
Isaac Mann 2022-12-08 14:22:50 -05:00 committed by GitHub
parent fd7ca43324
commit c9e39e31d7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 266 additions and 357 deletions

View File

@ -40,40 +40,7 @@ graph and then executes the tasks in that graph.
For instance `nx test lib` creates a task graph with a single node:
{% graph height="100px" type="task" %}
```json
{
"projects": [
{
"name": "lib",
"type": "lib",
"data": {
"tags": [],
"targets": {
"test": {}
}
}
}
],
"taskId": "lib:test",
"taskGraphs": {
"lib:test": {
"roots": ["lib:test"],
"tasks": {
"lib:test": {
"id": "lib:test",
"target": { "project": "lib", "target": "test" },
"projectRoot": "libs/lib",
"overrides": {}
}
},
"dependencies": {}
}
}
}
```
{% graph height="100px" type="task" jsonFile="shared/mental-model/single-task.json" %}
{% /graph %}
A task is an invocation of a target. If you invoke the same target twice, you create two tasks.
@ -90,126 +57,10 @@ running `nx run-many --target=test --projects=app1,app2,lib`, the created task g
{% /side-by-side %}
{% side-by-side %}
{% graph height="200px" type="project" %}
```json
{
"projects": [
{
"name": "app1",
"type": "app",
"data": {
"tags": [],
"targets": {
"test": {}
}
}
},
{
"name": "app2",
"type": "app",
"data": {
"tags": [],
"targets": {
"test": {}
}
}
},
{
"name": "lib",
"type": "lib",
"data": {
"tags": [],
"targets": {
"test": {}
}
}
}
],
"dependencies": {
"app1": [{ "source": "app1", "target": "lib", "type": "static" }],
"app2": [{ "source": "app2", "target": "lib", "type": "static" }],
"lib": []
},
"workspaceLayout": {
"appsDir": "apps",
"libsDir": "libs"
},
"affectedProjectIds": [],
"focus": null,
"groupByFolder": false,
"exclude": []
}
```
{% graph height="200px" type="project" jsonFile="shared/mental-model/three-projects.json" %}
{% /graph %}
{% graph height="200px" type="task" %}
```json
{
"projects": [
{
"name": "app1",
"type": "app",
"data": {
"tags": [],
"targets": {
"test": {}
}
}
},
{
"name": "app2",
"type": "app",
"data": {
"tags": [],
"targets": {
"test": {}
}
}
},
{
"name": "lib",
"type": "lib",
"data": {
"tags": [],
"targets": {
"test": {}
}
}
}
],
"taskId": "lib:test",
"taskGraphs": {
"lib:test": {
"roots": ["app1:test", "app2:test", "lib:test"],
"tasks": {
"app1:test": {
"id": "app1:test",
"target": { "project": "app1", "target": "test" },
"projectRoot": "apps/app1",
"overrides": {}
},
"app2:test": {
"id": "app2:test",
"target": { "project": "app2", "target": "test" },
"projectRoot": "apps/app2",
"overrides": {}
},
"lib:test": {
"id": "lib:test",
"target": { "project": "lib", "target": "test" },
"projectRoot": "libs/lib",
"overrides": {}
}
},
"dependencies": {}
}
}
}
```
{% graph height="200px" type="task" jsonFile="shared/mental-model/disconnected-tasks.json"%}
{% /graph %}
{% /side-by-side %}
@ -244,129 +95,10 @@ With this, running the same test command creates the following task graph:
{% /side-by-side %}
{% side-by-side %}
{% graph height="200px" type="project" %}
```json
{
"projects": [
{
"name": "app1",
"type": "app",
"data": {
"tags": [],
"targets": {
"test": {}
}
}
},
{
"name": "app2",
"type": "app",
"data": {
"tags": [],
"targets": {
"test": {}
}
}
},
{
"name": "lib",
"type": "lib",
"data": {
"tags": [],
"targets": {
"test": {}
}
}
}
],
"dependencies": {
"app1": [{ "source": "app1", "target": "lib", "type": "static" }],
"app2": [{ "source": "app2", "target": "lib", "type": "static" }],
"lib": []
},
"workspaceLayout": {
"appsDir": "apps",
"libsDir": "libs"
},
"affectedProjectIds": [],
"focus": null,
"groupByFolder": false,
"exclude": []
}
```
{% graph height="200px" type="project" jsonFile="shared/mental-model/three-projects.json" %}
{% /graph %}
{% graph height="200px" type="task" %}
```json
{
"projects": [
{
"name": "app1",
"type": "app",
"data": {
"tags": [],
"targets": {
"test": {}
}
}
},
{
"name": "app2",
"type": "app",
"data": {
"tags": [],
"targets": {
"test": {}
}
}
},
{
"name": "lib",
"type": "lib",
"data": {
"tags": [],
"targets": {
"test": {}
}
}
}
],
"taskId": "lib:test",
"taskGraphs": {
"lib:test": {
"roots": ["app1:test", "app2:test", "lib:test"],
"tasks": {
"app1:test": {
"id": "app1:test",
"target": { "project": "app1", "target": "test" },
"projectRoot": "apps/app1",
"overrides": {}
},
"app2:test": {
"id": "app2:test",
"target": { "project": "app2", "target": "test" },
"projectRoot": "apps/app2",
"overrides": {}
},
"lib:test": {
"id": "lib:test",
"target": { "project": "lib", "target": "test" },
"projectRoot": "libs/lib",
"overrides": {}
}
},
"dependencies": {
"app1:test": ["lib:test"],
"app2:test": ["lib:test"]
}
}
}
}
```
{% graph height="200px" type="task" jsonFile="shared/mental-model/connected-tasks.json" %}
{% /graph %}
{% /side-by-side %}

View File

@ -0,0 +1,64 @@
{
"projects": [
{
"name": "app1",
"type": "app",
"data": {
"tags": [],
"targets": {
"test": {}
}
}
},
{
"name": "app2",
"type": "app",
"data": {
"tags": [],
"targets": {
"test": {}
}
}
},
{
"name": "lib",
"type": "lib",
"data": {
"tags": [],
"targets": {
"test": {}
}
}
}
],
"taskId": "lib:test",
"taskGraphs": {
"lib:test": {
"roots": ["app1:test", "app2:test", "lib:test"],
"tasks": {
"app1:test": {
"id": "app1:test",
"target": { "project": "app1", "target": "test" },
"projectRoot": "apps/app1",
"overrides": {}
},
"app2:test": {
"id": "app2:test",
"target": { "project": "app2", "target": "test" },
"projectRoot": "apps/app2",
"overrides": {}
},
"lib:test": {
"id": "lib:test",
"target": { "project": "lib", "target": "test" },
"projectRoot": "libs/lib",
"overrides": {}
}
},
"dependencies": {
"app1:test": ["lib:test"],
"app2:test": ["lib:test"]
}
}
}
}

View File

@ -0,0 +1,61 @@
{
"projects": [
{
"name": "app1",
"type": "app",
"data": {
"tags": [],
"targets": {
"test": {}
}
}
},
{
"name": "app2",
"type": "app",
"data": {
"tags": [],
"targets": {
"test": {}
}
}
},
{
"name": "lib",
"type": "lib",
"data": {
"tags": [],
"targets": {
"test": {}
}
}
}
],
"taskId": "lib:test",
"taskGraphs": {
"lib:test": {
"roots": ["app1:test", "app2:test", "lib:test"],
"tasks": {
"app1:test": {
"id": "app1:test",
"target": { "project": "app1", "target": "test" },
"projectRoot": "apps/app1",
"overrides": {}
},
"app2:test": {
"id": "app2:test",
"target": { "project": "app2", "target": "test" },
"projectRoot": "apps/app2",
"overrides": {}
},
"lib:test": {
"id": "lib:test",
"target": { "project": "lib", "target": "test" },
"projectRoot": "libs/lib",
"overrides": {}
}
},
"dependencies": {}
}
}
}

View File

@ -0,0 +1,29 @@
{
"projects": [
{
"name": "lib",
"type": "lib",
"data": {
"tags": [],
"targets": {
"test": {}
}
}
}
],
"taskId": "lib:test",
"taskGraphs": {
"lib:test": {
"roots": ["lib:test"],
"tasks": {
"lib:test": {
"id": "lib:test",
"target": { "project": "lib", "target": "test" },
"projectRoot": "libs/lib",
"overrides": {}
}
},
"dependencies": {}
}
}
}

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 94 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 55 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 6.4 KiB

View File

@ -0,0 +1,47 @@
{
"projects": [
{
"name": "app1",
"type": "app",
"data": {
"tags": [],
"targets": {
"test": {}
}
}
},
{
"name": "app2",
"type": "app",
"data": {
"tags": [],
"targets": {
"test": {}
}
}
},
{
"name": "lib",
"type": "lib",
"data": {
"tags": [],
"targets": {
"test": {}
}
}
}
],
"dependencies": {
"app1": [{ "source": "app1", "target": "lib", "type": "static" }],
"app2": [{ "source": "app2", "target": "lib", "type": "static" }],
"lib": []
},
"workspaceLayout": {
"appsDir": "apps",
"libsDir": "libs"
},
"affectedProjectIds": [],
"focus": null,
"groupByFolder": false,
"exclude": []
}

View File

@ -1,6 +1,19 @@
import { useTheme } from '@nrwl/nx-dev/ui-theme';
import dynamic from 'next/dynamic';
import { ReactElement } from 'react';
import { ReactElement, useEffect, useState } from 'react';
export function Loading() {
return (
<div className="flex h-[450px] w-full items-center justify-center">
<div
className="spinner-border inline-block h-8 w-8 animate-spin rounded-full border-4 border-slate-100 border-r-slate-400 dark:border-slate-700 dark:border-r-slate-500"
role="status"
>
<span className="sr-only">Loading...</span>
</div>
</div>
);
}
/**
* dynamic() can't be used inside of React rendering as it needs to be marked
@ -11,66 +24,69 @@ const NxProjectGraphViz = dynamic(
import('@nrwl/graph/ui-graph').then((module) => module.NxProjectGraphViz),
{
ssr: false,
loading: () => (
<div className="flex h-[450px] w-full items-center justify-center">
<div
className="spinner-border inline-block h-8 w-8 animate-spin rounded-full border-4 border-slate-100 border-r-slate-400 dark:border-slate-700 dark:border-r-slate-500"
role="status"
>
<span className="sr-only">Loading...</span>
</div>
</div>
),
loading: () => <Loading />,
}
);
const NxTaskGraphViz = dynamic(
() => import('@nrwl/graph/ui-graph').then((module) => module.NxTaskGraphViz),
{
ssr: false,
loading: () => (
<div className="flex h-[450px] w-full items-center justify-center">
<div
className="spinner-border inline-block h-8 w-8 animate-spin rounded-full border-4 border-slate-100 border-r-slate-400 dark:border-slate-700 dark:border-r-slate-500"
role="status"
>
<span className="sr-only">Loading...</span>
</div>
</div>
),
loading: () => <Loading />,
}
);
export function Graph({
height,
type,
jsonFile,
children,
}: {
height: string;
type: 'project' | 'task';
jsonFile?: string;
children: ReactElement;
}): JSX.Element {
const [theme] = useTheme();
const [parsedProps, setParsedProps] = useState<any>();
const getData = async (path: string) => {
const response = await fetch('/documentation/' + path, {
headers: {
'Content-Type': 'application/json',
Accept: 'application/json',
},
});
setParsedProps(await response.json());
};
useEffect(() => {
if (jsonFile) {
getData(jsonFile);
}
}, [jsonFile, setParsedProps]);
if (!jsonFile && !parsedProps) {
if (!children || !children.hasOwnProperty('props')) {
return (
<div className="no-prose my-6 block rounded-md bg-red-50 p-4 text-red-700 ring-1 ring-red-100 dark:bg-red-900/30 dark:text-red-600 dark:ring-red-900">
<p className="mb-4">
No JSON provided for graph, use JSON code fence to embed data for
the graph.
</p>
</div>
);
}
if (!children || !children.hasOwnProperty('props'))
return (
<div className="no-prose my-6 block rounded-md bg-red-50 p-4 text-red-700 ring-1 ring-red-100 dark:bg-red-900/30 dark:text-red-600 dark:ring-red-900">
<p className="mb-4">
No JSON provided for graph, use JSON code fence to embed data for the
graph.
</p>
</div>
);
let parsedProps;
try {
parsedProps = JSON.parse(children?.props.children as any);
} catch {
return (
<div className="not-prose my-6 block rounded-md bg-red-50 p-4 text-red-700 ring-1 ring-red-100 dark:bg-red-900/30 dark:text-red-600 dark:ring-red-900">
<p className="mb-4">Could not parse JSON for graph:</p>
<pre className="p-4 text-sm">{children?.props.children as any}</pre>
</div>
);
try {
setParsedProps(JSON.parse(children?.props.children as any));
} catch {
return (
<div className="not-prose my-6 block rounded-md bg-red-50 p-4 text-red-700 ring-1 ring-red-100 dark:bg-red-900/30 dark:text-red-600 dark:ring-red-900">
<p className="mb-4">Could not parse JSON for graph:</p>
<pre className="p-4 text-sm">{children?.props.children as any}</pre>
</div>
);
}
}
if (!parsedProps) {
return <Loading />;
}
return (

View File

@ -5,6 +5,9 @@ export const graph: Schema = {
children: [],
attributes: {
jsonFile: {
type: 'String',
},
type: {
type: 'String',
matches: ['project', 'task'],