@teambit/graph 1.0.316 → 1.0.318

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. package/artifacts/__bit_junit.xml +1 -1
  2. package/artifacts/preview/teambit_component_graph-preview.js +1 -1
  3. package/artifacts/schema.json +281 -172
  4. package/dist/graph.graphql.js +3 -2
  5. package/dist/graph.graphql.js.map +1 -1
  6. package/dist/{preview-1719372071684.js → preview-1719544843434.js} +2 -2
  7. package/dist/ui/component-node/component-node.js +6 -7
  8. package/dist/ui/component-node/component-node.js.map +1 -1
  9. package/dist/ui/dependencies-compare/compare-node-model.d.ts +1 -1
  10. package/dist/ui/dependencies-compare/compare-node-model.js.map +1 -1
  11. package/dist/ui/dependencies-compare/dependency-compare-node.js +7 -4
  12. package/dist/ui/dependencies-compare/dependency-compare-node.js.map +1 -1
  13. package/dist/ui/dependencies-compare/diff-graph.js +4 -4
  14. package/dist/ui/dependencies-compare/diff-graph.js.map +1 -1
  15. package/dist/ui/dependencies-graph/calc-elements.js +2 -2
  16. package/dist/ui/dependencies-graph/calc-elements.js.map +1 -1
  17. package/dist/ui/dependencies-graph/dependencies-graph.d.ts +3 -2
  18. package/dist/ui/dependencies-graph/dependencies-graph.js +30 -12
  19. package/dist/ui/dependencies-graph/dependencies-graph.js.map +1 -1
  20. package/dist/ui/graph-page/graph-filters.d.ts +1 -0
  21. package/dist/ui/graph-page/graph-filters.js.map +1 -1
  22. package/dist/ui/graph-page/graph-page.js +18 -19
  23. package/dist/ui/graph-page/graph-page.js.map +1 -1
  24. package/dist/ui/graph-page/graph-page.module.scss +3 -1
  25. package/dist/ui/graph.section.js +3 -3
  26. package/dist/ui/graph.section.js.map +1 -1
  27. package/dist/ui/query/get-graph.query.d.ts +2 -1
  28. package/dist/ui/query/get-graph.query.js +15 -3
  29. package/dist/ui/query/get-graph.query.js.map +1 -1
  30. package/dist/ui/query/node-model.d.ts +3 -2
  31. package/dist/ui/query/node-model.js +3 -1
  32. package/dist/ui/query/node-model.js.map +1 -1
  33. package/dist/ui/query/use-graph-query.d.ts +2 -1
  34. package/dist/ui/query/use-graph-query.js +43 -14
  35. package/dist/ui/query/use-graph-query.js.map +1 -1
  36. package/dist/ui/query/use-graph.d.ts +2 -0
  37. package/package.json +13 -15
  38. package/ui/component-node/component-node.tsx +6 -5
  39. package/ui/dependencies-compare/compare-node-model.ts +1 -1
  40. package/ui/dependencies-compare/dependency-compare-node.tsx +4 -4
  41. package/ui/dependencies-compare/diff-graph.ts +5 -4
  42. package/ui/dependencies-graph/calc-elements.tsx +2 -2
  43. package/ui/dependencies-graph/dependencies-graph.tsx +29 -10
  44. package/ui/graph-page/graph-filters.tsx +1 -0
  45. package/ui/graph-page/graph-page.module.scss +3 -1
  46. package/ui/graph-page/graph-page.tsx +17 -15
  47. package/ui/graph.section.tsx +3 -3
  48. package/ui/query/get-graph.query.ts +15 -5
  49. package/ui/query/node-model.ts +5 -3
  50. package/ui/query/use-graph-query.ts +53 -11
@@ -1,4 +1,4 @@
1
- import React, { useCallback, useEffect, useMemo, useRef } from 'react';
1
+ import React, { useCallback, useMemo, useRef, useEffect } from 'react';
2
2
  import classnames from 'classnames';
3
3
  import ReactFlow, {
4
4
  Background,
@@ -11,6 +11,7 @@ import ReactFlow, {
11
11
  Position,
12
12
  ReactFlowProps,
13
13
  ReactFlowProvider,
14
+ useNodesState,
14
15
  } from 'reactflow';
15
16
  import { ComponentID } from '@teambit/component';
16
17
  import { ComponentWidgetSlot } from '../../graph.ui.runtime';
@@ -36,9 +37,10 @@ function ComponentNodeContainer(props: NodeProps) {
36
37
 
37
38
  export type DependenciesGraphProps = {
38
39
  rootNode: ComponentID;
39
- graph: GraphModel<NodeModel, EdgeModel>;
40
+ graph?: GraphModel<NodeModel, EdgeModel>;
40
41
  componentWidgets: ComponentWidgetSlot;
41
42
  onLoad?: (instance: ReactFlowInstance) => void;
43
+ loadingGraphMetadata?: boolean;
42
44
  } & Omit<ReactFlowProps, 'elements'>;
43
45
 
44
46
  export function DependenciesGraph({
@@ -48,17 +50,24 @@ export function DependenciesGraph({
48
50
  className,
49
51
  onLoad,
50
52
  children,
53
+ loadingGraphMetadata,
51
54
  ...rest
52
55
  }: DependenciesGraphProps) {
53
56
  const nodeTypes: NodeTypes = React.useMemo(() => ({ ComponentNode: ComponentNodeContainer }), []);
54
57
  const graphRef = useRef<ReactFlowInstance>();
55
58
  const elements = calcElements(graph, { rootNode });
59
+ const [nodes, setNodes] = useNodesState(elements.nodes);
56
60
 
57
- const context = useMemo(() => ({ componentWidgets }), [componentWidgets]);
61
+ useEffect(() => {
62
+ setNodes(elements.nodes);
63
+ }, [elements.nodes]);
64
+
65
+ const context = useMemo(() => ({ componentWidgets, loadingGraphMetadata }), [componentWidgets, loadingGraphMetadata]);
58
66
 
59
67
  const handleLoad = useCallback(
60
68
  (instance: ReactFlowInstance) => {
61
- if ((graph?.nodes.length ?? 0) <= 3) {
69
+ graphRef.current = instance;
70
+ if ((elements?.nodes.length ?? 0) <= 3) {
62
71
  instance.fitView({
63
72
  padding: 2,
64
73
  maxZoom: 1,
@@ -78,13 +87,18 @@ export function DependenciesGraph({
78
87
 
79
88
  useEffect(() => {
80
89
  setTimeout(() => {
81
- if (graph.nodes.length <= 3)
90
+ if (!elements?.nodes.length) return;
91
+ if ((elements?.nodes?.length ?? 0) <= 3) {
82
92
  return graphRef.current?.fitView({
83
93
  padding: 2,
94
+ maxZoom: 1,
84
95
  });
85
- return graphRef.current?.fitView();
86
- }, 0);
87
- }, [graph]);
96
+ }
97
+ return graphRef.current?.fitView({
98
+ maxZoom: 1,
99
+ });
100
+ }, 100);
101
+ }, [elements?.nodes.length]);
88
102
 
89
103
  return (
90
104
  <ComponentGraphContext.Provider value={context}>
@@ -101,10 +115,15 @@ export function DependenciesGraph({
101
115
  minZoom={0}
102
116
  {...rest}
103
117
  className={classnames(styles.graph, className)}
104
- defaultNodes={elements.nodes}
105
- defaultEdges={elements.edges}
118
+ nodes={nodes}
119
+ edges={elements.edges}
106
120
  nodeTypes={nodeTypes}
107
121
  onInit={handleLoad}
122
+ fitView={true}
123
+ fitViewOptions={{
124
+ padding: (elements?.nodes.length ?? 0) <= 3 ? 2 : undefined,
125
+ maxZoom: 1,
126
+ }}
108
127
  proOptions={{
109
128
  hideAttribution: true,
110
129
  }}
@@ -4,6 +4,7 @@ import { CheckboxLabel } from '@teambit/evangelist.input.checkbox.label';
4
4
 
5
5
  type GraphFiltersType = {
6
6
  isFiltered: boolean;
7
+ showMetadata?: boolean;
7
8
  onChangeFilter: (isFiltered: boolean) => void;
8
9
  disable?: boolean;
9
10
  } & CardProps;
@@ -28,7 +28,9 @@
28
28
  top: 8px;
29
29
  right: 8px;
30
30
  padding: 8px;
31
-
31
+ display: flex;
32
+ flex-direction: column;
33
+ gap: 8px;
32
34
  font-size: 0.75em;
33
35
  box-shadow: var(--bit-shadow-faint);
34
36
  z-index: 8; // position above the abs positioned graph items
@@ -1,10 +1,9 @@
1
1
  import React, { useContext, useState } from 'react';
2
-
3
- import { H2 } from '@teambit/documenter.ui.heading';
4
2
  import { NotFoundPage } from '@teambit/design.ui.pages.not-found';
5
3
  import { ServerErrorPage } from '@teambit/design.ui.pages.server-error';
6
4
  import { ComponentContext } from '@teambit/component';
7
- import { FullLoader } from '@teambit/ui-foundation.ui.full-loader';
5
+ import { skeleton } from '@teambit/design.skeletons.base-skeleton';
6
+ import classNames from 'classnames';
8
7
 
9
8
  import { useGraphQuery } from '../query';
10
9
  import { DependenciesGraph } from '../dependencies-graph';
@@ -23,31 +22,34 @@ export function GraphPage({ componentWidgets }: GraphPageProps) {
23
22
  const component = useContext(ComponentContext);
24
23
 
25
24
  const [filter, setFilter] = useState<GraphFilter>('runtimeOnly');
25
+
26
26
  const onCheckFilter = (isFiltered: boolean) => {
27
27
  setFilter(isFiltered ? 'runtimeOnly' : undefined);
28
28
  };
29
29
 
30
- const { graph, error, loading } = useGraphQuery([component.id.toString()], filter);
31
- if (error) return error.code === 404 ? <NotFoundPage /> : <ServerErrorPage />;
32
- if (!graph) return <FullLoader />;
30
+ const { graph, error, graphLoading, loading } = useGraphQuery([component.id.toString()], filter);
33
31
 
34
32
  const isFiltered = filter === 'runtimeOnly';
35
33
 
34
+ if (error) return error.code === 404 ? <NotFoundPage /> : <ServerErrorPage />;
35
+
36
36
  return (
37
- <div className={styles.page}>
38
- <H2 size="xs">Component Dependencies</H2>
37
+ <div className={classNames(styles.page)}>
39
38
  <DependenciesGraph
40
39
  componentWidgets={componentWidgets}
41
40
  graph={graph}
42
41
  rootNode={component.id}
43
- className={styles.graph}
42
+ className={classNames(styles.graph, !graph && skeleton)}
43
+ loadingGraphMetadata={graphLoading}
44
44
  >
45
- <GraphFilters
46
- className={styles.filters}
47
- disable={loading}
48
- isFiltered={isFiltered}
49
- onChangeFilter={onCheckFilter}
50
- />
45
+ {graph && (
46
+ <GraphFilters
47
+ className={classNames(styles.filters)}
48
+ disable={loading}
49
+ isFiltered={isFiltered}
50
+ onChangeFilter={onCheckFilter}
51
+ />
52
+ )}
51
53
  </DependenciesGraph>
52
54
  </div>
53
55
  );
@@ -8,12 +8,12 @@ export class GraphSection implements Section {
8
8
  constructor(private componentWidgetSlot: ComponentWidgetSlot) {}
9
9
 
10
10
  route = {
11
- path: '~dependencies',
11
+ path: '~graph',
12
12
  element: <GraphPage componentWidgets={this.componentWidgetSlot} />,
13
13
  };
14
14
  navigationLink = {
15
- href: '~dependencies',
16
- children: 'Dependencies',
15
+ href: '~graph',
16
+ children: 'Graph',
17
17
  };
18
18
  order = 40;
19
19
  }
@@ -1,7 +1,20 @@
1
1
  import { gql } from '@apollo/client';
2
2
  import { EdgeType } from '../../edge-type';
3
3
 
4
- // please update types when updating query, for added safety
4
+ export const GET_GRAPH_IDS = gql`
5
+ query graph($ids: [String], $filter: String) {
6
+ graph(ids: $ids, filter: $filter) {
7
+ nodes {
8
+ id
9
+ }
10
+ edges {
11
+ sourceId
12
+ targetId
13
+ dependencyLifecycleType
14
+ }
15
+ }
16
+ }
17
+ `;
5
18
 
6
19
  export const GET_GRAPH = gql`
7
20
  query graph($ids: [String], $filter: String) {
@@ -46,19 +59,16 @@ export type RawGraph = {
46
59
 
47
60
  export type RawNode = {
48
61
  id: string;
49
- component: {
62
+ component?: {
50
63
  id: {
51
64
  name: string;
52
65
  scope: string;
53
66
  version: string;
54
67
  };
55
-
56
68
  displayName: string;
57
-
58
69
  deprecation: {
59
70
  isDeprecate: boolean;
60
71
  };
61
-
62
72
  env: {
63
73
  id: string;
64
74
  icon: string;
@@ -1,16 +1,18 @@
1
- import { ComponentModel } from '@teambit/component';
1
+ import { ComponentID, ComponentModel } from '@teambit/component';
2
2
  import { RawNode } from './get-graph.query';
3
3
 
4
4
  export class NodeModel {
5
5
  id: string;
6
- component: ComponentModel;
6
+ component?: ComponentModel;
7
+ componentId: ComponentID;
7
8
 
8
9
  static from(rawNode: RawNode) {
9
10
  const node = new NodeModel();
10
11
  node.id = rawNode.id;
11
12
  // @TODO - component model should not expect all fields to have values
12
13
  // @ts-ignore
13
- node.component = ComponentModel.from(rawNode.component);
14
+ node.component = rawNode.component ? ComponentModel.from(rawNode.component) : undefined;
15
+ node.componentId = node.component ? node.component.id : ComponentID.fromString(rawNode.id);
14
16
  return node;
15
17
  }
16
18
  }
@@ -1,7 +1,7 @@
1
- import { useMemo } from 'react';
2
- import { useDataQuery } from '@teambit/ui-foundation.ui.hooks.use-data-query';
1
+ import { useMemo, useEffect, useState } from 'react';
2
+ import { useQuery, useLazyQuery } from '@apollo/client';
3
3
  import { GraphQlError } from '@teambit/graphql';
4
- import { GET_GRAPH, RawGraphQuery } from './get-graph.query';
4
+ import { GET_GRAPH, RawGraphQuery, GET_GRAPH_IDS } from './get-graph.query';
5
5
  import { GraphModel } from './graph-model';
6
6
 
7
7
  type QueryVariables = {
@@ -9,22 +9,64 @@ type QueryVariables = {
9
9
  filter?: string;
10
10
  };
11
11
 
12
- /** provides dependencies graph data from graphQL */
13
12
  export function useGraphQuery(componentId?: string[], filter?: string) {
14
- const { data, error, loading } = useDataQuery<RawGraphQuery, QueryVariables>(GET_GRAPH, {
13
+ // Eagerly fetch GET_GRAPH_IDS
14
+ const {
15
+ data: idsData,
16
+ error: idsError,
17
+ loading: idsLoading,
18
+ } = useQuery<RawGraphQuery, QueryVariables>(GET_GRAPH_IDS, {
15
19
  variables: { ids: componentId, filter },
16
- skip: !componentId,
20
+ skip: !componentId || !filter,
17
21
  });
18
22
 
19
- const rawGraph = data?.graph;
20
- const clientError = !rawGraph && !loading ? new GraphQlError(404) : undefined;
21
- const serverError = error ? new GraphQlError(500, error.message) : undefined;
23
+ // Lazily fetch GET_GRAPH
24
+ const [getGraph, { data: graphData, error: graphError, loading: graphLoading }] = useLazyQuery<
25
+ RawGraphQuery,
26
+ QueryVariables
27
+ >(GET_GRAPH);
28
+
29
+ const [fetchError, setFetchError] = useState<GraphQlError | undefined>(undefined);
30
+
31
+ const [shouldRefetchGraph, setShouldRefetchGraph] = useState(false);
32
+
33
+ useEffect(() => {
34
+ if (idsData?.graph.nodes.length || !filter) {
35
+ setShouldRefetchGraph(true);
36
+ }
37
+ }, [idsData?.graph.nodes.length, filter]);
38
+
39
+ useEffect(() => {
40
+ if (shouldRefetchGraph) {
41
+ setShouldRefetchGraph(false);
42
+ void getGraph({ variables: { ids: componentId, filter } }).catch((error) => {
43
+ setFetchError(new GraphQlError(500, error.message));
44
+ });
45
+ }
46
+ }, [componentId, filter, getGraph, shouldRefetchGraph]);
47
+
48
+ const rawGraph = idsLoading
49
+ ? undefined
50
+ : (idsData?.graph &&
51
+ graphData?.graph &&
52
+ idsData?.graph.nodes.length === graphData?.graph.nodes.length &&
53
+ graphData?.graph) ||
54
+ idsData?.graph ||
55
+ graphData?.graph;
56
+
57
+ const clientError = !rawGraph && !idsLoading && !graphLoading ? new GraphQlError(404) : undefined;
58
+ const serverError =
59
+ graphError?.message || idsError?.message
60
+ ? new GraphQlError(500, graphError?.message || idsError?.message)
61
+ : fetchError;
22
62
 
23
63
  return useMemo(() => {
24
64
  return {
25
65
  graph: rawGraph ? GraphModel.from(rawGraph) : undefined,
26
66
  error: serverError || clientError,
27
- loading,
67
+ loading: idsLoading || graphLoading,
68
+ idsLoading,
69
+ graphLoading,
28
70
  };
29
- }, [rawGraph, error]);
71
+ }, [rawGraph, serverError, clientError, idsLoading, graphLoading]);
30
72
  }