@eventcatalog/core 3.29.2 → 3.31.1

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 (113) hide show
  1. package/dist/analytics/analytics.cjs +1 -1
  2. package/dist/analytics/analytics.js +2 -2
  3. package/dist/analytics/log-build.cjs +1 -1
  4. package/dist/analytics/log-build.js +3 -3
  5. package/dist/{chunk-36IA4UE4.js → chunk-7IGMIOQF.js} +1 -1
  6. package/dist/{chunk-EGQGCB2B.js → chunk-HVOLSUC2.js} +1 -1
  7. package/dist/{chunk-DB4IQ3GB.js → chunk-LWVHWR77.js} +1 -1
  8. package/dist/{chunk-VEUNSJ6Z.js → chunk-QIJOBQZ7.js} +1 -1
  9. package/dist/{chunk-MEJOYC5Z.js → chunk-UY5QDWK7.js} +1 -1
  10. package/dist/constants.cjs +1 -1
  11. package/dist/constants.js +1 -1
  12. package/dist/eventcatalog.cjs +1 -1
  13. package/dist/eventcatalog.js +5 -5
  14. package/dist/generate.cjs +1 -1
  15. package/dist/generate.js +3 -3
  16. package/dist/utils/cli-logger.cjs +1 -1
  17. package/dist/utils/cli-logger.js +2 -2
  18. package/eventcatalog/astro.config.mjs +11 -7
  19. package/eventcatalog/public/logo.png +0 -0
  20. package/eventcatalog/src/components/CopyAsMarkdown.tsx +29 -24
  21. package/eventcatalog/src/components/EnvironmentDropdown.tsx +33 -21
  22. package/eventcatalog/src/components/FieldsExplorer/FieldFilters.tsx +3 -53
  23. package/eventcatalog/src/components/FieldsExplorer/FieldsExplorer.tsx +144 -91
  24. package/eventcatalog/src/components/FieldsExplorer/FieldsTable.tsx +112 -109
  25. package/eventcatalog/src/components/Header.astro +9 -19
  26. package/eventcatalog/src/components/MDX/Accordion/Accordion.tsx +12 -14
  27. package/eventcatalog/src/components/MDX/Accordion/AccordionGroup.astro +11 -3
  28. package/eventcatalog/src/components/MDX/Design/Design.astro +1 -1
  29. package/eventcatalog/src/components/MDX/ResourceRef/ResourceRef.astro +15 -5
  30. package/eventcatalog/src/components/MDX/Tiles/Tile.astro +11 -8
  31. package/eventcatalog/src/components/SchemaExplorer/ApiContentViewer.tsx +164 -53
  32. package/eventcatalog/src/components/SchemaExplorer/DiffViewer.tsx +1 -1
  33. package/eventcatalog/src/components/SchemaExplorer/ExamplesViewer.tsx +4 -4
  34. package/eventcatalog/src/components/SchemaExplorer/Pagination.tsx +12 -10
  35. package/eventcatalog/src/components/SchemaExplorer/SchemaContentViewer.tsx +48 -77
  36. package/eventcatalog/src/components/SchemaExplorer/SchemaDetailsPanel.tsx +238 -169
  37. package/eventcatalog/src/components/SchemaExplorer/SchemaExplorer.tsx +189 -230
  38. package/eventcatalog/src/components/SchemaExplorer/SchemaListItem.tsx +39 -36
  39. package/eventcatalog/src/components/Search/Search.astro +1 -1
  40. package/eventcatalog/src/components/Seo.astro +1 -1
  41. package/eventcatalog/src/components/Settings/AssistantSettingsForm.tsx +218 -0
  42. package/eventcatalog/src/components/Settings/BillingSettingsForm.tsx +265 -0
  43. package/eventcatalog/src/components/Settings/GeneralSettingsForm.tsx +371 -0
  44. package/eventcatalog/src/components/Settings/LlmAccessSettingsForm.tsx +183 -0
  45. package/eventcatalog/src/components/Settings/LogoUpload.tsx +137 -0
  46. package/eventcatalog/src/components/Settings/McpSettingsForm.tsx +91 -0
  47. package/eventcatalog/src/components/Settings/ReadOnlyBanner.tsx +18 -0
  48. package/eventcatalog/src/components/Settings/Row.tsx +59 -0
  49. package/eventcatalog/src/components/Settings/SettingsShared.tsx +176 -0
  50. package/eventcatalog/src/components/SideNav/NestedSideBar/SearchBar.tsx +3 -3
  51. package/eventcatalog/src/components/SideNav/NestedSideBar/index.tsx +233 -261
  52. package/eventcatalog/src/components/Tables/Discover/DiscoverTable.tsx +116 -68
  53. package/eventcatalog/src/components/Tables/Discover/FilterComponents.tsx +2 -2
  54. package/eventcatalog/src/components/Tables/Discover/columns.tsx +130 -197
  55. package/eventcatalog/src/components/Tables/Table.tsx +21 -18
  56. package/eventcatalog/src/components/Tables/columns/TeamsTableColumns.tsx +79 -131
  57. package/eventcatalog/src/components/Tables/columns/UserTableColumns.tsx +104 -175
  58. package/eventcatalog/src/content.config.ts +1 -1
  59. package/eventcatalog/src/enterprise/auth/error.astro +1 -1
  60. package/eventcatalog/src/enterprise/auth/login.astro +1 -1
  61. package/eventcatalog/src/enterprise/auth/middleware/middleware-auth.ts +11 -7
  62. package/eventcatalog/src/enterprise/custom-documentation/components/CustomDocsNav/index.tsx +97 -95
  63. package/eventcatalog/src/enterprise/custom-documentation/pages/docs/custom/index.astro +232 -181
  64. package/eventcatalog/src/enterprise/feature.ts +2 -1
  65. package/eventcatalog/src/enterprise/fields/pages/fields.astro +10 -8
  66. package/eventcatalog/src/enterprise/integrations/eventcatalog-features.ts +0 -8
  67. package/eventcatalog/src/layouts/DirectoryLayout.astro +17 -88
  68. package/eventcatalog/src/layouts/SettingsLayout.astro +116 -0
  69. package/eventcatalog/src/layouts/VerticalSideBarLayout.astro +562 -141
  70. package/eventcatalog/src/layouts/VisualiserLayout.astro +7 -2
  71. package/eventcatalog/src/pages/_index.astro +253 -256
  72. package/eventcatalog/src/pages/api/settings/ai.ts +57 -0
  73. package/eventcatalog/src/pages/api/settings/general.ts +71 -0
  74. package/eventcatalog/src/pages/api/settings/logo.ts +113 -0
  75. package/eventcatalog/src/pages/architecture/[type]/[id]/[version]/index.astro +3 -3
  76. package/eventcatalog/src/pages/diagrams/[id]/[version]/index.astro +223 -73
  77. package/eventcatalog/src/pages/discover/[type]/index.astro +22 -141
  78. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/[docType]/[docId]/[docVersion]/index.astro +130 -30
  79. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/[docType]/[docId]/index.astro +147 -53
  80. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/asyncapi/[filename].astro +6 -2
  81. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/examples/[...filename].astro +2 -2
  82. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/graphql/[filename].astro +22 -19
  83. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/index.astro +71 -61
  84. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/spec/[filename].astro +5 -1
  85. package/eventcatalog/src/pages/docs/[type]/[id]/language/[dictionaryId]/index.astro +3 -3
  86. package/eventcatalog/src/pages/docs/[type]/[id]/language/index.astro +6 -32
  87. package/eventcatalog/src/pages/docs/llm/llms.txt.ts +5 -1
  88. package/eventcatalog/src/pages/docs/teams/[id]/index.astro +11 -4
  89. package/eventcatalog/src/pages/docs/users/[id]/index.astro +12 -5
  90. package/eventcatalog/src/pages/schemas/explorer/index.astro +10 -8
  91. package/eventcatalog/src/pages/settings/assistant.astro +37 -0
  92. package/eventcatalog/src/pages/settings/billing.astro +17 -0
  93. package/eventcatalog/src/pages/settings/general.astro +32 -0
  94. package/eventcatalog/src/pages/settings/index.astro +21 -0
  95. package/eventcatalog/src/pages/settings/llm-access.astro +34 -0
  96. package/eventcatalog/src/pages/settings/mcp.astro +14 -0
  97. package/eventcatalog/src/pages/studio.astro +1 -1
  98. package/eventcatalog/src/pages/visualiser/[type]/[id]/[version]/entity-map/index.astro +2 -7
  99. package/eventcatalog/src/pages/visualiser/[type]/[id]/[version]/index.astro +2 -2
  100. package/eventcatalog/src/pages/visualiser/domains/[id]/[version]/entity-map/index.astro +2 -7
  101. package/eventcatalog/src/styles/theme.css +95 -30
  102. package/eventcatalog/src/styles/themes/forest.css +17 -9
  103. package/eventcatalog/src/styles/themes/ocean.css +10 -2
  104. package/eventcatalog/src/styles/themes/sapphire.css +10 -2
  105. package/eventcatalog/src/styles/themes/sunset.css +25 -17
  106. package/eventcatalog/src/types/react-syntax-highlighter.d.ts +13 -0
  107. package/eventcatalog/src/utils/eventcatalog-config/config-schema.ts +49 -0
  108. package/eventcatalog/src/utils/eventcatalog-config/config-writer.ts +149 -0
  109. package/eventcatalog/src/utils/url-builder.ts +4 -2
  110. package/package.json +7 -5
  111. package/eventcatalog/public/logo.svg +0 -14
  112. package/eventcatalog/src/enterprise/plans/index.astro +0 -319
  113. package/eventcatalog/src/pages/docs/llm/llms-services.txt.ts +0 -81
@@ -1,5 +1,5 @@
1
- import { useState, useEffect, useCallback, useRef } from 'react';
2
- import { ChevronLeft, ChevronRight, Lock, X } from 'lucide-react';
1
+ import { useState, useEffect, useCallback, useRef, useMemo } from 'react';
2
+ import { ChevronLeft, ChevronRight, Lock, Search, X, AlertTriangle } from 'lucide-react';
3
3
  import FieldFilters from './FieldFilters';
4
4
  import FieldsTable from './FieldsTable';
5
5
  import type { FieldResult } from './FieldsTable';
@@ -398,104 +398,157 @@ export default function FieldsExplorer({ isScaleEnabled = false }: FieldsExplore
398
398
  }
399
399
  : null;
400
400
 
401
+ const conflictingFieldCount = useMemo(() => {
402
+ return new Set(fields.filter((field) => field.conflicts && field.conflicts.length > 1).map((field) => field.path)).size;
403
+ }, [fields]);
404
+
401
405
  return (
402
- <div className="flex h-full">
403
- {/* Filter Sidebar */}
404
- <div className="w-[320px] flex-shrink-0 flex flex-col bg-[rgb(var(--ec-page-bg))] bg-gradient-to-bl from-[rgb(var(--ec-page-bg))] via-[rgb(var(--ec-page-bg))] to-[rgb(var(--ec-accent)/0.08)] border-r border-[rgb(var(--ec-page-border))]">
405
- <div className="flex-1 overflow-y-auto px-4 pt-4 pb-4">
406
- <FieldFilters
407
- searchQuery={searchQuery}
408
- onSearchChange={setSearchQuery}
409
- selectedFormats={selectedFormats}
410
- onFormatsChange={setSelectedFormats}
411
- selectedMessageTypes={selectedMessageTypes}
412
- onMessageTypesChange={setSelectedMessageTypes}
413
- sharedOnly={sharedOnly}
414
- onSharedOnlyChange={setSharedOnly}
415
- conflictingOnly={conflictingOnly}
416
- onConflictingOnlyChange={setConflictingOnly}
417
- facets={filterFacets}
418
- isScaleEnabled={isScaleEnabled}
419
- />
420
- </div>
421
- </div>
406
+ <div className="flex h-full min-h-0 flex-col overflow-hidden">
407
+ <div className="flex flex-1 min-h-0 gap-0 overflow-hidden">
408
+ {/* Filter Sidebar */}
409
+ <div
410
+ className="fixed top-0 z-20 flex h-screen w-[320px] flex-shrink-0 flex-col overflow-hidden border-r border-[rgb(var(--ec-page-border))] bg-linear-to-bl from-[rgb(var(--ec-page-bg))] via-[rgb(var(--ec-page-bg))] to-[rgb(var(--ec-accent)/0.08)]"
411
+ style={{ left: 'var(--ec-vertical-nav-width)', width: 'var(--ec-fields-sidebar-width, 320px)' }}
412
+ >
413
+ <div className="flex h-[60px] flex-shrink-0 items-center border-b border-[rgb(var(--ec-page-border))] px-4">
414
+ <div className="relative min-w-0 flex-1">
415
+ <div className="pointer-events-none absolute inset-y-0 left-0 flex items-center pl-3">
416
+ <Search className="h-4 w-4 text-[rgb(var(--ec-icon-color))]" />
417
+ </div>
418
+ <input
419
+ type="text"
420
+ value={searchQuery}
421
+ onChange={(e) => setSearchQuery(e.target.value)}
422
+ placeholder="Search fields..."
423
+ className="block w-full rounded-md border-0 bg-[rgb(var(--ec-header-bg))] py-1.5 pl-10 pr-8 text-[rgb(var(--ec-header-text))] shadow-xs ring-1 ring-inset ring-[rgb(var(--ec-dropdown-border))] placeholder:text-[rgb(var(--ec-icon-color))] font-light sm:text-sm sm:leading-6 focus:outline-hidden focus:ring-1 focus:ring-inset focus:ring-[rgb(var(--ec-accent))]"
424
+ />
425
+ {searchQuery && (
426
+ <button
427
+ onClick={() => setSearchQuery('')}
428
+ className="absolute right-2 top-1/2 -translate-y-1/2 p-0.5 text-[rgb(var(--ec-icon-color))] hover:text-[rgb(var(--ec-page-text))]"
429
+ >
430
+ <X className="h-3.5 w-3.5" />
431
+ </button>
432
+ )}
433
+ </div>
434
+ </div>
422
435
 
423
- {/* Main Content */}
424
- <div className="flex-1 min-w-0 flex flex-col overflow-hidden">
425
- {/* Header */}
426
- <div className="flex items-center justify-between px-6 py-4">
427
- <h2 className="text-lg font-semibold text-[rgb(var(--ec-page-text))]">
428
- Fields <span className="text-sm text-[rgb(var(--ec-page-text-muted))] font-normal ml-1">({total})</span>
429
- </h2>
436
+ <div className="flex-1 overflow-y-auto px-4 pt-4 pb-4">
437
+ <FieldFilters
438
+ searchQuery={searchQuery}
439
+ onSearchChange={setSearchQuery}
440
+ selectedFormats={selectedFormats}
441
+ onFormatsChange={setSelectedFormats}
442
+ selectedMessageTypes={selectedMessageTypes}
443
+ onMessageTypesChange={setSelectedMessageTypes}
444
+ sharedOnly={sharedOnly}
445
+ onSharedOnlyChange={setSharedOnly}
446
+ conflictingOnly={conflictingOnly}
447
+ onConflictingOnlyChange={setConflictingOnly}
448
+ facets={filterFacets}
449
+ isScaleEnabled={isScaleEnabled}
450
+ />
451
+ </div>
430
452
  </div>
431
453
 
432
- {/* Error state */}
433
- {error && (
434
- <div className="mx-6 mb-4 px-4 py-3 rounded-lg border border-red-300 bg-red-50 text-red-700 text-sm">{error}</div>
435
- )}
454
+ {/* Main Content */}
455
+ <div
456
+ className="flex-1 min-h-0 min-w-0 flex flex-col overflow-hidden bg-[rgb(var(--ec-page-bg))]"
457
+ style={{ marginLeft: 'var(--ec-fields-sidebar-width, 320px)' }}
458
+ >
459
+ {/* Header */}
460
+ <div className="flex items-center justify-between px-6 py-4">
461
+ <h2 className="text-lg font-semibold text-[rgb(var(--ec-page-text))]">
462
+ Fields <span className="text-sm text-[rgb(var(--ec-page-text-muted))] font-normal ml-1">({total})</span>
463
+ </h2>
464
+ </div>
436
465
 
437
- {/* Table */}
438
- <FieldsTable fields={fields} onSelectField={handleSelectField} isLoading={isLoading} isScaleEnabled={isScaleEnabled} />
439
-
440
- {/* Pagination */}
441
- <div className="flex-shrink-0 flex items-center justify-between px-6 py-3 border-t border-[rgb(var(--ec-page-border))]">
442
- <span className="text-xs text-[rgb(var(--ec-page-text-muted))]">
443
- {total > 0 && (
444
- <>
445
- <span className="font-medium text-[rgb(var(--ec-page-text))]">{fields.length}</span> of{' '}
446
- <span className="font-medium text-[rgb(var(--ec-page-text))]">{total}</span> fields
447
- </>
448
- )}
449
- </span>
450
- <div className="flex items-center gap-1.5">
451
- <button
452
- className="p-1.5 text-[rgb(var(--ec-icon-color))] hover:text-[rgb(var(--ec-page-text))] disabled:opacity-30 disabled:cursor-not-allowed transition-colors"
453
- onClick={handlePrevPage}
454
- disabled={currentPageIndex === 0}
455
- title="Previous page"
456
- >
457
- <ChevronLeft className="w-4 h-4" />
458
- </button>
459
- <span className="text-xs tabular-nums text-[rgb(var(--ec-page-text-muted))] min-w-[40px] text-center">
460
- <span className="font-medium text-[rgb(var(--ec-page-text))]">{currentPageIndex + 1}</span>
466
+ {/* Error state */}
467
+ {error && (
468
+ <div className="mx-6 mb-4 px-4 py-3 rounded-lg border border-red-300 bg-red-50 text-red-700 text-sm">{error}</div>
469
+ )}
470
+
471
+ {conflictingFieldCount > 0 && (
472
+ <div className="mx-6 mb-4 rounded-lg border border-amber-500/25 bg-amber-500/8 px-4 py-3 text-sm text-[rgb(var(--ec-page-text))]">
473
+ <div className="flex items-start gap-2.5">
474
+ <AlertTriangle className="mt-0.5 h-4 w-4 flex-shrink-0 text-amber-500" />
475
+ <div>
476
+ <p className="font-medium text-[rgb(var(--ec-page-text))]">
477
+ {conflictingFieldCount} conflicting {conflictingFieldCount === 1 ? 'property' : 'properties'} found
478
+ </p>
479
+ <p className="mt-1 text-[0.8rem] text-[rgb(var(--ec-page-text-muted))]">
480
+ These properties are used with more than one type across the current results.
481
+ </p>
482
+ </div>
483
+ </div>
484
+ </div>
485
+ )}
486
+
487
+ {/* Table */}
488
+ <FieldsTable fields={fields} onSelectField={handleSelectField} isLoading={isLoading} isScaleEnabled={isScaleEnabled} />
489
+
490
+ {/* Pagination */}
491
+ <div className="flex-shrink-0 flex items-center justify-between px-6 py-3 border-t border-[rgb(var(--ec-page-border))]">
492
+ <span className="text-xs text-[rgb(var(--ec-page-text-muted))]">
493
+ {total > 0 && (
494
+ <>
495
+ <span className="font-medium text-[rgb(var(--ec-page-text))]">{fields.length}</span> of{' '}
496
+ <span className="font-medium text-[rgb(var(--ec-page-text))]">{total}</span> fields
497
+ </>
498
+ )}
461
499
  </span>
462
- <button
463
- className="p-1.5 text-[rgb(var(--ec-icon-color))] hover:text-[rgb(var(--ec-page-text))] disabled:opacity-30 disabled:cursor-not-allowed transition-colors"
464
- onClick={handleNextPage}
465
- disabled={!cursor}
466
- title="Next page"
467
- >
468
- <ChevronRight className="w-4 h-4" />
469
- </button>
500
+ <div className="flex items-center gap-1.5">
501
+ <button
502
+ className="p-1.5 text-[rgb(var(--ec-icon-color))] hover:text-[rgb(var(--ec-page-text))] disabled:opacity-30 disabled:cursor-not-allowed transition-colors"
503
+ onClick={handlePrevPage}
504
+ disabled={currentPageIndex === 0}
505
+ title="Previous page"
506
+ >
507
+ <ChevronLeft className="w-4 h-4" />
508
+ </button>
509
+ <span className="text-xs tabular-nums text-[rgb(var(--ec-page-text-muted))] min-w-[60px] text-center">
510
+ <span className="font-medium text-[rgb(var(--ec-page-text))]">{currentPageIndex + 1}</span>
511
+ {' / '}
512
+ <span>{Math.max(cursorHistory.length + (cursor ? 2 : 1), currentPageIndex + 1)}</span>
513
+ </span>
514
+ <button
515
+ className="p-1.5 text-[rgb(var(--ec-icon-color))] hover:text-[rgb(var(--ec-page-text))] disabled:opacity-30 disabled:cursor-not-allowed transition-colors"
516
+ onClick={handleNextPage}
517
+ disabled={!cursor}
518
+ title="Next page"
519
+ >
520
+ <ChevronRight className="w-4 h-4" />
521
+ </button>
522
+ </div>
470
523
  </div>
471
524
  </div>
472
- </div>
473
525
 
474
- {/* Field Detail Modal with Node Graph */}
475
- {selectedField && !isScaleEnabled && (
476
- <FieldLineageUpgradeModal fieldPath={selectedField.path} onClose={() => setSelectedField(null)} />
477
- )}
478
- {selectedField && isScaleEnabled && (
479
- <FieldNodeGraph
480
- fieldPath={selectedField.path}
481
- fieldType={selectedField.type}
482
- fieldDescription={selectedField.description}
483
- fieldRequired={selectedField.required}
484
- fieldConflicts={selectedField.conflicts}
485
- occurrences={selectedField.occurrences.map((f) => ({
486
- messageId: f.messageId,
487
- messageVersion: f.messageVersion,
488
- messageType: f.messageType,
489
- messageName: f.messageName,
490
- messageSummary: f.messageSummary,
491
- messageOwners: f.messageOwners,
492
- fieldType: f.type,
493
- producers: f.producers,
494
- consumers: f.consumers,
495
- }))}
496
- onClose={() => setSelectedField(null)}
497
- />
498
- )}
526
+ {/* Field Detail Modal with Node Graph */}
527
+ {selectedField && !isScaleEnabled && (
528
+ <FieldLineageUpgradeModal fieldPath={selectedField.path} onClose={() => setSelectedField(null)} />
529
+ )}
530
+ {selectedField && isScaleEnabled && (
531
+ <FieldNodeGraph
532
+ fieldPath={selectedField.path}
533
+ fieldType={selectedField.type}
534
+ fieldDescription={selectedField.description}
535
+ fieldRequired={selectedField.required}
536
+ fieldConflicts={selectedField.conflicts}
537
+ occurrences={selectedField.occurrences.map((f) => ({
538
+ messageId: f.messageId,
539
+ messageVersion: f.messageVersion,
540
+ messageType: f.messageType,
541
+ messageName: f.messageName,
542
+ messageSummary: f.messageSummary,
543
+ messageOwners: f.messageOwners,
544
+ fieldType: f.type,
545
+ producers: f.producers,
546
+ consumers: f.consumers,
547
+ }))}
548
+ onClose={() => setSelectedField(null)}
549
+ />
550
+ )}
551
+ </div>
499
552
  </div>
500
553
  );
501
554
  }
@@ -56,13 +56,12 @@ function MessageBadge({ id, name, version, type }: { id: string; name?: string;
56
56
  <a
57
57
  href={messageUrl}
58
58
  onClick={(e) => e.stopPropagation()}
59
- className="group/msg inline-flex items-center gap-1.5 text-xs hover:text-[rgb(var(--ec-accent))] transition-colors"
59
+ className="group/msg inline-flex items-center gap-1.5 text-[0.8rem] text-[rgb(var(--ec-page-text-muted))] hover:text-[rgb(var(--ec-accent))] transition-colors"
60
60
  >
61
61
  <Icon className={`h-3.5 w-3.5 ${colorClasses[color] || 'text-gray-500'} flex-shrink-0`} />
62
- <span className="truncate max-w-[160px] text-[rgb(var(--ec-page-text))] group-hover/msg:text-[rgb(var(--ec-accent))]">
62
+ <span className="truncate max-w-[160px] text-[rgb(var(--ec-page-text-muted))] group-hover/msg:text-[rgb(var(--ec-accent))]">
63
63
  {name || id}
64
64
  </span>
65
- <span className="text-[rgb(var(--ec-icon-color))]">v{version}</span>
66
65
  </a>
67
66
  );
68
67
  }
@@ -92,7 +91,7 @@ function FieldPathCell({ path }: { path: string }) {
92
91
  export default function FieldsTable({ fields, onSelectField, isLoading, isScaleEnabled = false }: FieldsTableProps) {
93
92
  if (isLoading) {
94
93
  return (
95
- <div className="flex-1 flex items-center justify-center">
94
+ <div className="flex-1 flex items-center justify-center px-6 pb-5">
96
95
  <div className="flex flex-col items-center gap-3">
97
96
  <div className="w-8 h-8 border-2 border-[rgb(var(--ec-accent))] border-t-transparent rounded-full animate-spin" />
98
97
  <span className="text-sm text-[rgb(var(--ec-page-text-muted))]">Loading fields...</span>
@@ -103,7 +102,7 @@ export default function FieldsTable({ fields, onSelectField, isLoading, isScaleE
103
102
 
104
103
  if (fields.length === 0) {
105
104
  return (
106
- <div className="flex-1 flex items-center justify-center">
105
+ <div className="flex-1 flex items-center justify-center px-6 pb-5">
107
106
  <div className="flex flex-col items-center justify-center text-[rgb(var(--ec-page-text-muted))]">
108
107
  <SearchX className="w-10 h-10 text-[rgb(var(--ec-icon-color))] mb-3 opacity-50" />
109
108
  <p className="text-sm font-medium text-[rgb(var(--ec-page-text-muted))]">No schema fields found</p>
@@ -117,122 +116,126 @@ export default function FieldsTable({ fields, onSelectField, isLoading, isScaleE
117
116
  }
118
117
 
119
118
  return (
120
- <div className="flex-1 overflow-auto px-6">
121
- <table className="min-w-full divide-y divide-[rgb(var(--ec-page-border))]">
122
- <thead className="sticky top-0 z-10 bg-[rgb(var(--ec-page-bg))]">
123
- <tr>
124
- <th className="px-4 py-2.5 text-left text-[11px] font-medium text-[rgb(var(--ec-page-text-muted))] uppercase tracking-wider">
125
- Field Path
126
- </th>
127
- <th className="px-4 py-2.5 text-left text-[11px] font-medium text-[rgb(var(--ec-page-text-muted))] uppercase tracking-wider">
128
- Type
129
- </th>
130
- <th className="px-4 py-2.5 text-left text-[11px] font-medium text-[rgb(var(--ec-page-text-muted))] uppercase tracking-wider">
131
- Message
132
- </th>
133
- <th className="px-4 py-2.5 text-left text-[11px] font-medium text-[rgb(var(--ec-page-text-muted))] uppercase tracking-wider">
134
- Format
135
- </th>
136
- <th className="px-4 py-2.5 text-left text-[11px] font-medium text-[rgb(var(--ec-page-text-muted))] uppercase tracking-wider">
137
- Required
138
- </th>
139
- {isScaleEnabled && (
119
+ <div className="min-h-0 flex-1 overflow-auto px-6 pb-5">
120
+ <div className="overflow-hidden rounded-xl border border-[rgb(var(--ec-page-border)/0.72)] dark:border-white/10 bg-[rgb(var(--ec-dropdown-bg)/0.66)]">
121
+ <table className="min-w-full divide-y divide-[rgb(var(--ec-page-border)/0.62)] dark:divide-white/10">
122
+ <thead className="sticky top-0 z-10 bg-[rgb(var(--ec-content-hover)/0.45)]">
123
+ <tr>
140
124
  <th className="px-4 py-2.5 text-left text-[11px] font-medium text-[rgb(var(--ec-page-text-muted))] uppercase tracking-wider">
141
- Consistency
125
+ Property
142
126
  </th>
143
- )}
144
- {isScaleEnabled && (
145
127
  <th className="px-4 py-2.5 text-left text-[11px] font-medium text-[rgb(var(--ec-page-text-muted))] uppercase tracking-wider">
146
- Used In
128
+ Type
147
129
  </th>
148
- )}
149
- <th className="px-4 py-2.5 text-left text-[11px] font-medium text-[rgb(var(--ec-page-text-muted))] uppercase tracking-wider">
150
- Owners
151
- </th>
152
- </tr>
153
- </thead>
154
- <tbody className="divide-y divide-[rgb(var(--ec-page-border)/0.5)]">
155
- {fields.map((field, index) => {
156
- const rowKey = `${field.path}-${field.messageId}-${field.messageVersion}-${index}`;
157
- const owners = field.messageOwners || [];
130
+ <th className="px-4 py-2.5 text-left text-[11px] font-medium text-[rgb(var(--ec-page-text-muted))] uppercase tracking-wider">
131
+ Message
132
+ </th>
133
+ <th className="px-4 py-2.5 text-left text-[11px] font-medium text-[rgb(var(--ec-page-text-muted))] uppercase tracking-wider">
134
+ Format
135
+ </th>
136
+ <th className="px-4 py-2.5 text-left text-[11px] font-medium text-[rgb(var(--ec-page-text-muted))] uppercase tracking-wider">
137
+ Required
138
+ </th>
139
+ {isScaleEnabled && (
140
+ <th className="px-4 py-2.5 text-left text-[11px] font-medium text-[rgb(var(--ec-page-text-muted))] uppercase tracking-wider">
141
+ Consistency
142
+ </th>
143
+ )}
144
+ {isScaleEnabled && (
145
+ <th className="px-4 py-2.5 text-left text-[11px] font-medium text-[rgb(var(--ec-page-text-muted))] uppercase tracking-wider">
146
+ Used In
147
+ </th>
148
+ )}
149
+ <th className="px-4 py-2.5 text-left text-[11px] font-medium text-[rgb(var(--ec-page-text-muted))] uppercase tracking-wider">
150
+ Owners
151
+ </th>
152
+ </tr>
153
+ </thead>
154
+ <tbody className="divide-y divide-[rgb(var(--ec-page-border)/0.5)] dark:divide-white/8">
155
+ {fields.map((field, index) => {
156
+ const rowKey = `${field.path}-${field.messageId}-${field.messageVersion}-${index}`;
157
+ const owners = field.messageOwners || [];
158
158
 
159
- return (
160
- <tr
161
- key={rowKey}
162
- className="group cursor-pointer transition-colors hover:bg-[rgb(var(--ec-content-hover))]"
163
- onClick={() => onSelectField(field.path)}
164
- >
165
- <td className="px-4 py-3 text-sm max-w-[300px]">
166
- <div className="overflow-x-auto">
167
- <FieldPathCell path={field.path} />
168
- </div>
169
- </td>
170
- <td className="px-4 py-3 text-sm font-mono text-[rgb(var(--ec-page-text-muted))]">{field.type}</td>
171
- <td className="px-4 py-3 text-sm">
172
- <MessageBadge
173
- id={field.messageId}
174
- name={field.messageName}
175
- version={field.messageVersion}
176
- type={field.messageType}
177
- />
178
- </td>
179
- <td className="px-4 py-3 text-sm text-[rgb(var(--ec-page-text-muted))]">{field.schemaFormat}</td>
180
- <td className="px-4 py-3 text-sm">
181
- {field.required && (
182
- <span className="inline-flex items-center px-1.5 py-0.5 rounded text-[10px] font-semibold bg-red-500/10 text-red-500 border border-red-500/20">
183
- Required
184
- </span>
185
- )}
186
- </td>
187
- {isScaleEnabled && (
188
- <td className="px-4 py-3 text-sm">
189
- {field.conflicts && field.conflicts.length > 1 ? (
190
- <div
191
- className="flex items-center gap-1.5"
192
- title={field.conflicts.map((c) => `${c.type} (${c.count})`).join(', ')}
193
- >
194
- <AlertTriangle className="w-3.5 h-3.5 text-amber-500 flex-shrink-0" />
195
- <span className="inline-flex items-center px-1.5 py-0.5 rounded text-[10px] font-semibold bg-amber-500/10 text-amber-600 border border-amber-500/20">
196
- {field.conflicts.length} types
197
- </span>
198
- </div>
159
+ return (
160
+ <tr
161
+ key={rowKey}
162
+ className="group cursor-pointer bg-transparent transition-colors hover:bg-[rgb(var(--ec-content-hover)/0.38)]"
163
+ onClick={() => onSelectField(field.path)}
164
+ >
165
+ <td className="px-4 py-3 text-sm text-[rgb(var(--ec-page-text))] max-w-[300px]">
166
+ <div className="overflow-x-auto">
167
+ <FieldPathCell path={field.path} />
168
+ </div>
169
+ </td>
170
+ <td className="px-4 py-3 text-sm font-mono text-[rgb(var(--ec-page-text-muted))]">{field.type}</td>
171
+ <td className="px-4 py-3 text-sm text-[rgb(var(--ec-page-text))]">
172
+ <MessageBadge
173
+ id={field.messageId}
174
+ name={field.messageName}
175
+ version={field.messageVersion}
176
+ type={field.messageType}
177
+ />
178
+ </td>
179
+ <td className="px-4 py-3 text-sm text-[rgb(var(--ec-page-text-muted))]">{field.schemaFormat}</td>
180
+ <td className="px-4 py-3 text-sm text-[rgb(var(--ec-page-text-muted))]">
181
+ {field.required ? (
182
+ <Check className="h-4 w-4 text-green-500" />
199
183
  ) : (
200
- <span className="text-[10px] text-green-500 font-medium">Consistent</span>
184
+ <span className="text-[0.8rem] text-[rgb(var(--ec-page-text-muted))]">-</span>
201
185
  )}
202
186
  </td>
203
- )}
204
- {isScaleEnabled && (
205
- <td className="px-4 py-3 text-sm">
206
- <span className="inline-flex items-center px-2 py-0.5 rounded-full text-[11px] font-medium bg-[rgb(var(--ec-accent)/0.1)] text-[rgb(var(--ec-accent))]">
207
- {field.usedInCount || 1} {(field.usedInCount || 1) === 1 ? 'schema' : 'schemas'}
208
- </span>
209
- </td>
210
- )}
211
- <td className="px-4 py-3 text-sm">
212
- {owners.length > 0 ? (
213
- <div className="flex items-center gap-1 flex-wrap">
214
- {owners.slice(0, 2).map((owner) => (
215
- <span
216
- key={owner}
217
- className="inline-flex items-center px-1.5 py-0.5 rounded text-[10px] font-medium bg-[rgb(var(--ec-accent)/0.1)] text-[rgb(var(--ec-accent))] truncate max-w-[100px]"
218
- title={owner}
187
+ {isScaleEnabled && (
188
+ <td className="px-4 py-3 text-sm text-[rgb(var(--ec-page-text-muted))]">
189
+ {field.conflicts && field.conflicts.length > 1 ? (
190
+ <div
191
+ className="flex items-center gap-1.5"
192
+ title={field.conflicts.map((c) => `${c.type} (${c.count})`).join(', ')}
219
193
  >
220
- {owner}
194
+ <AlertTriangle className="w-3.5 h-3.5 text-amber-500 flex-shrink-0" />
195
+ <span className="inline-flex items-center px-1.5 py-0.5 rounded text-[10px] font-semibold bg-amber-500/10 text-amber-600 border border-amber-500/20">
196
+ {field.conflicts.length} types
197
+ </span>
198
+ </div>
199
+ ) : (
200
+ <span className="inline-flex items-center" title="All usages of this field match the same type">
201
+ <Check className="h-4 w-4 text-green-500" />
221
202
  </span>
222
- ))}
223
- {owners.length > 2 && (
224
- <span className="text-[10px] text-[rgb(var(--ec-page-text-muted))]">+{owners.length - 2}</span>
225
203
  )}
226
- </div>
227
- ) : (
228
- <span className="text-[rgb(var(--ec-page-text-muted))] text-xs">-</span>
204
+ </td>
205
+ )}
206
+ {isScaleEnabled && (
207
+ <td className="px-4 py-3 text-sm text-[rgb(var(--ec-page-text-muted))]">
208
+ <span className="text-[0.8rem] text-[rgb(var(--ec-page-text-muted))]">
209
+ {field.usedInCount || 1} {(field.usedInCount || 1) === 1 ? 'schema' : 'schemas'}
210
+ </span>
211
+ </td>
229
212
  )}
230
- </td>
231
- </tr>
232
- );
233
- })}
234
- </tbody>
235
- </table>
213
+ <td className="px-4 py-3 text-sm text-[rgb(var(--ec-page-text-muted))]">
214
+ {owners.length > 0 ? (
215
+ <div className="flex items-center gap-1 flex-wrap">
216
+ {owners.slice(0, 2).map((owner) => (
217
+ <span
218
+ key={owner}
219
+ className="inline-flex items-center px-1.5 py-0.5 rounded text-[10px] font-medium bg-[rgb(var(--ec-accent)/0.1)] text-[rgb(var(--ec-accent))] truncate max-w-[100px]"
220
+ title={owner}
221
+ >
222
+ {owner}
223
+ </span>
224
+ ))}
225
+ {owners.length > 2 && (
226
+ <span className="text-[10px] text-[rgb(var(--ec-page-text-muted))]">+{owners.length - 2}</span>
227
+ )}
228
+ </div>
229
+ ) : (
230
+ <span className="text-[0.8rem] text-[rgb(var(--ec-page-text-muted))]">-</span>
231
+ )}
232
+ </td>
233
+ </tr>
234
+ );
235
+ })}
236
+ </tbody>
237
+ </table>
238
+ </div>
236
239
  </div>
237
240
  );
238
241
  }
@@ -9,6 +9,8 @@ import { EnvironmentDropdown } from './EnvironmentDropdown';
9
9
  import ChatPanelButton from './ChatPanel/ChatPanelButton';
10
10
  import ThemeToggle from './ThemeToggle';
11
11
 
12
+ const { showNestedSideBar = true } = Astro.props;
13
+
12
14
  let session = null;
13
15
  if (isAuthEnabled()) {
14
16
  session = await getSession(Astro.request);
@@ -25,26 +27,14 @@ const repositoryUrl = catalog?.repositoryUrl || 'https://github.com/event-catalo
25
27
 
26
28
  <nav
27
29
  id="eventcatalog-header"
28
- class="fixed top-0 left-0 right-0 h-header bg-[rgb(var(--ec-header-bg))] border-b border-[rgb(var(--ec-header-border))] py-3 font-bold text-xl z-10 text-[rgb(var(--ec-header-text))]"
30
+ class="fixed top-0 right-0 h-[60px] bg-[rgb(var(--ec-header-bg))] border-b border-[rgb(var(--ec-header-border))] py-3 font-bold text-xl z-50 text-[rgb(var(--ec-header-text))]"
31
+ style={showNestedSideBar
32
+ ? 'left: calc(var(--ec-vertical-nav-width, 14rem) + var(--ec-sidebar-panel-width, 20rem));'
33
+ : 'left: var(--ec-vertical-nav-width, 14rem);'}
29
34
  >
30
- <div class="px-4 sm:px-4 lg:px-4">
35
+ <div class="px-6">
31
36
  <div class="flex justify-between items-center">
32
- <div class="flex-shrink-0 flex items-center w-3/12 lg:w-[360px]">
33
- <a href={buildUrl(catalog.landingPage || '/')} class="flex space-x-2 items-center group">
34
- {
35
- logo.src && logo.src !== '/' && (
36
- <img alt={logo.alt} src={buildUrl(logo.src, true)} class="w-8 h-8 transition-transform group-hover:scale-105" />
37
- )
38
- }
39
- {
40
- logo.text && (
41
- <span class="hidden sm:inline-block text-[1em] transition-colors group-hover:text-gray-600">{logo.text}</span>
42
- )
43
- }
44
- </a>
45
- </div>
46
-
47
- <div class="hidden lg:flex flex-grow -ml-1 items-center">
37
+ <div class="hidden lg:flex flex-grow items-center">
48
38
  <div class="w-full max-w-xl">
49
39
  <Search />
50
40
  </div>
@@ -211,7 +201,7 @@ const repositoryUrl = catalog?.repositoryUrl || 'https://github.com/event-catalo
211
201
  </div>
212
202
  </nav>
213
203
 
214
- <div id="eventcatalog-header-spacer" class="h-header"></div>
204
+ <div id="eventcatalog-header-spacer" class="h-[60px]"></div>
215
205
  <!-- Spacer to prevent content from being hidden under the fixed header -->
216
206
 
217
207
  <script>
@@ -1,6 +1,5 @@
1
1
  import { Disclosure, DisclosureButton, DisclosurePanel } from '@headlessui/react';
2
- import { MinusIcon } from '@heroicons/react/16/solid';
3
- import { PlusIcon } from '@heroicons/react/24/outline';
2
+ import { ChevronDownIcon } from '@heroicons/react/20/solid';
4
3
  import { useEffect } from 'react';
5
4
 
6
5
  declare global {
@@ -12,8 +11,8 @@ declare global {
12
11
 
13
12
  export default function Example({ title, children }: any) {
14
13
  return (
15
- <div className="border border-[rgb(var(--ec-page-border))] rounded-md px-4 shadow-xs py-2 accordion bg-[rgb(var(--ec-card-bg,var(--ec-page-bg)))]">
16
- <Disclosure as="div" key={title} className="">
14
+ <div className="accordion border border-[rgb(var(--ec-page-border))] rounded-lg bg-[rgb(var(--ec-card-bg,var(--ec-page-bg)))] my-3">
15
+ <Disclosure as="div" key={title}>
17
16
  {({ open }) => {
18
17
  useEffect(() => {
19
18
  if (open) {
@@ -30,17 +29,16 @@ export default function Example({ title, children }: any) {
30
29
 
31
30
  return (
32
31
  <div>
33
- <DisclosureButton className="flex w-full items-start justify-between text-left text-[rgb(var(--ec-page-text))]">
34
- <span className="text-base font-semibold leading-7">{title}</span>
35
- <span className="ml-6 flex h-7 items-center">
36
- {open ? (
37
- <MinusIcon className="h-6 w-6" aria-hidden="true" />
38
- ) : (
39
- <PlusIcon className="h-6 w-6" aria-hidden="true" />
40
- )}
41
- </span>
32
+ <DisclosureButton className="group flex w-full items-center gap-3 px-5 py-4 text-left text-[rgb(var(--ec-page-text))] hover:bg-[rgb(var(--ec-page-text)/0.03)] transition-colors">
33
+ <ChevronDownIcon
34
+ className={`h-5 w-5 shrink-0 text-[rgb(var(--ec-page-text-muted))] transition-transform duration-200 ${
35
+ open ? 'rotate-0' : '-rotate-90'
36
+ }`}
37
+ aria-hidden="true"
38
+ />
39
+ <span className="text-base font-semibold leading-6">{title}</span>
42
40
  </DisclosureButton>
43
- <DisclosurePanel as="dd" className="pr-12 py-4 prose prose-sm max-w-none">
41
+ <DisclosurePanel as="dd" className="px-5 pb-5 pt-1 pl-12 prose prose-sm max-w-none">
44
42
  <div className="text-base leading-7 text-[rgb(var(--ec-page-text-muted))]">{children}</div>
45
43
  </DisclosurePanel>
46
44
  </div>