@eventcatalog/core 3.43.0 → 3.44.0
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.
- package/dist/analytics/analytics.cjs +1 -1
- package/dist/analytics/analytics.js +2 -2
- package/dist/analytics/log-build.cjs +50 -2
- package/dist/analytics/log-build.js +4 -4
- package/dist/catalog-to-astro-content-directory.cjs +31 -1
- package/dist/catalog-to-astro-content-directory.js +2 -2
- package/dist/{chunk-O6KT4DPL.js → chunk-4SMA4HQ3.js} +1 -1
- package/dist/{chunk-5T63CXKU.js → chunk-6QENHZZP.js} +32 -2
- package/dist/{chunk-ZQHBDPIY.js → chunk-A7WJATRV.js} +2 -2
- package/dist/{chunk-ULZYHF3V.js → chunk-B7HCX5HM.js} +1 -1
- package/dist/{chunk-2EI3M7OO.js → chunk-H7IGB2WO.js} +1 -1
- package/dist/{chunk-7M5IQL3J.js → chunk-L2JZBH6K.js} +1 -1
- package/dist/{chunk-WAJIJEI3.js → chunk-LHR4G2UO.js} +1 -1
- package/dist/{chunk-QV2PKXZM.js → chunk-SWSSBJ6H.js} +20 -2
- package/dist/{chunk-KY74BE42.js → chunk-W7UIDHNR.js} +1 -1
- package/dist/constants.cjs +1 -1
- package/dist/constants.js +1 -1
- package/dist/eventcatalog-config-file-utils.cjs +31 -1
- package/dist/eventcatalog-config-file-utils.js +1 -1
- package/dist/eventcatalog.cjs +50 -2
- package/dist/eventcatalog.config.d.cts +25 -0
- package/dist/eventcatalog.config.d.ts +25 -0
- package/dist/eventcatalog.js +9 -9
- package/dist/features.cjs +31 -1
- package/dist/features.js +2 -2
- package/dist/generate.cjs +32 -2
- package/dist/generate.js +4 -4
- package/dist/resolve-catalog-dependencies.cjs +31 -1
- package/dist/resolve-catalog-dependencies.js +2 -2
- package/dist/utils/cli-logger.cjs +1 -1
- package/dist/utils/cli-logger.js +2 -2
- package/eventcatalog/astro.config.mjs +9 -1
- package/eventcatalog/src/components/FieldsExplorer/FieldNodeGraph.tsx +2 -2
- package/eventcatalog/src/components/Tables/Table.tsx +4 -0
- package/eventcatalog/src/components/Tables/columns/DirectorySourceColumn.tsx +49 -0
- package/eventcatalog/src/components/Tables/columns/TeamsTableColumns.tsx +11 -0
- package/eventcatalog/src/components/Tables/columns/UserTableColumns.tsx +11 -0
- package/eventcatalog/src/content.config.ts +29 -8
- package/eventcatalog/src/enterprise/directory/user-team-directory.spec.ts +527 -0
- package/eventcatalog/src/enterprise/directory/user-team-directory.ts +191 -0
- package/eventcatalog/src/pages/directory/[type]/index.astro +2 -0
- package/eventcatalog/src/pages/docs/teams/[id]/index.astro +29 -5
- package/eventcatalog/src/pages/docs/users/[id]/index.astro +29 -0
- package/eventcatalog/src/stores/eventcatalog-store.spec.ts +60 -0
- package/eventcatalog/src/stores/eventcatalog-store.ts +103 -0
- package/package.json +3 -3
|
@@ -7,6 +7,7 @@ import type { CollectionEntry } from 'astro:content';
|
|
|
7
7
|
import OwnersList from '@components/Lists/OwnersList';
|
|
8
8
|
import PillListFlat from '@components/Lists/PillListFlat';
|
|
9
9
|
import EnvelopeIcon from '@heroicons/react/16/solid/EnvelopeIcon';
|
|
10
|
+
import { Github } from 'lucide-react';
|
|
10
11
|
import { formatAdrStatus } from '@utils/collections/adrs';
|
|
11
12
|
import { buildUrl } from '@utils/url-builder';
|
|
12
13
|
import VerticalSideBarLayout from '@layouts/VerticalSideBarLayout.astro';
|
|
@@ -78,6 +79,9 @@ const ownedAdrsList = adrs.map((p) => ({
|
|
|
78
79
|
}));
|
|
79
80
|
|
|
80
81
|
const pageTitle = `Team | ${props.data.name}`;
|
|
82
|
+
const source = props.data.source;
|
|
83
|
+
const sourceLabel = source?.provider === 'github' ? 'GitHub' : source?.provider;
|
|
84
|
+
const sourceTitle = sourceLabel ? `Synced from ${sourceLabel}` : undefined;
|
|
81
85
|
---
|
|
82
86
|
|
|
83
87
|
<VerticalSideBarLayout title={pageTitle} description={props.data.summary}>
|
|
@@ -92,11 +96,6 @@ const pageTitle = `Team | ${props.data.name}`;
|
|
|
92
96
|
<div class="flex justify-start">
|
|
93
97
|
<div class="flex flex-col justify-between space-y-3">
|
|
94
98
|
<div>
|
|
95
|
-
<span
|
|
96
|
-
class="inline-flex items-center px-2.5 py-0.5 rounded-md text-xs font-medium bg-[rgb(var(--ec-content-hover))] text-[rgb(var(--ec-page-text-muted))] mb-2"
|
|
97
|
-
>
|
|
98
|
-
Team
|
|
99
|
-
</span>
|
|
100
99
|
<h2 class="text-3xl font-bold text-[rgb(var(--ec-page-text))]">{props.data.name}</h2>
|
|
101
100
|
</div>
|
|
102
101
|
{
|
|
@@ -140,6 +139,31 @@ const pageTitle = `Team | ${props.data.name}`;
|
|
|
140
139
|
</a>
|
|
141
140
|
)
|
|
142
141
|
}
|
|
142
|
+
{
|
|
143
|
+
source && sourceLabel && source.url && (
|
|
144
|
+
<a
|
|
145
|
+
href={source.url}
|
|
146
|
+
target="_blank"
|
|
147
|
+
rel="noopener noreferrer"
|
|
148
|
+
title={sourceTitle}
|
|
149
|
+
class="inline-flex items-center gap-1.5 text-sm text-[rgb(var(--ec-page-text-muted))] hover:text-[rgb(var(--ec-page-text))] transition-colors"
|
|
150
|
+
>
|
|
151
|
+
{source.provider === 'github' && <Github className="w-4 h-4 text-[rgb(var(--ec-icon-color))]" />}
|
|
152
|
+
<span>{sourceLabel}</span>
|
|
153
|
+
</a>
|
|
154
|
+
)
|
|
155
|
+
}
|
|
156
|
+
{
|
|
157
|
+
source && sourceLabel && !source.url && (
|
|
158
|
+
<span
|
|
159
|
+
title={sourceTitle}
|
|
160
|
+
class="inline-flex items-center gap-1.5 text-sm text-[rgb(var(--ec-page-text-muted))]"
|
|
161
|
+
>
|
|
162
|
+
{source.provider === 'github' && <Github className="w-4 h-4 text-[rgb(var(--ec-icon-color))]" />}
|
|
163
|
+
<span>{sourceLabel}</span>
|
|
164
|
+
</span>
|
|
165
|
+
)
|
|
166
|
+
}
|
|
143
167
|
</div>
|
|
144
168
|
</div>
|
|
145
169
|
</div>
|
|
@@ -7,6 +7,7 @@ import type { CollectionEntry } from 'astro:content';
|
|
|
7
7
|
import OwnersList from '@components/Lists/OwnersList';
|
|
8
8
|
import PillListFlat from '@components/Lists/PillListFlat';
|
|
9
9
|
import EnvelopeIcon from '@heroicons/react/16/solid/EnvelopeIcon';
|
|
10
|
+
import { Github } from 'lucide-react';
|
|
10
11
|
import { formatAdrStatus } from '@utils/collections/adrs';
|
|
11
12
|
import { buildUrl } from '@utils/url-builder';
|
|
12
13
|
import VerticalSideBarLayout from '@layouts/VerticalSideBarLayout.astro';
|
|
@@ -75,6 +76,9 @@ const associatedTeams = teams.map((o) => ({
|
|
|
75
76
|
}));
|
|
76
77
|
|
|
77
78
|
const pageTitle = `User | ${props.data.name}`;
|
|
79
|
+
const source = props.data.source;
|
|
80
|
+
const sourceLabel = source?.provider === 'github' ? 'GitHub' : source?.provider;
|
|
81
|
+
const sourceTitle = sourceLabel ? `Synced from ${sourceLabel}` : undefined;
|
|
78
82
|
---
|
|
79
83
|
|
|
80
84
|
<VerticalSideBarLayout title={pageTitle}>
|
|
@@ -141,6 +145,31 @@ const pageTitle = `User | ${props.data.name}`;
|
|
|
141
145
|
</a>
|
|
142
146
|
)
|
|
143
147
|
}
|
|
148
|
+
{
|
|
149
|
+
source && sourceLabel && source.url && (
|
|
150
|
+
<a
|
|
151
|
+
href={source.url}
|
|
152
|
+
target="_blank"
|
|
153
|
+
rel="noopener noreferrer"
|
|
154
|
+
title={sourceTitle}
|
|
155
|
+
class="inline-flex items-center gap-1.5 text-sm text-[rgb(var(--ec-page-text-muted))] hover:text-[rgb(var(--ec-page-text))] transition-colors"
|
|
156
|
+
>
|
|
157
|
+
{source.provider === 'github' && <Github className="w-4 h-4 text-[rgb(var(--ec-icon-color))]" />}
|
|
158
|
+
<span>{sourceLabel}</span>
|
|
159
|
+
</a>
|
|
160
|
+
)
|
|
161
|
+
}
|
|
162
|
+
{
|
|
163
|
+
source && sourceLabel && !source.url && (
|
|
164
|
+
<span
|
|
165
|
+
title={sourceTitle}
|
|
166
|
+
class="inline-flex items-center gap-1.5 text-sm text-[rgb(var(--ec-page-text-muted))]"
|
|
167
|
+
>
|
|
168
|
+
{source.provider === 'github' && <Github className="w-4 h-4 text-[rgb(var(--ec-icon-color))]" />}
|
|
169
|
+
<span>{sourceLabel}</span>
|
|
170
|
+
</span>
|
|
171
|
+
)
|
|
172
|
+
}
|
|
144
173
|
</div>
|
|
145
174
|
</div>
|
|
146
175
|
</div>
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { mkdtemp, readFile, rm } from 'node:fs/promises';
|
|
2
|
+
import { tmpdir } from 'node:os';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { describe, expect, it } from 'vitest';
|
|
5
|
+
import { EventCatalogStore } from './eventcatalog-store';
|
|
6
|
+
|
|
7
|
+
type TestStoreResources = {
|
|
8
|
+
users: { id: string; name: string }[];
|
|
9
|
+
teams: { id: string; name: string }[];
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
describe('EventCatalogStore', () => {
|
|
13
|
+
it('writes one collection while preserving the rest of the store', async () => {
|
|
14
|
+
const tempDir = await mkdtemp(path.join(tmpdir(), 'eventcatalog-store-'));
|
|
15
|
+
const storePath = EventCatalogStore.getStorePath(tempDir, 'directory');
|
|
16
|
+
const store = new EventCatalogStore<TestStoreResources>({
|
|
17
|
+
storePath,
|
|
18
|
+
resources: {
|
|
19
|
+
users: [],
|
|
20
|
+
teams: [],
|
|
21
|
+
},
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
try {
|
|
25
|
+
await store.writeCollection('teams', [{ id: 'platform', name: 'Platform' }]);
|
|
26
|
+
await store.writeCollection('users', [{ id: 'jane', name: 'Jane' }]);
|
|
27
|
+
|
|
28
|
+
const stored = JSON.parse(await readFile(storePath, 'utf8'));
|
|
29
|
+
expect(stored).toMatchObject({
|
|
30
|
+
version: '1',
|
|
31
|
+
resources: {
|
|
32
|
+
users: [{ id: 'jane', name: 'Jane' }],
|
|
33
|
+
teams: [{ id: 'platform', name: 'Platform' }],
|
|
34
|
+
},
|
|
35
|
+
});
|
|
36
|
+
expect(stored.generatedAt).toEqual(expect.any(String));
|
|
37
|
+
} finally {
|
|
38
|
+
await rm(tempDir, { recursive: true, force: true });
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it('does not create a store file when clearing a collection that has not been generated', async () => {
|
|
43
|
+
const tempDir = await mkdtemp(path.join(tmpdir(), 'eventcatalog-store-'));
|
|
44
|
+
const storePath = EventCatalogStore.getStorePath(tempDir, 'directory');
|
|
45
|
+
const store = new EventCatalogStore<TestStoreResources>({
|
|
46
|
+
storePath,
|
|
47
|
+
resources: {
|
|
48
|
+
users: [],
|
|
49
|
+
teams: [],
|
|
50
|
+
},
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
try {
|
|
54
|
+
await store.clearCollectionIfStoreExists('users');
|
|
55
|
+
expect(await store.exists()).toBe(false);
|
|
56
|
+
} finally {
|
|
57
|
+
await rm(tempDir, { recursive: true, force: true });
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
});
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { access, mkdir, readFile, rename, writeFile } from 'node:fs/promises';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
|
|
4
|
+
type StoreResource = {
|
|
5
|
+
id: string;
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
type StoreResources<TResources> = {
|
|
9
|
+
[K in keyof TResources]: StoreResource[];
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
type EventCatalogStoreFile<TResources> = {
|
|
13
|
+
version: '1';
|
|
14
|
+
generatedAt: string;
|
|
15
|
+
resources: TResources;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
type EventCatalogStoreOptions<TResources> = {
|
|
19
|
+
storePath: string;
|
|
20
|
+
resources: TResources;
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
const writeQueues = new Map<string, Promise<void>>();
|
|
24
|
+
|
|
25
|
+
export class EventCatalogStore<TResources extends StoreResources<TResources>> {
|
|
26
|
+
static getStorePath(projectDir: string, name: string) {
|
|
27
|
+
return path.join(projectDir, '.eventcatalog', 'store', `${name}.json`);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
constructor(private options: EventCatalogStoreOptions<TResources>) {}
|
|
31
|
+
|
|
32
|
+
async exists() {
|
|
33
|
+
try {
|
|
34
|
+
await access(this.options.storePath);
|
|
35
|
+
return true;
|
|
36
|
+
} catch {
|
|
37
|
+
return false;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
async read(): Promise<EventCatalogStoreFile<TResources>> {
|
|
42
|
+
try {
|
|
43
|
+
const store = JSON.parse(await readFile(this.options.storePath, 'utf8')) as Partial<EventCatalogStoreFile<TResources>>;
|
|
44
|
+
return {
|
|
45
|
+
version: '1',
|
|
46
|
+
generatedAt: store.generatedAt ?? new Date().toISOString(),
|
|
47
|
+
resources: this.normalizeResources(store.resources),
|
|
48
|
+
};
|
|
49
|
+
} catch {
|
|
50
|
+
return this.createEmptyStore();
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
async writeCollection<TKey extends keyof TResources & string>(collection: TKey, resources: TResources[TKey]) {
|
|
55
|
+
await this.queueWrite(async () => {
|
|
56
|
+
const store = await this.read();
|
|
57
|
+
store.generatedAt = new Date().toISOString();
|
|
58
|
+
store.resources[collection] = [...resources].sort((a, b) => a.id.localeCompare(b.id)) as TResources[TKey];
|
|
59
|
+
|
|
60
|
+
await this.write(store);
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
async clearCollectionIfStoreExists<TKey extends keyof TResources & string>(collection: TKey) {
|
|
65
|
+
if (!(await this.exists())) return;
|
|
66
|
+
await this.writeCollection(collection, [] as unknown as TResources[TKey]);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
private createEmptyStore(): EventCatalogStoreFile<TResources> {
|
|
70
|
+
return {
|
|
71
|
+
version: '1',
|
|
72
|
+
generatedAt: new Date().toISOString(),
|
|
73
|
+
resources: this.normalizeResources(),
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
private normalizeResources(resources?: Partial<TResources>): TResources {
|
|
78
|
+
const normalized = {} as TResources;
|
|
79
|
+
|
|
80
|
+
for (const collection of Object.keys(this.options.resources) as (keyof TResources & string)[]) {
|
|
81
|
+
const value = resources?.[collection];
|
|
82
|
+
normalized[collection] = (
|
|
83
|
+
Array.isArray(value) ? value : [...this.options.resources[collection]]
|
|
84
|
+
) as TResources[typeof collection];
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
return normalized;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
private async write(store: EventCatalogStoreFile<TResources>) {
|
|
91
|
+
await mkdir(path.dirname(this.options.storePath), { recursive: true });
|
|
92
|
+
await writeFile(`${this.options.storePath}.tmp`, `${JSON.stringify(store, null, 2)}\n`);
|
|
93
|
+
await rename(`${this.options.storePath}.tmp`, this.options.storePath);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
private async queueWrite(write: () => Promise<void>) {
|
|
97
|
+
const previousWrite = writeQueues.get(this.options.storePath) ?? Promise.resolve();
|
|
98
|
+
const nextWrite = previousWrite.catch(() => undefined).then(write);
|
|
99
|
+
|
|
100
|
+
writeQueues.set(this.options.storePath, nextWrite);
|
|
101
|
+
await nextWrite;
|
|
102
|
+
}
|
|
103
|
+
}
|
package/package.json
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
},
|
|
8
8
|
"license": "SEE LICENSE IN LICENSE",
|
|
9
9
|
"type": "module",
|
|
10
|
-
"version": "3.
|
|
10
|
+
"version": "3.44.0",
|
|
11
11
|
"publishConfig": {
|
|
12
12
|
"access": "public"
|
|
13
13
|
},
|
|
@@ -112,9 +112,9 @@
|
|
|
112
112
|
"update-notifier": "^7.3.1",
|
|
113
113
|
"uuid": "^10.0.0",
|
|
114
114
|
"zod": "^4.3.6",
|
|
115
|
-
"@eventcatalog/
|
|
115
|
+
"@eventcatalog/linter": "1.0.28",
|
|
116
116
|
"@eventcatalog/visualiser": "^3.22.1",
|
|
117
|
-
"@eventcatalog/
|
|
117
|
+
"@eventcatalog/sdk": "2.24.0"
|
|
118
118
|
},
|
|
119
119
|
"devDependencies": {
|
|
120
120
|
"@astrojs/check": "^0.9.9",
|