Skip to content

Commit ed94ed8

Browse files
authored
Add cover image support (#598)
1 parent 5b742d9 commit ed94ed8

2 files changed

Lines changed: 94 additions & 32 deletions

File tree

packages/hypergraph/src/space/find-many-public.ts

Lines changed: 39 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ const spaceFields = `
1010
type
1111
page {
1212
name
13-
relationsList(filter: {
13+
avatarRelations: relationsList(filter: {
1414
typeId: { is: "${ContentIds.AVATAR_PROPERTY}"}
1515
}) {
1616
toEntity {
@@ -22,6 +22,18 @@ const spaceFields = `
2222
}
2323
}
2424
}
25+
coverRelations: relationsList(filter: {
26+
typeId: { is: "${SystemIds.COVER_PROPERTY}"}
27+
}) {
28+
toEntity {
29+
valuesList(filter: {
30+
propertyId: { is: "${SystemIds.IMAGE_URL_PROPERTY}"}
31+
}) {
32+
propertyId
33+
text
34+
}
35+
}
36+
}
2537
}
2638
editorsList {
2739
memberSpaceId
@@ -40,26 +52,30 @@ export const PublicSpaceSchema = EffectSchema.Struct({
4052
type: SpaceTypeSchema,
4153
name: EffectSchema.String,
4254
avatar: EffectSchema.optional(EffectSchema.String),
55+
cover: EffectSchema.optional(EffectSchema.String),
4356
editorIds: EffectSchema.Array(EffectSchema.String),
4457
memberIds: EffectSchema.Array(EffectSchema.String),
4558
});
4659

4760
export type PublicSpace = typeof PublicSpaceSchema.Type;
4861

62+
type RelationEntry = {
63+
toEntity?: {
64+
valuesList?: {
65+
propertyId: string;
66+
text: string | null;
67+
}[];
68+
} | null;
69+
};
70+
4971
type SpacesQueryResult = {
5072
spaces?: {
5173
id: string;
5274
type: 'PERSONAL' | 'DAO';
5375
page: {
5476
name?: string | null;
55-
relationsList?: {
56-
toEntity?: {
57-
valuesList?: {
58-
propertyId: string;
59-
text: string | null;
60-
}[];
61-
} | null;
62-
}[];
77+
avatarRelations?: RelationEntry[];
78+
coverRelations?: RelationEntry[];
6379
} | null;
6480
editorsList?: {
6581
memberSpaceId: string;
@@ -74,16 +90,24 @@ type SpaceQueryEntry = NonNullable<SpacesQueryResult['spaces']>[number];
7490

7591
const decodeSpace = EffectSchema.decodeUnknownEither(PublicSpaceSchema);
7692

77-
const getAvatarFromSpace = (space: SpaceQueryEntry) => {
78-
const firstRelation = space.page?.relationsList?.[0];
93+
const getImageFromRelations = (relations?: RelationEntry[]) => {
94+
const firstRelation = relations?.[0];
7995
const firstValue = firstRelation?.toEntity?.valuesList?.[0];
80-
const avatar = firstValue?.text;
81-
if (typeof avatar === 'string') {
82-
return avatar;
96+
const url = firstValue?.text;
97+
if (typeof url === 'string') {
98+
return url;
8399
}
84100
return undefined;
85101
};
86102

103+
const getAvatarFromSpace = (space: SpaceQueryEntry) => {
104+
return getImageFromRelations(space.page?.avatarRelations);
105+
};
106+
107+
const getCoverFromSpace = (space: SpaceQueryEntry) => {
108+
return getImageFromRelations(space.page?.coverRelations);
109+
};
110+
87111
const getEditorIdsFromSpace = (space: SpaceQueryEntry): string[] => {
88112
return (space.editorsList ?? []).map((e) => e.memberSpaceId).filter((id): id is string => typeof id === 'string');
89113
};
@@ -103,6 +127,7 @@ export const parseSpacesQueryResult = (queryResult: SpacesQueryResult) => {
103127
type: space.type,
104128
name: space.page?.name ?? undefined,
105129
avatar: getAvatarFromSpace(space),
130+
cover: getCoverFromSpace(space),
106131
editorIds: getEditorIdsFromSpace(space),
107132
memberIds: getMemberIdsFromSpace(space),
108133
};

packages/hypergraph/test/space/find-many-public.test.ts

Lines changed: 55 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,36 @@
11
import { describe, expect, it } from 'vitest';
22
import { buildFilterString, buildSpacesQuery, parseSpacesQueryResult } from '../../src/space/find-many-public.js';
33

4+
const buildImageRelation = (url: string | null) => [
5+
{
6+
toEntity: {
7+
valuesList:
8+
url === null
9+
? []
10+
: [
11+
{
12+
propertyId: '8a743832c0944a62b6650c3cc2f9c7bc',
13+
text: url,
14+
},
15+
],
16+
},
17+
},
18+
];
19+
420
const buildQuerySpace = ({
521
id = 'space-id',
622
type = 'PERSONAL',
723
name = 'Space name',
824
avatar,
25+
cover,
926
editorsList = [],
1027
membersList = [],
1128
}: {
1229
id?: string;
1330
type?: 'PERSONAL' | 'DAO';
1431
name?: string | null;
1532
avatar?: string | null;
33+
cover?: string | null;
1634
editorsList?: { memberSpaceId: string }[];
1735
membersList?: { memberSpaceId: string }[];
1836
} = {}) => {
@@ -21,24 +39,8 @@ const buildQuerySpace = ({
2139
type,
2240
page: {
2341
name,
24-
relationsList:
25-
avatar === undefined
26-
? []
27-
: [
28-
{
29-
toEntity: {
30-
valuesList:
31-
avatar === null
32-
? []
33-
: [
34-
{
35-
propertyId: '8a743832c0944a62b6650c3cc2f9c7bc',
36-
text: avatar,
37-
},
38-
],
39-
},
40-
},
41-
],
42+
avatarRelations: avatar === undefined ? [] : buildImageRelation(avatar),
43+
coverRelations: cover === undefined ? [] : buildImageRelation(cover),
4244
},
4345
editorsList,
4446
membersList,
@@ -64,6 +66,39 @@ describe('parseSpacesQueryResult', () => {
6466
expect(invalidSpaces).toHaveLength(0);
6567
});
6668

69+
it('parses cover image', () => {
70+
const { data } = parseSpacesQueryResult({
71+
spaces: [
72+
buildQuerySpace({
73+
id: 'space-cover',
74+
name: 'Space with cover',
75+
avatar: 'https://example.com/avatar.png',
76+
cover: 'https://example.com/cover.png',
77+
}),
78+
],
79+
});
80+
81+
expect(data).toEqual([
82+
{
83+
id: 'space-cover',
84+
type: 'PERSONAL',
85+
name: 'Space with cover',
86+
avatar: 'https://example.com/avatar.png',
87+
cover: 'https://example.com/cover.png',
88+
editorIds: [],
89+
memberIds: [],
90+
},
91+
]);
92+
});
93+
94+
it('omits cover when not provided', () => {
95+
const { data } = parseSpacesQueryResult({
96+
spaces: [buildQuerySpace({ id: 'space-no-cover', name: 'No cover' })],
97+
});
98+
99+
expect(data[0]?.cover).toBeUndefined();
100+
});
101+
67102
it('omits avatar when not provided', () => {
68103
const { data } = parseSpacesQueryResult({
69104
spaces: [buildQuerySpace({ id: 'space-2', name: 'Space 2', avatar: undefined })],
@@ -243,6 +278,8 @@ describe('buildSpacesQuery', () => {
243278
expect(query).toContain('id');
244279
expect(query).toContain('type');
245280
expect(query).toContain('page {');
281+
expect(query).toContain('avatarRelations:');
282+
expect(query).toContain('coverRelations:');
246283
expect(query).toContain('editorsList {');
247284
expect(query).toContain('membersList {');
248285
});

0 commit comments

Comments
 (0)