Skip to content

Commit 5a82e8c

Browse files
committed
Merge branch 'feat/exo' into dx-935-type-exo-query-filter-params
2 parents 29406a4 + 89e52b0 commit 5a82e8c

13 files changed

Lines changed: 804 additions & 11 deletions

File tree

lib/adapters/REST/endpoints/experience.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,9 +57,14 @@ export const update: RestEndpoint<'Experience', 'update'> = (
5757
rawData: UpdateExperienceProps,
5858
headers?: RawAxiosRequestHeaders,
5959
) => {
60-
const data: SetOptional<typeof rawData, 'sys'> & { componentTypeId?: string } = copy(rawData)
60+
const data: SetOptional<typeof rawData, 'sys'> & {
61+
componentTypeId?: string
62+
templateId?: string
63+
} = copy(rawData)
6164
if (rawData.sys.componentType) {
6265
data.componentTypeId = rawData.sys.componentType.sys.id
66+
} else if (rawData.sys.template) {
67+
data.templateId = rawData.sys.template.sys.id
6368
}
6469
delete data.sys
6570
return raw.put<ExperienceProps>(http, getBaseUrl(params) + `/${params.experienceId}`, data, {
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
import type { RawAxiosRequestHeaders } from 'axios'
2+
import type { AxiosInstance } from 'contentful-sdk-core'
3+
import copy from 'fast-copy'
4+
import type { SetOptional } from 'type-fest'
5+
import type {
6+
CursorPaginatedCollectionProp,
7+
GetFragmentParams,
8+
GetSpaceEnvironmentParams,
9+
} from '../../../common-types'
10+
import type {
11+
CreateFragmentProps,
12+
FragmentProps,
13+
FragmentQueryOptions,
14+
UpdateFragmentProps,
15+
} from '../../../entities/fragment'
16+
import type { RestEndpoint } from '../types'
17+
import * as raw from './raw'
18+
19+
const getBaseUrl = (params: GetSpaceEnvironmentParams) =>
20+
`/spaces/${params.spaceId}/environments/${params.environmentId}/fragments`
21+
22+
export const getMany: RestEndpoint<'Fragment', 'getMany'> = (
23+
http: AxiosInstance,
24+
params: GetSpaceEnvironmentParams & { query: FragmentQueryOptions },
25+
headers?: RawAxiosRequestHeaders,
26+
) => {
27+
return raw.get<CursorPaginatedCollectionProp<FragmentProps>>(http, getBaseUrl(params), {
28+
params: params.query,
29+
headers,
30+
})
31+
}
32+
33+
export const get: RestEndpoint<'Fragment', 'get'> = (
34+
http: AxiosInstance,
35+
params: GetFragmentParams,
36+
headers?: RawAxiosRequestHeaders,
37+
) => {
38+
return raw.get<FragmentProps>(http, getBaseUrl(params) + `/${params.fragmentId}`, { headers })
39+
}
40+
41+
export const create: RestEndpoint<'Fragment', 'create'> = (
42+
http: AxiosInstance,
43+
params: GetSpaceEnvironmentParams,
44+
rawData: CreateFragmentProps,
45+
headers?: RawAxiosRequestHeaders,
46+
) => {
47+
const data = copy(rawData)
48+
return raw.post<FragmentProps>(http, getBaseUrl(params), data, { headers })
49+
}
50+
51+
export const update: RestEndpoint<'Fragment', 'update'> = (
52+
http: AxiosInstance,
53+
params: GetFragmentParams,
54+
rawData: UpdateFragmentProps,
55+
headers?: RawAxiosRequestHeaders,
56+
) => {
57+
const data: SetOptional<typeof rawData, 'sys'> = copy(rawData)
58+
delete data.sys
59+
return raw.put<FragmentProps>(http, getBaseUrl(params) + `/${params.fragmentId}`, data, {
60+
headers: {
61+
...(rawData.sys?.version !== undefined && {
62+
'X-Contentful-Version': rawData.sys.version,
63+
}),
64+
...headers,
65+
},
66+
})
67+
}
68+
69+
export const del: RestEndpoint<'Fragment', 'delete'> = (
70+
http: AxiosInstance,
71+
params: GetFragmentParams,
72+
) => {
73+
return raw.del(http, getBaseUrl(params) + `/${params.fragmentId}`)
74+
}
75+
76+
export const publish: RestEndpoint<'Fragment', 'publish'> = (
77+
http: AxiosInstance,
78+
params: GetFragmentParams & { version: number },
79+
headers?: RawAxiosRequestHeaders,
80+
) => {
81+
return raw.put<FragmentProps>(
82+
http,
83+
getBaseUrl(params) + `/${params.fragmentId}/published`,
84+
null,
85+
{
86+
headers: {
87+
'X-Contentful-Version': params.version,
88+
...headers,
89+
},
90+
},
91+
)
92+
}
93+
94+
export const unpublish: RestEndpoint<'Fragment', 'unpublish'> = (
95+
http: AxiosInstance,
96+
params: GetFragmentParams & { version: number },
97+
headers?: RawAxiosRequestHeaders,
98+
) => {
99+
return raw.del<FragmentProps>(http, getBaseUrl(params) + `/${params.fragmentId}/published`, {
100+
headers: {
101+
'X-Contentful-Version': params.version,
102+
...headers,
103+
},
104+
})
105+
}

lib/adapters/REST/endpoints/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ import * as EnvironmentAlias from './environment-alias'
3434
import * as EnvironmentTemplate from './environment-template'
3535
import * as EnvironmentTemplateInstallation from './environment-template-installation'
3636
import * as Extension from './extension'
37+
import * as Fragment from './fragment'
3738
import * as Function from './function'
3839
import * as FunctionLog from './function-log'
3940
import * as Http from './http'
@@ -118,6 +119,7 @@ export default {
118119
EnvironmentTemplate,
119120
EnvironmentTemplateInstallation,
120121
Extension,
122+
Fragment,
121123
Function,
122124
FunctionLog,
123125
Http,

lib/common-types.ts

Lines changed: 57 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,12 @@ import type {
6666
CreateComponentTypeProps,
6767
UpdateComponentTypeProps,
6868
} from './entities/component-type'
69+
import type {
70+
CreateFragmentProps,
71+
FragmentProps,
72+
FragmentQueryOptions,
73+
UpdateFragmentProps,
74+
} from './entities/fragment'
6975
import type {
7076
CreateTemplateProps,
7177
TemplateProps,
@@ -377,14 +383,21 @@ export interface MetadataProps {
377383
}
378384

379385
/**
380-
* Metadata shape for ExO entities (ComponentType, Experience/View, Template).
386+
* Base metadata shape for ExO entities (ComponentType, Template).
387+
* Mirrors upstream MetadataSchema: tags and concepts only.
381388
* - tags: optional (upstream MetadataSchema.tags is z.optional as of SPA-3821)
382389
* - concepts: optional taxonomy concept links
383-
* - name: optional display name for variant labeling (SPA-3939)
384390
*/
385391
export interface ExoMetadataProps {
386392
tags?: Link<'Tag'>[]
387393
concepts?: Link<'TaxonomyConcept'>[]
394+
}
395+
396+
/**
397+
* Extended metadata shape for Experience entities only.
398+
* Adds name? for variant labeling (SPA-3939), mirroring upstream ExperienceMetadata.
399+
*/
400+
export interface ExperienceMetadataProps extends ExoMetadataProps {
388401
name?: string
389402
}
390403

@@ -1002,6 +1015,14 @@ type MRInternal<UA extends boolean> = {
10021015
(opts: MROpts<'TeamSpaceMembership', 'update', UA>): MRReturn<'TeamSpaceMembership', 'update'>
10031016
(opts: MROpts<'TeamSpaceMembership', 'delete', UA>): MRReturn<'TeamSpaceMembership', 'delete'>
10041017

1018+
(opts: MROpts<'Fragment', 'getMany', UA>): MRReturn<'Fragment', 'getMany'>
1019+
(opts: MROpts<'Fragment', 'get', UA>): MRReturn<'Fragment', 'get'>
1020+
(opts: MROpts<'Fragment', 'create', UA>): MRReturn<'Fragment', 'create'>
1021+
(opts: MROpts<'Fragment', 'update', UA>): MRReturn<'Fragment', 'update'>
1022+
(opts: MROpts<'Fragment', 'delete', UA>): MRReturn<'Fragment', 'delete'>
1023+
(opts: MROpts<'Fragment', 'publish', UA>): MRReturn<'Fragment', 'publish'>
1024+
(opts: MROpts<'Fragment', 'unpublish', UA>): MRReturn<'Fragment', 'unpublish'>
1025+
10051026
(opts: MROpts<'Template', 'getMany', UA>): MRReturn<'Template', 'getMany'>
10061027
(opts: MROpts<'Template', 'get', UA>): MRReturn<'Template', 'get'>
10071028
(opts: MROpts<'Template', 'create', UA>): MRReturn<'Template', 'create'>
@@ -2688,6 +2709,38 @@ export type MRActions = {
26882709
}
26892710
delete: { params: GetTeamSpaceMembershipParams; return: any }
26902711
}
2712+
Fragment: {
2713+
getMany: {
2714+
params: GetSpaceEnvironmentParams & { query: FragmentQueryOptions }
2715+
return: CursorPaginatedCollectionProp<FragmentProps>
2716+
}
2717+
get: {
2718+
params: GetFragmentParams
2719+
return: FragmentProps
2720+
}
2721+
create: {
2722+
params: GetSpaceEnvironmentParams
2723+
payload: CreateFragmentProps
2724+
return: FragmentProps
2725+
}
2726+
update: {
2727+
params: GetFragmentParams
2728+
payload: UpdateFragmentProps
2729+
return: FragmentProps
2730+
}
2731+
delete: {
2732+
params: GetFragmentParams
2733+
return: void
2734+
}
2735+
publish: {
2736+
params: GetFragmentParams & { version: number }
2737+
return: FragmentProps
2738+
}
2739+
unpublish: {
2740+
params: GetFragmentParams & { version: number }
2741+
return: FragmentProps
2742+
}
2743+
}
26912744
Template: {
26922745
getMany: {
26932746
params: GetSpaceEnvironmentParams & { query: TemplateQueryOptions }
@@ -3010,6 +3063,8 @@ export type GetExperienceParams = GetSpaceEnvironmentParams & { experienceId: st
30103063
/** @internal */
30113064
export type GetDataAssemblyParams = GetSpaceEnvironmentParams & { dataAssemblyId: string }
30123065
/** @internal */
3066+
export type GetFragmentParams = GetSpaceEnvironmentParams & { fragmentId: string }
3067+
/** @internal */
30133068
export type GetTemplateParams = GetSpaceEnvironmentParams & { templateId: string }
30143069
/** @internal */
30153070
export type GetContentTypeParams = GetSpaceEnvironmentParams & { contentTypeId: string }

lib/entities/component-type.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ export type ComponentTypeViewport = {
2525
export type ComponentTypeContentProperty = {
2626
id: string
2727
name: string
28-
type: string
28+
type: 'String' | 'Number' | 'Boolean'
2929
required: boolean
3030
defaultValue?: unknown
3131
}
@@ -54,7 +54,6 @@ export type ComponentTypeDesignProperty = {
5454
validations?: {
5555
in?: ComponentTypeDesignPropertyValidation[]
5656
}
57-
designTokenSet: string[]
5857
}
5958

6059
// Dimension key map

lib/entities/experience.ts

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import type {
22
CursorPaginatedCollectionProp,
33
CursorPaginationParams,
4-
ExoMetadataProps,
4+
ExperienceMetadataProps,
55
ExoQueryFilters,
66
Link,
77
} from '../common-types'
@@ -36,6 +36,9 @@ export type ExperienceSys = {
3636
updatedAt: string
3737
createdBy: Link<'User'>
3838
updatedBy: Link<'User'>
39+
archivedAt?: string
40+
archivedBy?: Link<'User'>
41+
archivedVersion?: number
3942
variant?: string
4043
variantType?: string
4144
variantDimension?: string
@@ -55,7 +58,7 @@ type ExperienceCommonProps = {
5558
designProperties: Record<string, DimensionedDesignPropertyValue>
5659
dimensionKeyMap: ExperienceDimensionKeyMap
5760
contentBindings?: ExperienceContentBindings
58-
metadata?: ExoMetadataProps
61+
metadata?: ExperienceMetadataProps
5962
slots?: Record<string, Array<FragmentNode | InlineFragmentNode>>
6063
}
6164

@@ -73,10 +76,13 @@ export type ExperienceQueryOptions = CursorPaginationParams &
7376
// Omit the payload entirely for a full publish (all locales).
7477
export type ExperienceLocalePublishPayload = { add: string[] } | { remove: string[] }
7578

76-
// Create payload — no sys, uses componentTypeId instead of sys.componentType link
77-
export type CreateExperienceProps = ExperienceCommonProps & {
78-
componentTypeId: string
79-
}
79+
// Create payload — no sys, uses either componentTypeId (component-type-backed) or
80+
// templateId (template-backed). The two fields are mutually exclusive.
81+
export type CreateExperienceProps = ExperienceCommonProps &
82+
(
83+
| { componentTypeId: string; templateId?: never }
84+
| { templateId: string; componentTypeId?: never }
85+
)
8086

8187
export type UpdateExperienceProps = ExperienceProps
8288

lib/entities/fragment.ts

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
import type { Except } from 'type-fest'
2+
import type {
3+
CursorPaginatedCollectionProp,
4+
CursorPaginationParams,
5+
ExoMetadataProps,
6+
Link,
7+
} from '../common-types'
8+
import type {
9+
ComponentTypeViewport,
10+
DimensionedDesignPropertyValue,
11+
FragmentNode,
12+
TreeNode,
13+
} from './component-type'
14+
import type {
15+
ExperienceContentBindings,
16+
ExperienceDimensionKeyMap,
17+
InlineFragmentNode,
18+
} from './experience'
19+
20+
export type FragmentSys = {
21+
id: string
22+
type: 'Fragment'
23+
version: number
24+
space: Link<'Space'>
25+
environment: Link<'Environment'>
26+
componentType: Link<'ComponentType'>
27+
archivedAt?: string
28+
archivedBy?: Link<'User'>
29+
archivedVersion?: number
30+
createdAt: string
31+
updatedAt: string
32+
createdBy: Link<'User'>
33+
updatedBy: Link<'User'>
34+
variant?: string
35+
variantType?: string
36+
variantDimension?: string
37+
publishedAt?: string
38+
publishedVersion?: number
39+
publishedCounter?: number
40+
firstPublishedAt?: string
41+
publishedBy?: Link<'User'> | Link<'AppDefinition'>
42+
localeStatus?: Record<string, 'draft' | 'published' | 'changed'>
43+
}
44+
45+
export type FragmentProps = {
46+
sys: FragmentSys
47+
name: string
48+
description: string
49+
viewports: ComponentTypeViewport[]
50+
designProperties: Record<string, DimensionedDesignPropertyValue>
51+
dimensionKeyMap: ExperienceDimensionKeyMap
52+
contentBindings?: ExperienceContentBindings
53+
metadata?: ExoMetadataProps
54+
slots?: Record<string, Array<TreeNode | FragmentNode | InlineFragmentNode>>
55+
}
56+
57+
export type CreateFragmentProps = Except<FragmentProps, 'sys'> & {
58+
componentTypeId: string
59+
}
60+
61+
export type UpdateFragmentProps = Omit<FragmentProps, 'sys'> & {
62+
sys: {
63+
id: string
64+
type: 'Fragment'
65+
version: number
66+
}
67+
componentTypeId: string
68+
}
69+
70+
export type FragmentQueryOptions = CursorPaginationParams & {
71+
order?: string
72+
[key: string]: unknown
73+
}
74+
75+
export type FragmentCollection = CursorPaginatedCollectionProp<FragmentProps>

0 commit comments

Comments
 (0)