@redocly/theme 0.57.0-next.0 → 0.57.0-next.2

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 (108) hide show
  1. package/lib/components/Catalog/CatalogCardView/CatalogCard.js +1 -0
  2. package/lib/components/Catalog/CatalogEntity/CatalogEntity.js +36 -25
  3. package/lib/components/Catalog/CatalogEntity/CatalogEntityGraph/CatalogEntityRelationsEdge.d.ts +6 -0
  4. package/lib/components/Catalog/CatalogEntity/CatalogEntityGraph/CatalogEntityRelationsEdge.js +38 -0
  5. package/lib/components/Catalog/CatalogEntity/CatalogEntityGraph/CatalogEntityRelationsGraph.d.ts +6 -0
  6. package/lib/components/Catalog/CatalogEntity/CatalogEntityGraph/CatalogEntityRelationsGraph.js +83 -0
  7. package/lib/components/Catalog/CatalogEntity/CatalogEntityGraph/CatalogEntityRelationsGraph.lazy.d.ts +2 -0
  8. package/lib/components/Catalog/CatalogEntity/CatalogEntityGraph/CatalogEntityRelationsGraph.lazy.js +29 -0
  9. package/lib/components/Catalog/CatalogEntity/CatalogEntityGraph/CatalogEntityRelationsLinkedNode.d.ts +8 -0
  10. package/lib/components/Catalog/CatalogEntity/CatalogEntityGraph/CatalogEntityRelationsLinkedNode.js +33 -0
  11. package/lib/components/Catalog/CatalogEntity/CatalogEntityGraph/CatalogEntityRelationsNode.d.ts +16 -0
  12. package/lib/components/Catalog/CatalogEntity/CatalogEntityGraph/CatalogEntityRelationsNode.js +24 -0
  13. package/lib/components/Catalog/CatalogEntity/CatalogEntityGraph/CatalogEntityRelationsRootNode.d.ts +7 -0
  14. package/lib/components/Catalog/CatalogEntity/CatalogEntityGraph/CatalogEntityRelationsRootNode.js +30 -0
  15. package/lib/components/Catalog/CatalogEntity/CatalogEntityMethodAndPath.js +5 -2
  16. package/lib/components/Catalog/CatalogEntity/CatalogEntityRelations/CatalogEntityRelations.d.ts +1 -0
  17. package/lib/components/Catalog/CatalogEntity/CatalogEntityRelations/CatalogEntityRelations.js +7 -3
  18. package/lib/components/Catalog/CatalogEntity/CatalogEntityRelations/CatalogEntityRelationsTable.js +3 -8
  19. package/lib/components/Catalog/CatalogEntity/CatalogEntityRelations/CatalogEntityRelationsTableContent.d.ts +22 -0
  20. package/lib/components/Catalog/CatalogEntity/CatalogEntityRelations/CatalogEntityRelationsTableContent.js +18 -0
  21. package/lib/components/Catalog/CatalogEntity/CatalogEntityRelations/CatalogEntityTeamRelations.js +2 -2
  22. package/lib/components/Catalog/CatalogEntityIcon.d.ts +2 -1
  23. package/lib/components/Catalog/CatalogEntityIcon.js +4 -6
  24. package/lib/components/Catalog/CatalogTableView/CatalogTableViewRow.js +1 -1
  25. package/lib/components/Catalog/variables.js +42 -0
  26. package/lib/components/CatalogClassic/CatalogClassicVirtualizedGroups.js +13 -8
  27. package/lib/core/constants/catalog.d.ts +10 -0
  28. package/lib/core/constants/catalog.js +14 -1
  29. package/lib/core/hooks/__mocks__/search/use-recent-searches.d.ts +2 -2
  30. package/lib/core/hooks/__mocks__/search/use-recent-searches.js +2 -1
  31. package/lib/core/hooks/__mocks__/search/use-search-filter.d.ts +2 -2
  32. package/lib/core/hooks/__mocks__/search/use-search-filter.js +2 -1
  33. package/lib/core/hooks/__mocks__/search/use-suggested-pages.d.ts +2 -2
  34. package/lib/core/hooks/__mocks__/search/use-suggested-pages.js +2 -1
  35. package/lib/core/hooks/__mocks__/use-controlled-state.d.ts +1 -1
  36. package/lib/core/hooks/__mocks__/use-controlled-state.js +2 -1
  37. package/lib/core/hooks/__mocks__/use-input-key-commands.d.ts +3 -3
  38. package/lib/core/hooks/__mocks__/use-input-key-commands.js +3 -2
  39. package/lib/core/hooks/__mocks__/use-mobile-menu.d.ts +1 -1
  40. package/lib/core/hooks/__mocks__/use-mobile-menu.js +2 -1
  41. package/lib/core/hooks/__mocks__/use-theme-config.d.ts +2 -2
  42. package/lib/core/hooks/__mocks__/use-theme-config.js +2 -1
  43. package/lib/core/hooks/__mocks__/use-theme-hooks.d.ts +47 -47
  44. package/lib/core/hooks/__mocks__/use-theme-hooks.js +38 -37
  45. package/lib/core/hooks/__mocks__/use-time-ago.d.ts +2 -2
  46. package/lib/core/hooks/__mocks__/use-time-ago.js +2 -1
  47. package/lib/core/hooks/catalog/useGraph.d.ts +15 -0
  48. package/lib/core/hooks/catalog/useGraph.js +165 -0
  49. package/lib/core/hooks/code-walkthrough/__mocks__/MockIntersectionObserver.js +4 -3
  50. package/lib/core/hooks/index.d.ts +1 -0
  51. package/lib/core/hooks/index.js +1 -0
  52. package/lib/core/hooks/menu/__mocks__/use-mobile-menu-items.d.ts +1 -1
  53. package/lib/core/hooks/menu/__mocks__/use-mobile-menu-items.js +2 -1
  54. package/lib/core/hooks/use-page-actions.js +5 -1
  55. package/lib/core/openapi/index.d.ts +1 -0
  56. package/lib/core/openapi/index.js +3 -1
  57. package/lib/core/styles/index.d.ts +1 -0
  58. package/lib/core/styles/index.js +3 -0
  59. package/lib/core/styles/xyflow.d.ts +1 -0
  60. package/lib/core/styles/xyflow.js +623 -0
  61. package/lib/core/utils/dynamic.d.ts +9 -0
  62. package/lib/core/utils/dynamic.js +59 -0
  63. package/lib/core/utils/index.d.ts +1 -0
  64. package/lib/core/utils/index.js +1 -0
  65. package/lib/icons/GenericIcon/GenericIcon.d.ts +2 -2
  66. package/lib/icons/GenericIcon/GenericIcon.js +8 -3
  67. package/lib/icons/__tests__/IconTestUtils.d.ts +0 -1
  68. package/lib/icons/__tests__/IconTestUtils.js +8 -7
  69. package/package.json +11 -14
  70. package/src/components/Catalog/CatalogCardView/CatalogCard.tsx +1 -0
  71. package/src/components/Catalog/CatalogEntity/CatalogEntity.tsx +60 -42
  72. package/src/components/Catalog/CatalogEntity/CatalogEntityGraph/CatalogEntityRelationsEdge.tsx +63 -0
  73. package/src/components/Catalog/CatalogEntity/CatalogEntityGraph/CatalogEntityRelationsGraph.lazy.tsx +7 -0
  74. package/src/components/Catalog/CatalogEntity/CatalogEntityGraph/CatalogEntityRelationsGraph.tsx +91 -0
  75. package/src/components/Catalog/CatalogEntity/CatalogEntityGraph/CatalogEntityRelationsLinkedNode.tsx +48 -0
  76. package/src/components/Catalog/CatalogEntity/CatalogEntityGraph/CatalogEntityRelationsNode.tsx +45 -0
  77. package/src/components/Catalog/CatalogEntity/CatalogEntityGraph/CatalogEntityRelationsRootNode.tsx +49 -0
  78. package/src/components/Catalog/CatalogEntity/CatalogEntityMethodAndPath.tsx +6 -2
  79. package/src/components/Catalog/CatalogEntity/CatalogEntityRelations/CatalogEntityRelations.tsx +8 -2
  80. package/src/components/Catalog/CatalogEntity/CatalogEntityRelations/CatalogEntityRelationsTable.tsx +24 -43
  81. package/src/components/Catalog/CatalogEntity/CatalogEntityRelations/CatalogEntityRelationsTableContent.tsx +76 -0
  82. package/src/components/Catalog/CatalogEntity/CatalogEntityRelations/CatalogEntityTeamRelations.tsx +2 -2
  83. package/src/components/Catalog/CatalogEntityIcon.tsx +7 -5
  84. package/src/components/Catalog/CatalogTableView/CatalogTableViewRow.tsx +1 -1
  85. package/src/components/Catalog/variables.ts +42 -0
  86. package/src/components/CatalogClassic/CatalogClassicVirtualizedGroups.tsx +29 -18
  87. package/src/core/constants/catalog.ts +13 -0
  88. package/src/core/hooks/__mocks__/search/use-recent-searches.ts +3 -1
  89. package/src/core/hooks/__mocks__/search/use-search-filter.ts +3 -1
  90. package/src/core/hooks/__mocks__/search/use-suggested-pages.ts +3 -1
  91. package/src/core/hooks/__mocks__/use-controlled-state.ts +3 -1
  92. package/src/core/hooks/__mocks__/use-input-key-commands.ts +4 -2
  93. package/src/core/hooks/__mocks__/use-mobile-menu.ts +3 -1
  94. package/src/core/hooks/__mocks__/use-theme-config.ts +3 -1
  95. package/src/core/hooks/__mocks__/use-theme-hooks.ts +39 -37
  96. package/src/core/hooks/__mocks__/use-time-ago.ts +3 -1
  97. package/src/core/hooks/catalog/useGraph.ts +236 -0
  98. package/src/core/hooks/code-walkthrough/__mocks__/MockIntersectionObserver.ts +5 -3
  99. package/src/core/hooks/index.ts +1 -0
  100. package/src/core/hooks/menu/__mocks__/use-mobile-menu-items.ts +3 -1
  101. package/src/core/hooks/use-page-actions.ts +5 -1
  102. package/src/core/openapi/index.ts +1 -0
  103. package/src/core/styles/index.ts +1 -0
  104. package/src/core/styles/xyflow.ts +620 -0
  105. package/src/core/utils/dynamic.tsx +85 -0
  106. package/src/core/utils/index.ts +1 -0
  107. package/src/icons/GenericIcon/GenericIcon.tsx +13 -4
  108. package/src/icons/__tests__/IconTestUtils.tsx +5 -4
@@ -24,7 +24,7 @@ export function CatalogEntityMethodAndPath({ entity }: CatalogEntityMethodAndPat
24
24
  leftContent={
25
25
  <Label>
26
26
  <MethodTag color={method.toLowerCase()}>{method}</MethodTag>
27
- {path}
27
+ <PathLabel>{path}</PathLabel>
28
28
  </Label>
29
29
  }
30
30
  withSeparator={false}
@@ -36,7 +36,10 @@ export function CatalogEntityMethodAndPath({ entity }: CatalogEntityMethodAndPat
36
36
  const MethodTag = styled(HttpTag)`
37
37
  width: auto;
38
38
  justify-content: start;
39
- margin-right: var(--spacing-xxs);
39
+ `;
40
+
41
+ const PathLabel = styled.label`
42
+ margin-left: var(--spacing-xxs);
40
43
  `;
41
44
 
42
45
  const LinksWrapper = styled.div`
@@ -51,6 +54,7 @@ const LinksWrapper = styled.div`
51
54
 
52
55
  const Label = styled.div`
53
56
  display: flex;
57
+ width: 100%;
54
58
  `;
55
59
 
56
60
  const Heading = styled.h2`
@@ -11,6 +11,7 @@ export type CatalogEntityRelationsProps = {
11
11
  entitiesCatalogConfig: EntitiesCatalogConfig;
12
12
  catalogConfig: CatalogEntityConfig;
13
13
  initialRelations: BffCatalogRelatedEntityList;
14
+ initialFilter?: string;
14
15
  searchQuery: string;
15
16
  setSearchQuery: (query: string) => void;
16
17
  };
@@ -29,10 +30,15 @@ export function CatalogEntityRelations({
29
30
  }: CatalogEntityRelationsProps): JSX.Element | null {
30
31
  const { useCatalogSort, useFetchCatalogEntitiesRelations } = useThemeHooks();
31
32
  const { sortOption, setSortOption, handleSortClick, isColumnSorted } = useCatalogSort();
32
- const [filter, setFilter] = useState<string>(ENTITY_DEFAULT_FILTERS[entity.type] ?? '');
33
+ const [filter, setFilter] = useState<string>();
33
34
 
34
35
  const { items: relations, query } = useFetchCatalogEntitiesRelations(
35
- { entityKey: entity.key, search: searchQuery, sort: sortOption ?? undefined, filter },
36
+ {
37
+ entityKey: entity.key,
38
+ search: searchQuery,
39
+ sort: sortOption ?? undefined,
40
+ filter: filter ?? ENTITY_DEFAULT_FILTERS[entity.type],
41
+ },
36
42
  initialRelations,
37
43
  );
38
44
 
@@ -2,16 +2,11 @@ import React, { JSX } from 'react';
2
2
  import styled from 'styled-components';
3
3
  import { CatalogEntityConfig, EntitiesCatalogConfig } from '@redocly/config';
4
4
 
5
- import { ArrowDownIcon } from '@redocly/theme/icons/ArrowDownIcon/ArrowDownIcon';
6
5
  import { BffCatalogEntity, BffCatalogRelatedEntity, SortOption } from '@redocly/theme/core/types';
7
- import { LoadMore } from '@redocly/theme/components/LoadMore/LoadMore';
8
- import {
9
- CatalogColumn,
10
- CatalogTableView,
11
- } from '@redocly/theme/components/Catalog/CatalogTableView/CatalogTableView';
6
+ import { CatalogColumn } from '@redocly/theme/components/Catalog/CatalogTableView/CatalogTableView';
12
7
  import { CatalogActionsRow } from '@redocly/theme/components/Catalog/CatalogActionsRow';
13
- import { HighlightContext } from '@redocly/theme/components/Catalog/CatalogHighlight';
14
- import { CatalogEntitiesEmptyState } from '@redocly/theme/components/Catalog/CatalogEntitiesEmptyState';
8
+
9
+ import { CatalogEntityRelationsTableContent } from './CatalogEntityRelationsTableContent';
15
10
 
16
11
  export type CatalogEntityRelationsTableProps = {
17
12
  entity: BffCatalogEntity;
@@ -53,41 +48,27 @@ export function CatalogEntityRelationsTable({
53
48
  return (
54
49
  <div data-component-name="Catalog/CatalogEntity/CatalogEntityRelations/CatalogEntityRelationsTable">
55
50
  {heading && <Heading>{heading}</Heading>}
56
- {(searchQuery || relations.length > 0) && (
57
- <CatalogActionsRow
58
- searchQuery={searchQuery}
59
- setSearchQuery={setSearchQuery}
60
- sortOption={sortOption}
61
- setSortOption={setSortOption}
62
- style={{ marginBottom: '12px' }}
63
- />
64
- )}
65
- <HighlightContext.Provider value={[searchQuery]}>
66
- {relations.length > 0 ? (
67
- <CatalogTableView
68
- entities={relations}
69
- entitiesCatalogConfig={entitiesCatalogConfig}
70
- catalogConfig={catalogConfig}
71
- columns={columns}
72
- setSortOption={setSortOption}
73
- currentSortOption={sortOption}
74
- handleSortClick={handleSortClick}
75
- isColumnSorted={isColumnSorted}
76
- style={{ marginTop: 0 }}
77
- />
78
- ) : (
79
- <CatalogEntitiesEmptyState listType={listType} />
80
- )}
81
- </HighlightContext.Provider>
82
- {shouldShowLoadMore && (
83
- <LoadMore
84
- icon={<ArrowDownIcon size="var(--catalog-load-more-icon-size)" />}
85
- onClick={query.fetchNextPage}
86
- disabled={query.isFetchingNextPage}
87
- blinking={query.isFetchingNextPage}
88
- label={query.isFetchingNextPage ? 'Loading...' : 'Load More'}
89
- />
90
- )}
51
+ <CatalogActionsRow
52
+ searchQuery={searchQuery}
53
+ setSearchQuery={setSearchQuery}
54
+ sortOption={sortOption}
55
+ setSortOption={setSortOption}
56
+ style={{ marginBottom: '12px' }}
57
+ />
58
+ <CatalogEntityRelationsTableContent
59
+ entitiesCatalogConfig={entitiesCatalogConfig}
60
+ catalogConfig={catalogConfig}
61
+ relations={relations}
62
+ query={query}
63
+ searchQuery={searchQuery}
64
+ columns={columns}
65
+ setSortOption={setSortOption}
66
+ sortOption={sortOption}
67
+ handleSortClick={handleSortClick}
68
+ isColumnSorted={isColumnSorted}
69
+ shouldShowLoadMore={shouldShowLoadMore}
70
+ listType={listType}
71
+ />
91
72
  </div>
92
73
  );
93
74
  }
@@ -0,0 +1,76 @@
1
+ import React, { JSX } from 'react';
2
+ import { CatalogEntityConfig, EntitiesCatalogConfig } from '@redocly/config';
3
+
4
+ import { ArrowDownIcon } from '@redocly/theme/icons/ArrowDownIcon/ArrowDownIcon';
5
+ import { BffCatalogRelatedEntity, SortOption } from '@redocly/theme/core/types';
6
+ import { LoadMore } from '@redocly/theme/components/LoadMore/LoadMore';
7
+ import {
8
+ CatalogColumn,
9
+ CatalogTableView,
10
+ } from '@redocly/theme/components/Catalog/CatalogTableView/CatalogTableView';
11
+ import { HighlightContext } from '@redocly/theme/components/Catalog/CatalogHighlight';
12
+ import { CatalogEntitiesEmptyState } from '@redocly/theme/components/Catalog/CatalogEntitiesEmptyState';
13
+
14
+ export type CatalogEntityRelationsTableContentProps = {
15
+ entitiesCatalogConfig: EntitiesCatalogConfig;
16
+ catalogConfig: CatalogEntityConfig;
17
+ relations: BffCatalogRelatedEntity[];
18
+ query: {
19
+ fetchNextPage: () => void;
20
+ isFetchingNextPage: boolean;
21
+ };
22
+ searchQuery: string;
23
+ columns: CatalogColumn<BffCatalogRelatedEntity>[];
24
+ sortOption: SortOption | null;
25
+ setSortOption: (sortOption: SortOption | null) => void;
26
+ handleSortClick: (sortKey: string, direction: 'asc' | 'desc') => void;
27
+ isColumnSorted: (sortKey: string, direction: 'asc' | 'desc') => boolean;
28
+ shouldShowLoadMore: boolean;
29
+ listType?: 'default' | 'team';
30
+ };
31
+
32
+ export function CatalogEntityRelationsTableContent({
33
+ entitiesCatalogConfig,
34
+ catalogConfig,
35
+ relations,
36
+ query,
37
+ searchQuery,
38
+ columns,
39
+ setSortOption,
40
+ sortOption,
41
+ handleSortClick,
42
+ isColumnSorted,
43
+ shouldShowLoadMore,
44
+ listType,
45
+ }: CatalogEntityRelationsTableContentProps): JSX.Element {
46
+ return (
47
+ <div data-component-name="Catalog/CatalogEntity/CatalogEntityRelations/CatalogEntityRelationsTableContent">
48
+ <HighlightContext.Provider value={[searchQuery]}>
49
+ {relations.length > 0 ? (
50
+ <CatalogTableView
51
+ entities={relations}
52
+ entitiesCatalogConfig={entitiesCatalogConfig}
53
+ catalogConfig={catalogConfig}
54
+ columns={columns}
55
+ setSortOption={setSortOption}
56
+ currentSortOption={sortOption}
57
+ handleSortClick={handleSortClick}
58
+ isColumnSorted={isColumnSorted}
59
+ style={{ marginTop: 0 }}
60
+ />
61
+ ) : (
62
+ <CatalogEntitiesEmptyState listType={listType} />
63
+ )}
64
+ </HighlightContext.Provider>
65
+ {shouldShowLoadMore && (
66
+ <LoadMore
67
+ icon={<ArrowDownIcon size="var(--catalog-load-more-icon-size)" />}
68
+ onClick={query.fetchNextPage}
69
+ disabled={query.isFetchingNextPage}
70
+ blinking={query.isFetchingNextPage}
71
+ label={query.isFetchingNextPage ? 'Loading...' : 'Load More'}
72
+ />
73
+ )}
74
+ </div>
75
+ );
76
+ }
@@ -88,7 +88,7 @@ export function CatalogEntityTeamRelations({
88
88
  <Tabs forceReady={relations.length > 0} size={TabsSize.MEDIUM}>
89
89
  <TabItem label="Members" icon={<PeopleIcon />} onClick={() => setFilter('type:user')}>
90
90
  <CatalogEntityRelationsTable
91
- key={`members-${relations.length}-${relations.map((r) => r.id).join(',')}`}
91
+ key="members-table"
92
92
  entity={entity}
93
93
  entitiesCatalogConfig={entitiesCatalogConfig}
94
94
  catalogConfig={catalogConfig}
@@ -111,7 +111,7 @@ export function CatalogEntityTeamRelations({
111
111
  onClick={() => setFilter('-type:user')}
112
112
  >
113
113
  <CatalogEntityDefaultRelations
114
- key={`related-${relations.length}-${relations.map((r) => r.id).join(',')}`}
114
+ key="related-entities-table"
115
115
  entity={entity}
116
116
  relations={relations}
117
117
  query={query}
@@ -11,14 +11,15 @@ import { MoleculesIcon } from '@redocly/theme/icons/MoleculesIcon/MoleculesIcon'
11
11
  export type CatalogEntityIconProps = {
12
12
  entityType: string;
13
13
  defaultColor?: boolean;
14
+ forceColor?: string;
14
15
  };
15
16
 
16
17
  const getIconColor = (entityType: EntityType) => `var(--catalog-entity-icon-color-${entityType})`;
17
18
 
18
- const getEntityIcon = ({ entityType, defaultColor }: CatalogEntityIconProps) => {
19
- const iconColor = defaultColor
20
- ? `var(--catalog-entity-icon-color)`
21
- : getIconColor(entityType as EntityType);
19
+ const getEntityIcon = ({ entityType, defaultColor, forceColor }: CatalogEntityIconProps) => {
20
+ const iconColor =
21
+ forceColor ??
22
+ (defaultColor ? `var(--catalog-entity-icon-color)` : getIconColor(entityType as EntityType));
22
23
 
23
24
  const entityIconMap: Record<EntityType, JSX.Element> = {
24
25
  service: <CodeIcon color={iconColor} />,
@@ -36,8 +37,9 @@ const getEntityIcon = ({ entityType, defaultColor }: CatalogEntityIconProps) =>
36
37
  export function CatalogEntityIcon({
37
38
  entityType,
38
39
  defaultColor = false,
40
+ forceColor,
39
41
  }: CatalogEntityIconProps): JSX.Element {
40
- const icon = getEntityIcon({ entityType, defaultColor });
42
+ const icon = getEntityIcon({ entityType, defaultColor, forceColor });
41
43
 
42
44
  if (!icon) {
43
45
  throw new Error(`Unhandled entity type: ${entityType}`);
@@ -101,7 +101,7 @@ export const CatalogTableViewRow = <T extends BaseEntity>({
101
101
  key={entity.id}
102
102
  $columnsWidths={columns.map((column) => column.width || '1fr')}
103
103
  $columnsMinWidths={columns.map((column) => column.minWidth || 'auto')}
104
- to={getEntityDetailsLink()}
104
+ to={getEntityDetailsLink() + '?search='}
105
105
  style={{ color: 'var(--catalog-page-wrapper-text-color)' }}
106
106
  data-component-name="Catalog/CatalogTableView/CatalogTableViewRow"
107
107
  >
@@ -382,4 +382,46 @@ export const catalog = css`
382
382
 
383
383
  --catalog-avatar-bg-color: #ededf2;
384
384
  // @tokens End
385
+
386
+ /**
387
+ * @tokens Catalog entity relations node
388
+ */
389
+ --catalog-entity-relations-node-padding-vertical: 10px;
390
+ --catalog-entity-relations-node-padding-horizontal: 14px;
391
+ --catalog-entity-relations-node-padding: var(--catalog-entity-relations-node-padding-vertical) var(--catalog-entity-relations-node-padding-horizontal);
392
+ --catalog-entity-relations-node-gap: 8px;
393
+ --catalog-entity-relations-node-border-radius: 10px;
394
+
395
+ --catalog-entity-relations-node-bg-color: var(--layer-color);
396
+ --catalog-entity-relations-node-text-color: var(--catalog-card-text-color);
397
+
398
+ --catalog-entity-relations-node-border-color: var(--border-color-secondary);
399
+ --catalog-entity-relations-node-border-width: var(--border-width);
400
+ --catalog-entity-relations-node-border-style: var(--border-style);
401
+
402
+ --catalog-entity-relations-node-font-weight: var(--font-weight-regular);
403
+ --catalog-entity-relations-node-font-weight-root: 600;
404
+
405
+ --catalog-entity-relations-node-root-bg-color: var(--color-blue-6);
406
+ --catalog-entity-relations-node-root-text-color: #ffffff;
407
+ --catalog-entity-relations-node-root-icon-color: #ffffff;
408
+ // @tokens End
409
+
410
+ /**
411
+ * @tokens Catalog entity relations edge
412
+ */
413
+ --catalog-entity-relations-edge-label-bg-color: var(--layer-color);
414
+ --catalog-entity-relations-edge-label-text-color: var(--catalog-card-text-color);
415
+ --catalog-entity-relations-edge-label-border-color: var(--border-color-secondary);
416
+ --catalog-entity-relations-edge-label-border-width: var(--border-width);
417
+ --catalog-entity-relations-edge-label-border-style: var(--border-style);
418
+ --catalog-entity-relations-edge-label-border-radius: 10px;
419
+
420
+ --catalog-entity-relations-edge-label-padding-vertical: 2px;
421
+ --catalog-entity-relations-edge-label-padding-horizontal: 8px;
422
+ --catalog-entity-relations-edge-label-padding: var(--catalog-entity-relations-edge-label-padding-vertical) var(--catalog-entity-relations-edge-label-padding-horizontal);
423
+
424
+ --catalog-entity-relations-edge-label-font-size: 12px;
425
+ --catalog-entity-relations-edge-label-line-height: 1.2;
426
+ // @tokens End
385
427
  `;
@@ -106,6 +106,7 @@ export function CatalogClassicVirtualizedGroups({
106
106
  return ESTIMATED_CARD_HEIGHT;
107
107
  },
108
108
  overscan: 5,
109
+ enabled: shouldVirtualize,
109
110
  });
110
111
 
111
112
  useEffect(() => {
@@ -117,27 +118,29 @@ export function CatalogClassicVirtualizedGroups({
117
118
  // eslint-disable-next-line react-hooks/exhaustive-deps
118
119
  }, [filters, filterTerm, size.width, shouldVirtualize]);
119
120
 
121
+ const renderRow = (rowData: VirtualRowData) => {
122
+ if (rowData.type === 'header') {
123
+ return (
124
+ <SSRHeaderRow key={rowData.key}>
125
+ <CatalogSeparatorLabel>{rowData.groupTitle}</CatalogSeparatorLabel>
126
+ <CounterTag borderless>{rowData.groupCount}</CounterTag>
127
+ </SSRHeaderRow>
128
+ );
129
+ }
130
+
131
+ return (
132
+ <SSRGridRow key={rowData.key}>
133
+ {rowData.items.map((item) => (
134
+ <CatalogClassicCard key={item.link} item={item} />
135
+ ))}
136
+ </SSRGridRow>
137
+ );
138
+ };
139
+
120
140
  if (!isClient) {
121
141
  return (
122
142
  <div ref={parentRef} data-component-name="CatalogClassic/CatalogClassicVirtualizedGroups">
123
- {flatRows.slice(0, 15).map((rowData) => {
124
- if (rowData.type === 'header') {
125
- return (
126
- <SSRHeaderRow key={rowData.key}>
127
- <CatalogSeparatorLabel>{rowData.groupTitle}</CatalogSeparatorLabel>
128
- <CounterTag borderless>{rowData.groupCount}</CounterTag>
129
- </SSRHeaderRow>
130
- );
131
- }
132
-
133
- return (
134
- <SSRGridRow key={rowData.key}>
135
- {rowData.items.map((item) => (
136
- <CatalogClassicCard key={item.link} item={item} />
137
- ))}
138
- </SSRGridRow>
139
- );
140
- })}
143
+ {flatRows.slice(0, 15).map((rowData) => renderRow(rowData))}
141
144
  <LoadingWrapper>
142
145
  <SpinnerLoader color="var(--catalog-classic-description-text-color)" size="20px" />
143
146
  </LoadingWrapper>
@@ -145,6 +148,14 @@ export function CatalogClassicVirtualizedGroups({
145
148
  );
146
149
  }
147
150
 
151
+ if (!shouldVirtualize) {
152
+ return (
153
+ <div ref={parentRef} data-component-name="CatalogClassic/CatalogClassicVirtualizedGroups">
154
+ {flatRows.map((rowData) => renderRow(rowData))}
155
+ </div>
156
+ );
157
+ }
158
+
148
159
  return (
149
160
  <div ref={parentRef} data-component-name="CatalogClassic/CatalogClassicVirtualizedGroups">
150
161
  <div
@@ -57,3 +57,16 @@ export const reverseRelationMap: Record<EntityRelationType, EntityRelationType>
57
57
  triggers: 'triggeredBy',
58
58
  triggeredBy: 'triggers',
59
59
  } as const;
60
+
61
+ export enum GraphHandleType {
62
+ Target = 'target',
63
+ Source = 'source',
64
+ }
65
+
66
+ export enum GraphCustomNodeType {
67
+ CatalogEntity = 'catalogEntity',
68
+ }
69
+
70
+ export enum GraphCustomEdgeType {
71
+ CatalogEdge = 'catalogEdge',
72
+ }
@@ -1,4 +1,6 @@
1
- export const useRecentSearches = jest.fn(() => {
1
+ import { vi } from 'vitest';
2
+
3
+ export const useRecentSearches = vi.fn(() => {
2
4
  const items = ['test'];
3
5
  return {
4
6
  items,
@@ -1,4 +1,6 @@
1
- export const useSearchFilter = jest.fn(() => {
1
+ import { vi } from 'vitest';
2
+
3
+ export const useSearchFilter = vi.fn(() => {
2
4
  return {
3
5
  isFilterOpen: false,
4
6
  onFacetReset: () => {},
@@ -1,4 +1,6 @@
1
- export const useSuggestedPages = jest.fn(() => {
1
+ import { vi } from 'vitest';
2
+
3
+ export const useSuggestedPages = vi.fn(() => {
2
4
  return [
3
5
  {
4
6
  link: '/',
@@ -1 +1,3 @@
1
- export const useControlledState = () => [false, jest.fn()];
1
+ import { vi } from 'vitest';
2
+
3
+ export const useControlledState = () => [false, vi.fn()];
@@ -1,3 +1,5 @@
1
- export const useInputKeyCommands = jest.fn(() => ({
2
- onKeyDown: jest.fn(),
1
+ import { vi } from 'vitest';
2
+
3
+ export const useInputKeyCommands = vi.fn(() => ({
4
+ onKeyDown: vi.fn(),
3
5
  }));
@@ -1 +1,3 @@
1
- export const useMobileMenu = () => [false, jest.fn];
1
+ import { vi } from 'vitest';
2
+
3
+ export const useMobileMenu = () => [false, vi.fn()];
@@ -1,4 +1,6 @@
1
- export const useThemeConfig = jest.fn(() => ({
1
+ import { vi } from 'vitest';
2
+
3
+ export const useThemeConfig = vi.fn(() => ({
2
4
  userMenu: {
3
5
  items: [],
4
6
  },
@@ -1,6 +1,8 @@
1
- export const useThemeHooks = jest.fn(() => ({
2
- useTranslate: jest.fn(() => ({
3
- translate: jest.fn((key: string, defaultValue: string) =>
1
+ import { vi } from 'vitest';
2
+
3
+ export const useThemeHooks = vi.fn(() => ({
4
+ useTranslate: vi.fn(() => ({
5
+ translate: vi.fn((key: string, defaultValue: string) =>
4
6
  defaultValue
5
7
  ? typeof defaultValue !== 'string'
6
8
  ? (defaultValue as any).defaultValue
@@ -8,21 +10,21 @@ export const useThemeHooks = jest.fn(() => ({
8
10
  : key,
9
11
  ),
10
12
  })),
11
- useTelemetry: jest.fn(() => ({
12
- send: jest.fn(),
13
+ useTelemetry: vi.fn(() => ({
14
+ send: vi.fn(),
13
15
  })),
14
- useBreadcrumbs: jest.fn().mockReturnValue([]),
15
- usePageSharedData: jest.fn().mockReturnValue({}),
16
- useCatalogClassic: jest.fn(() => ({
16
+ useBreadcrumbs: vi.fn().mockReturnValue([]),
17
+ usePageSharedData: vi.fn().mockReturnValue({}),
18
+ useCatalogClassic: vi.fn(() => ({
17
19
  groups: [],
18
20
  filters: [],
19
21
  filterTerm: '',
20
- setFilterTerm: jest.fn(),
22
+ setFilterTerm: vi.fn(),
21
23
  })),
22
- useL10n: jest.fn(() => ({
23
- changeLanguage: jest.fn(),
24
+ useL10n: vi.fn(() => ({
25
+ changeLanguage: vi.fn(),
24
26
  })),
25
- useL10nConfig: jest.fn(() => ({
27
+ useL10nConfig: vi.fn(() => ({
26
28
  currentLocale: 'en',
27
29
  defaultLocale: 'en',
28
30
  locales: [
@@ -31,42 +33,42 @@ export const useThemeHooks = jest.fn(() => ({
31
33
  { code: 'uk', name: 'Ukraine' },
32
34
  ],
33
35
  })),
34
- usePreloadHistory: jest.fn(() => ({
35
- push: jest.fn(),
36
+ usePreloadHistory: vi.fn(() => ({
37
+ push: vi.fn(),
36
38
  })),
37
- useCurrentProduct: jest.fn(),
38
- useProducts: jest.fn(() => []),
39
- useSearch: jest.fn(() => ({
40
- query: jest.fn().mockReturnValue(''),
41
- setQuery: jest.fn(),
39
+ useCurrentProduct: vi.fn(),
40
+ useProducts: vi.fn(() => []),
41
+ useSearch: vi.fn(() => ({
42
+ query: vi.fn().mockReturnValue(''),
43
+ setQuery: vi.fn(),
42
44
  items: [],
43
45
  isLoading: false,
44
46
  })),
45
- useAiSearch: jest.fn(() => ({
46
- askQuestion: jest.fn(),
47
+ useAiSearch: vi.fn(() => ({
48
+ askQuestion: vi.fn(),
47
49
  references: [],
48
50
  })),
49
- useFacetQuery: jest.fn(() => ({
51
+ useFacetQuery: vi.fn(() => ({
50
52
  searchFacet: null,
51
- setSearchFacet: jest.fn(),
52
- setSearchFacetQuery: jest.fn(),
53
+ setSearchFacet: vi.fn(),
54
+ setSearchFacetQuery: vi.fn(),
53
55
  })),
54
- useMarkdownText: jest.fn(() => {
56
+ useMarkdownText: vi.fn(() => {
55
57
  return null;
56
58
  }),
57
- useUserMenu: jest.fn(() => ({
59
+ useUserMenu: vi.fn(() => ({
58
60
  userData: {
59
61
  isAuthenticated: true,
60
62
  name: 'test-name',
61
63
  email: 'test-email@test.xyz',
62
64
  picture: 'picture',
63
65
  },
64
- handleLogout: jest.fn(),
66
+ handleLogout: vi.fn(),
65
67
  loginUrl: 'https://login.redoc.ly',
66
68
  hasDeveloperOnboarding: true,
67
69
  })),
68
- usePageVersions: jest.fn(),
69
- useSidebarItems: jest.fn().mockReturnValue({
70
+ usePageVersions: vi.fn(),
71
+ useSidebarItems: vi.fn().mockReturnValue({
70
72
  currentItems: [
71
73
  {
72
74
  label: 'Item',
@@ -77,14 +79,14 @@ export const useThemeHooks = jest.fn(() => ({
77
79
  label: 'Item',
78
80
  },
79
81
  ],
80
- popDrilldownState: jest.fn(),
81
- pushDrilldownState: jest.fn(),
82
+ popDrilldownState: vi.fn(),
83
+ pushDrilldownState: vi.fn(),
82
84
  }),
83
- useSidebarSiblingsData: jest.fn(),
84
- useSubmitFeedback: jest.fn(() => ({
85
- submitFeedback: jest.fn(),
85
+ useSidebarSiblingsData: vi.fn(),
86
+ useSubmitFeedback: vi.fn(() => ({
87
+ submitFeedback: vi.fn(),
86
88
  })),
87
- useLoadAndNavigate: jest.fn(),
88
- usePageProps: jest.fn().mockReturnValue({}),
89
- usePageData: jest.fn().mockReturnValue(null),
89
+ useLoadAndNavigate: vi.fn(),
90
+ usePageProps: vi.fn().mockReturnValue({}),
91
+ usePageData: vi.fn().mockReturnValue(null),
90
92
  }));
@@ -1,3 +1,5 @@
1
- export const useTimeAgo = jest.fn(() => ({
1
+ import { vi } from 'vitest';
2
+
3
+ export const useTimeAgo = vi.fn(() => ({
2
4
  format: () => '5 days ago',
3
5
  }));