chore(content-releases): remove future flags (#19245)

This commit is contained in:
markkaylor 2024-01-19 15:54:10 +01:00 committed by GitHub
parent 0d0b078513
commit d172fb07e2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 663 additions and 682 deletions

File diff suppressed because it is too large Load Diff

View File

@ -12,10 +12,7 @@ import type { Plugin } from '@strapi/types';
const admin: Plugin.Config.AdminInput = { const admin: Plugin.Config.AdminInput = {
// eslint-disable-next-line @typescript-eslint/no-explicit-any // eslint-disable-next-line @typescript-eslint/no-explicit-any
register(app: any) { register(app: any) {
if ( if (window.strapi.features.isEnabled('cms-content-releases')) {
window.strapi.features.isEnabled('cms-content-releases') &&
window.strapi.future.isEnabled('contentReleases')
) {
app.addMenuLink({ app.addMenuLink({
to: `/plugins/${pluginId}`, to: `/plugins/${pluginId}`,
icon: PaperPlane, icon: PaperPlane,

View File

@ -23,9 +23,9 @@ describe('register', () => {
addDestroyListenerCallback: jest.fn(), addDestroyListenerCallback: jest.fn(),
})), })),
})), })),
eventHub: { hook: jest.fn(() => ({
on: jest.fn(), register: jest.fn(),
}, })),
admin: { admin: {
services: { services: {
permission: { permission: {

View File

@ -1,23 +1,20 @@
/* eslint-disable @typescript-eslint/no-var-requires */ /* eslint-disable @typescript-eslint/no-var-requires */
import type { LoadedStrapi, Entity as StrapiEntity } from '@strapi/types'; import type { LoadedStrapi, Entity as StrapiEntity } from '@strapi/types';
import { RELEASE_ACTION_MODEL_UID } from './constants'; import { RELEASE_ACTION_MODEL_UID } from './constants';
const { features } = require('@strapi/strapi/dist/utils/ee'); const { features } = require('@strapi/strapi/dist/utils/ee');
export const bootstrap = async ({ strapi }: { strapi: LoadedStrapi }) => { export const bootstrap = async ({ strapi }: { strapi: LoadedStrapi }) => {
if ( if (features.isEnabled('cms-content-releases')) {
features.isEnabled('cms-content-releases') && // Clean up release-actions when an entry is deleted
strapi.features.future.isEnabled('contentReleases')
) {
strapi.db.lifecycles.subscribe({ strapi.db.lifecycles.subscribe({
afterDelete(event) { afterDelete(event) {
// @ts-expect-error TODO: lifecycles types looks like are not 100% finished // @ts-expect-error TODO: lifecycles types looks like are not 100% finished
const { model, result } = event; const { model, result } = event;
// @ts-expect-error TODO: lifecycles types looks like are not 100% finished // @ts-expect-error TODO: lifecycles types looks like are not 100% finished
if (model.kind === 'collectionType' && model.options.draftAndPublish) { if (model.kind === 'collectionType' && model.options?.draftAndPublish) {
const { id } = result; const { id } = result;
strapi.db.query(RELEASE_ACTION_MODEL_UID).deleteMany({ strapi.db.query(RELEASE_ACTION_MODEL_UID).deleteMany({
where: { where: {
target_type: model.uid, target_type: model.uid,
@ -26,26 +23,21 @@ export const bootstrap = async ({ strapi }: { strapi: LoadedStrapi }) => {
}); });
} }
}, },
/** /**
* deleteMany hook doesn't return the deleted entries ids * deleteMany hook doesn't return the deleted entries ids
* so we need to fetch them before deleting the entries to save the ids on our state * so we need to fetch them before deleting the entries to save the ids on our state
*/ */
async beforeDeleteMany(event) { async beforeDeleteMany(event) {
const { model, params } = event; const { model, params } = event;
// @ts-expect-error TODO: lifecycles types looks like are not 100% finished // @ts-expect-error TODO: lifecycles types looks like are not 100% finished
if (model.kind === 'collectionType' && model.options.draftAndPublish) { if (model.kind === 'collectionType' && model.options?.draftAndPublish) {
const { where } = params; const { where } = params;
const entriesToDelete = await strapi.db const entriesToDelete = await strapi.db
.query(model.uid) .query(model.uid)
.findMany({ select: ['id'], where }); .findMany({ select: ['id'], where });
event.state.entriesToDelete = entriesToDelete; event.state.entriesToDelete = entriesToDelete;
} }
}, },
/** /**
* We delete the release actions related to deleted entries * We delete the release actions related to deleted entries
* We make this only after deleteMany is succesfully executed to avoid errors * We make this only after deleteMany is succesfully executed to avoid errors
@ -53,7 +45,6 @@ export const bootstrap = async ({ strapi }: { strapi: LoadedStrapi }) => {
async afterDeleteMany(event) { async afterDeleteMany(event) {
const { model, state } = event; const { model, state } = event;
const entriesToDelete = state.entriesToDelete; const entriesToDelete = state.entriesToDelete;
if (entriesToDelete) { if (entriesToDelete) {
await strapi.db.query(RELEASE_ACTION_MODEL_UID).deleteMany({ await strapi.db.query(RELEASE_ACTION_MODEL_UID).deleteMany({
where: { where: {

View File

@ -5,15 +5,11 @@ import { contentTypes } from './content-types';
import { services } from './services'; import { services } from './services';
import { controllers } from './controllers'; import { controllers } from './controllers';
import { routes } from './routes'; import { routes } from './routes';
import { getService } from './utils';
const { features } = require('@strapi/strapi/dist/utils/ee'); const { features } = require('@strapi/strapi/dist/utils/ee');
const getPlugin = () => { const getPlugin = () => {
if ( if (features.isEnabled('cms-content-releases')) {
features.isEnabled('cms-content-releases') &&
strapi.features.future.isEnabled('contentReleases')
) {
return { return {
register, register,
bootstrap, bootstrap,
@ -21,14 +17,6 @@ const getPlugin = () => {
services, services,
controllers, controllers,
routes, routes,
destroy() {
if (
features.isEnabled('cms-content-releases') &&
strapi.features.future.isEnabled('contentReleases')
) {
getService('event-manager').destroyAllListeners();
}
},
}; };
} }

View File

@ -0,0 +1,53 @@
import type { Schema } from '@strapi/types';
import { contentTypes as contentTypesUtils, mapAsync } from '@strapi/utils';
import { difference, keys } from 'lodash';
import { RELEASE_ACTION_MODEL_UID } from '../constants';
interface Input {
oldContentTypes: Record<string, Schema.ContentType>;
contentTypes: Record<string, Schema.ContentType>;
}
export async function deleteActionsOnDisableDraftAndPublish({
oldContentTypes,
contentTypes,
}: Input) {
if (!oldContentTypes) {
return;
}
for (const uid in contentTypes) {
if (!oldContentTypes[uid]) {
continue;
}
const oldContentType = oldContentTypes[uid];
const contentType = contentTypes[uid];
if (
contentTypesUtils.hasDraftAndPublish(oldContentType) &&
!contentTypesUtils.hasDraftAndPublish(contentType)
) {
await strapi.db
?.queryBuilder(RELEASE_ACTION_MODEL_UID)
.delete()
.where({ contentType: uid })
.execute();
}
}
}
export async function deleteActionsOnDeleteContentType({ oldContentTypes, contentTypes }: Input) {
const deletedContentTypes = difference(keys(oldContentTypes), keys(contentTypes)) ?? [];
if (deletedContentTypes.length) {
await mapAsync(deletedContentTypes, async (deletedContentTypeUID: unknown) => {
return strapi.db
?.queryBuilder(RELEASE_ACTION_MODEL_UID)
.delete()
.where({ contentType: deletedContentTypeUID })
.execute();
});
}
}

View File

@ -1,37 +1,16 @@
/* eslint-disable @typescript-eslint/no-var-requires */ /* eslint-disable @typescript-eslint/no-var-requires */
import type { LoadedStrapi } from '@strapi/types'; import type { LoadedStrapi } from '@strapi/types';
import { ACTIONS } from './constants';
import { getService } from './utils'; import { ACTIONS } from './constants';
import { deleteActionsOnDeleteContentType, deleteActionsOnDisableDraftAndPublish } from './migrations';
const { features } = require('@strapi/strapi/dist/utils/ee'); const { features } = require('@strapi/strapi/dist/utils/ee');
export const register = async ({ strapi }: { strapi: LoadedStrapi }) => { export const register = async ({ strapi }: { strapi: LoadedStrapi }) => {
if ( if (features.isEnabled('cms-content-releases')) {
features.isEnabled('cms-content-releases') &&
strapi.features.future.isEnabled('contentReleases')
) {
await strapi.admin.services.permission.actionProvider.registerMany(ACTIONS); await strapi.admin.services.permission.actionProvider.registerMany(ACTIONS);
const releaseActionService = getService('release-action', { strapi }); strapi.hook('strapi::content-types.beforeSync').register(deleteActionsOnDisableDraftAndPublish);
const eventManager = getService('event-manager', { strapi }); strapi.hook('strapi::content-types.afterSync').register(deleteActionsOnDeleteContentType);
// Clean up release-actions when draft and publish is disabled
const destroyContentTypeUpdateListener = strapi.eventHub.on(
'content-type.update',
async ({ contentType }) => {
if (contentType.schema.options.draftAndPublish === false) {
await releaseActionService.deleteManyForContentType(contentType.uid);
}
}
);
eventManager.addDestroyListenerCallback(destroyContentTypeUpdateListener);
// Clean up release-actions when a content-type is deleted
const destroyContentTypeDeleteListener = strapi.eventHub.on(
'content-type.delete',
async ({ contentType }) => {
await releaseActionService.deleteManyForContentType(contentType.uid);
}
);
eventManager.addDestroyListenerCallback(destroyContentTypeDeleteListener);
} }
}; };

View File

@ -1,23 +0,0 @@
import createReleaseActionService from '../release-action';
describe('Release Action service', () => {
it('deletes all release actions given a content type uid', async () => {
const strapiMock = {
db: {
query: jest.fn().mockReturnValue({
deleteMany: jest.fn(),
}),
},
};
// @ts-expect-error Ignore missing properties
const releaseActionService = createReleaseActionService({ strapi: strapiMock });
await releaseActionService.deleteManyForContentType('api::test.test');
expect(strapiMock.db.query().deleteMany).toHaveBeenCalledWith({
where: {
target_type: 'api::test.test',
},
});
});
});

View File

@ -1,27 +0,0 @@
interface ReleaseEventServiceState {
destroyListenerCallbacks: (() => void)[];
}
const createEventManagerService = () => {
const state: ReleaseEventServiceState = {
destroyListenerCallbacks: [],
};
return {
addDestroyListenerCallback(destroyListenerCallback: () => void) {
state.destroyListenerCallbacks.push(destroyListenerCallback);
},
destroyAllListeners() {
if (!state.destroyListenerCallbacks.length) {
return;
}
state.destroyListenerCallbacks.forEach((destroyListenerCallback) => {
destroyListenerCallback();
});
},
};
};
export default createEventManagerService;

View File

@ -1,11 +1,7 @@
import releaseAction from './release-action';
import release from './release'; import release from './release';
import releaseValidation from './validation'; import releaseValidation from './validation';
import eventManager from './event-manager';
export const services = { export const services = {
release, release,
'release-action': releaseAction,
'release-validation': releaseValidation, 'release-validation': releaseValidation,
'event-manager': eventManager,
}; };

View File

@ -1,15 +0,0 @@
import type { LoadedStrapi } from '@strapi/types';
import { RELEASE_ACTION_MODEL_UID } from '../constants';
import type { ReleaseAction } from '../../../shared/contracts/release-actions';
const createReleaseActionService = ({ strapi }: { strapi: LoadedStrapi }) => ({
async deleteManyForContentType(contentTypeUid: ReleaseAction['contentType']) {
return strapi.db.query(RELEASE_ACTION_MODEL_UID).deleteMany({
where: {
target_type: contentTypeUid,
},
});
},
});
export default createReleaseActionService;

View File

@ -26,7 +26,7 @@ import type {
import type { Entity, UserInfo } from '../../../shared/types'; import type { Entity, UserInfo } from '../../../shared/types';
import { getService } from '../utils'; import { getService } from '../utils';
interface Locale extends Entity { export interface Locale extends Entity {
name: string; name: string;
code: string; code: string;
} }