Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
d2fe023
feat: add bulk actions v2 support
colomolo Jan 27, 2025
01b28d0
chore: update payload types
colomolo Jan 27, 2025
1f73956
fix: add separate methods for v2 bulk actions
colomolo Jan 28, 2025
7368df8
Merge branch 'master' into locale-based-bulk-actions
colomolo Jan 28, 2025
f710030
fix: linting issues
colomolo Jan 28, 2025
79237e0
Merge branch 'locale-based-bulk-actions' of github.com:contentful/con…
colomolo Jan 28, 2025
2ea259f
test: add new methods tests
colomolo Jan 29, 2025
c35460a
test: adjust tests
colomolo Jan 30, 2025
60b4409
chore: add v2 wait method
colomolo Jan 30, 2025
5e667d1
chore: fix lint errors
colomolo Jan 30, 2025
59bf69f
chore: export types
colomolo Jan 31, 2025
0e3639b
chore: fix linter errors
colomolo Jan 31, 2025
560c415
test: tweak unpublish test
colomolo Feb 3, 2025
f6b9fa7
chore: fix prettier error
colomolo Feb 3, 2025
0defd8b
Merge branch 'master' into locale-based-bulk-actions
colomolo Feb 4, 2025
d37aacf
Merge branch 'master' into locale-based-bulk-actions
SofiaMargariti Oct 16, 2025
f32729a
fix: linting
SofiaMargariti Oct 16, 2025
92f2314
refactor: move test helpers to corresponding file
colomolo Oct 27, 2025
102ee69
Merge branch 'locale-based-bulk-actions' of github.com:contentful/con…
colomolo Oct 27, 2025
6a0e6a9
Merge branch 'master' into locale-based-bulk-actions
colomolo Oct 27, 2025
2bcfa7e
chore: fix lint
colomolo Nov 3, 2025
9c8a75a
Merge branch 'locale-based-bulk-actions' of github.com:contentful/con…
colomolo Nov 3, 2025
bb4f8a0
chore: linting fix
colomolo Nov 3, 2025
733f8b2
Merge branch 'master' into locale-based-bulk-actions
colomolo Nov 3, 2025
6169e7d
chore: another lint fix attempt
colomolo Nov 3, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 53 additions & 0 deletions lib/adapters/REST/endpoints/bulk-action.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ import type {
BulkActionPublishPayload,
BulkActionUnpublishPayload,
BulkActionValidatePayload,
PublishBulkActionV2Payload,
UnpublishBulkActionV2Payload,
ValidateBulkActionV2Payload,
} from '../../../entities/bulk-action'
import type { RestEndpoint } from '../types'
import * as raw from './raw'
Expand Down Expand Up @@ -54,3 +57,53 @@ export const validate: RestEndpoint<'BulkAction', 'validate'> = (
payload,
)
}

export const getV2: RestEndpoint<'BulkAction', 'getV2'> = (
http: AxiosInstance,
params: GetBulkActionParams,
) => {
return raw.get(
http,
`/spaces/${params.spaceId}/environments/${params.environmentId}/bulk_actions/${params.bulkActionId}`,
)
}

export const publishV2: RestEndpoint<'BulkAction', 'publishV2'> = (
http: AxiosInstance,
params: GetSpaceEnvironmentParams,
payload: PublishBulkActionV2Payload<'add'>,
): Promise<BulkActionProps<PublishBulkActionV2Payload<'add'>>> => {
return raw.post(
http,
`/spaces/${params.spaceId}/environments/${params.environmentId}/bulk_actions`,
payload,
)
}

export const unpublishV2: RestEndpoint<'BulkAction', 'unpublishV2'> = (
http: AxiosInstance,
params: GetSpaceEnvironmentParams,
payload: PublishBulkActionV2Payload<'remove'> | UnpublishBulkActionV2Payload,
): Promise<
BulkActionProps<PublishBulkActionV2Payload<'remove'> | UnpublishBulkActionV2Payload>
> => {
return raw.post(
http,
`/spaces/${params.spaceId}/environments/${params.environmentId}/bulk_actions`,
payload,
)
}

export const validateV2: RestEndpoint<'BulkAction', 'validateV2'> = (
http: AxiosInstance,
params: GetSpaceEnvironmentParams,
payload: ValidateBulkActionV2Payload<'add'> | ValidateBulkActionV2Payload<'remove'>,
): Promise<
BulkActionProps<ValidateBulkActionV2Payload<'add'> | ValidateBulkActionV2Payload<'remove'>>
> => {
return raw.post(
http,
`/spaces/${params.spaceId}/environments/${params.environmentId}/bulk_actions`,
payload,
)
}
29 changes: 29 additions & 0 deletions lib/common-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,11 @@ import type {
BulkActionProps,
BulkActionPublishPayload,
BulkActionUnpublishPayload,
BulkActionV2Payload,
BulkActionValidatePayload,
PublishBulkActionV2Payload,
UnpublishBulkActionV2Payload,
ValidateBulkActionV2Payload,
} from './entities/bulk-action'
import type {
CommentProps,
Expand Down Expand Up @@ -528,6 +532,10 @@ type MRInternal<UA extends boolean> = {
(opts: MROpts<'BulkAction', 'publish', UA>): MRReturn<'BulkAction', 'publish'>
(opts: MROpts<'BulkAction', 'unpublish', UA>): MRReturn<'BulkAction', 'unpublish'>
(opts: MROpts<'BulkAction', 'validate', UA>): MRReturn<'BulkAction', 'validate'>
(opts: MROpts<'BulkAction', 'getV2', UA>): MRReturn<'BulkAction', 'getV2'>
(opts: MROpts<'BulkAction', 'publishV2', UA>): MRReturn<'BulkAction', 'publishV2'>
(opts: MROpts<'BulkAction', 'unpublishV2', UA>): MRReturn<'BulkAction', 'unpublishV2'>
(opts: MROpts<'BulkAction', 'validateV2', UA>): MRReturn<'BulkAction', 'validateV2'>

(opts: MROpts<'Comment', 'get', UA>): MRReturn<'Comment', 'get'>
(opts: MROpts<'Comment', 'getMany', UA>): MRReturn<'Comment', 'getMany'>
Expand Down Expand Up @@ -1304,6 +1312,27 @@ export type MRActions = {
payload: BulkActionValidatePayload
return: BulkActionProps<BulkActionValidatePayload>
}
getV2: {
params: GetBulkActionParams
return: BulkActionProps<BulkActionV2Payload>
}
publishV2: {
params: GetSpaceEnvironmentParams
payload: PublishBulkActionV2Payload<'add'>
return: BulkActionProps<PublishBulkActionV2Payload<'add'>>
}
unpublishV2: {
params: GetSpaceEnvironmentParams
payload: PublishBulkActionV2Payload<'remove'> | UnpublishBulkActionV2Payload
return: BulkActionProps<PublishBulkActionV2Payload<'remove'> | UnpublishBulkActionV2Payload>
}
validateV2: {
params: GetSpaceEnvironmentParams
payload: ValidateBulkActionV2Payload<'add'> | ValidateBulkActionV2Payload<'remove'>
return: BulkActionProps<
ValidateBulkActionV2Payload<'add'> | ValidateBulkActionV2Payload<'remove'>
>
}
}
Comment: {
get:
Expand Down
53 changes: 48 additions & 5 deletions lib/entities/bulk-action.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,49 @@ export interface BulkActionPublishPayload extends MakeRequestPayload {
}
}

interface AddFieldsEntity<L extends Link<Entity> | VersionedLink<Entity>> {
entity: L
add?: {
fields: Record<'*', string[]>
}
}

interface RemoveFieldsEntity<L extends Link<Entity> | VersionedLink<Entity>> {
entity: L
remove?: {
fields: Record<'*', string[]>
}
}
type BulkActionEntity<L extends Link<Entity> | VersionedLink<Entity>> = {
entity: L
}

export interface PublishBulkActionV2Payload<PublishActionType extends 'add' | 'remove' = 'add'> {
action: 'publish'
entities: PublishActionType extends 'remove'
? RemoveFieldsEntity<VersionedLink<Entity>>[]
: AddFieldsEntity<VersionedLink<Entity>>[]
}

export interface ValidateBulkActionV2Payload<PublishActionType extends 'add' | 'remove' = 'add'> {
action: 'validate'
entities: PublishActionType extends 'remove'
? RemoveFieldsEntity<Link<Entity>>[]
: AddFieldsEntity<Link<Entity>>[]
}

export interface UnpublishBulkActionV2Payload {
action: 'unpublish'
entities: BulkActionEntity<Link<Entity>>[]
}

export type BulkActionV2Payload =
| PublishBulkActionV2Payload<'add'>
| PublishBulkActionV2Payload<'remove'>
| UnpublishBulkActionV2Payload
| ValidateBulkActionV2Payload<'add'>
| ValidateBulkActionV2Payload<'remove'>

export type BulkActionSysProps = {
id: string
type: 'BulkAction'
Expand All @@ -81,7 +124,7 @@ export type BulkActionSysProps = {
}

/** The object returned by the BulkActions API */
export interface BulkActionProps<TPayload extends BulkActionPayload = any> {
export interface BulkActionProps<TPayload extends BulkActionPayload | BulkActionV2Payload = any> {
sys: BulkActionSysProps
action: BulkActionType
/** original payload when BulkAction was created */
Expand Down Expand Up @@ -120,15 +163,15 @@ function createBulkActionApi(makeRequest: MakeRequest) {
params,
}).then((bulkAction) => wrapBulkAction(makeRequest, bulkAction))
},
async waitProcessing<TPayload extends BulkActionPayload = any>(
async waitProcessing<TPayload extends BulkActionPayload | BulkActionV2Payload = any>(
options?: AsyncActionProcessingOptions,
): Promise<BulkActionProps<TPayload>> {
return pollAsyncActionStatus<BulkActionProps<TPayload>>(async () => this.get(), options)
},
}
}

export interface BulkAction<T extends BulkActionPayload = any>
export interface BulkAction<T extends BulkActionPayload | BulkActionV2Payload = any>
extends BulkActionProps<T>,
BulkActionApiMethods,
DefaultElements<BulkActionProps<T>> {}
Expand All @@ -139,9 +182,9 @@ export interface BulkAction<T extends BulkActionPayload = any>
* @param data - Raw BulkAction data
* @return Wrapped BulkAction data
*/
export function wrapBulkAction<TPayload extends BulkActionPayload = any>(
export function wrapBulkAction<TPayload extends BulkActionPayload | BulkActionV2Payload = any>(
makeRequest: MakeRequest,
data: BulkActionProps<BulkActionPayload>,
data: BulkActionProps<BulkActionPayload | BulkActionV2Payload>,
): BulkAction<TPayload> {
const bulkAction = toPlainObject(copy(data))
const bulkActionWithApiMethods = enhanceWithMethods(
Expand Down
4 changes: 4 additions & 0 deletions lib/export-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,10 @@ export type {
BulkActionType,
BulkActionUnpublishPayload,
BulkActionValidatePayload,
BulkActionV2Payload,
PublishBulkActionV2Payload,
UnpublishBulkActionV2Payload,
ValidateBulkActionV2Payload,
} from './entities/bulk-action'
export type {
Comment,
Expand Down
29 changes: 0 additions & 29 deletions lib/methods/bulk-action.ts

This file was deleted.

19 changes: 19 additions & 0 deletions lib/plain/common-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,11 @@ import type {
BulkActionProps,
BulkActionPublishPayload,
BulkActionUnpublishPayload,
BulkActionV2Payload,
BulkActionValidatePayload,
PublishBulkActionV2Payload,
UnpublishBulkActionV2Payload,
ValidateBulkActionV2Payload,
} from '../entities/bulk-action'
import type { ContentTypeProps, CreateContentTypeProps } from '../entities/content-type'
import type { CreateEntryProps, EntryProps, EntryReferenceProps } from '../entities/entry'
Expand Down Expand Up @@ -246,6 +250,21 @@ export type PlainClientAPI = {
params: GetSpaceEnvironmentParams,
payload: BulkActionValidatePayload,
): Promise<BulkActionProps<BulkActionValidatePayload>>
getV2(params: GetBulkActionParams): Promise<BulkActionProps<BulkActionV2Payload>>
publishV2(
params: GetSpaceEnvironmentParams,
payload: PublishBulkActionV2Payload<'add'>,
): Promise<BulkActionProps<PublishBulkActionV2Payload<'add'>>>
unpublishV2(
params: GetSpaceEnvironmentParams,
payload: PublishBulkActionV2Payload<'remove'> | UnpublishBulkActionV2Payload,
): Promise<BulkActionProps<PublishBulkActionV2Payload<'remove'> | UnpublishBulkActionV2Payload>>
validateV2(
params: GetSpaceEnvironmentParams,
payload: ValidateBulkActionV2Payload<'add'> | ValidateBulkActionV2Payload<'remove'>,
): Promise<
BulkActionProps<ValidateBulkActionV2Payload<'add'> | ValidateBulkActionV2Payload<'remove'>>
>
}
comment: CommentPlainClientAPI
concept: ConceptPlainClientAPI
Expand Down
4 changes: 4 additions & 0 deletions lib/plain/plain-client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,10 @@ export const createPlainClient = (
publish: wrap(wrapParams, 'BulkAction', 'publish'),
unpublish: wrap(wrapParams, 'BulkAction', 'unpublish'),
validate: wrap(wrapParams, 'BulkAction', 'validate'),
getV2: wrap(wrapParams, 'BulkAction', 'getV2'),
publishV2: wrap(wrapParams, 'BulkAction', 'publishV2'),
unpublishV2: wrap(wrapParams, 'BulkAction', 'unpublishV2'),
validateV2: wrap(wrapParams, 'BulkAction', 'validateV2'),
},
comment: {
get: wrap(wrapParams, 'Comment', 'get') as PlainClientAPI['comment']['get'],
Expand Down
54 changes: 52 additions & 2 deletions test/helpers.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,25 @@
import type { CreateHttpClientParams } from 'contentful-sdk-core'
import * as testUtils from '@contentful/integration-test-utils'
import { createClient } from '../lib/contentful-management'
import type { Environment, Organization, Space } from '../lib/contentful-management'
import type {
BulkActionPayload,
BulkActionProps,
BulkActionV2Payload,
Environment,
Organization,
PlainClientAPI,
Space,
} from '../lib/contentful-management'
import { TestDefaults } from './defaults'
import { AsyncActionProcessingOptions, pollAsyncActionStatus } from '../lib/methods/action'

import * as testUtils from '@contentful/integration-test-utils'
type PlainOptions = {
/** Used by the PlainClient to perform a poll for the BulkAction status */
plainClient: PlainClientAPI
spaceId: string
environmentId: string
bulkActionId: string
}

const accessToken = process.env.CONTENTFUL_INTEGRATION_TEST_CMA_TOKEN
const orgId = process.env.CONTENTFUL_ORGANIZATION_ID
Expand Down Expand Up @@ -200,3 +216,37 @@ export const cleanupTaxonomy = async (olderThan = 1000 * 60 * 60) => {
}

export const timeoutToCalmRateLimiting = () => new Promise((resolve) => setTimeout(resolve, 1000))

/** Waits for a BulkAction status to be either succeeded or failed.
* Used by the Plain client */
export async function waitForBulkActionProcessing<T extends BulkActionPayload = any>(
{ plainClient, spaceId, environmentId, bulkActionId }: PlainOptions,
options?: AsyncActionProcessingOptions,
): Promise<BulkActionProps<T>> {
return pollAsyncActionStatus<BulkActionProps>(
async () =>
plainClient.bulkAction.get<T>({
bulkActionId,
spaceId,
environmentId,
}),
options,
)
}

/** Waits for a BulkAction V2 status to be either succeeded or failed.
* Used by the Plain client */
export async function waitForBulkActionV2Processing<T extends BulkActionV2Payload = any>(
{ plainClient, spaceId, environmentId, bulkActionId }: PlainOptions,
options?: AsyncActionProcessingOptions,
): Promise<BulkActionProps<T>> {
return pollAsyncActionStatus<BulkActionProps>(
async () =>
plainClient.bulkAction.getV2({
bulkActionId,
spaceId,
environmentId,
}),
options,
)
}
Loading