Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
5 changes: 5 additions & 0 deletions docs/docs/docs/01-core/admin/04-hooks/use-enterprise.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -54,3 +54,8 @@ if (!Component) {
return;
}
```

### `enabled`

Similar to react-query this boolean flag allows disabling the EE import, e.g. when more than one condition needs to be applied. If `enabled`
is set to false, the first argument (CE_DATA) will be returned.
Comment on lines +60 to +61
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

would a good example of this be where the EE addition is unique to a feature being enabled as opposed to EE in general?

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,22 +1,36 @@
import React from 'react';

import { BaseCheckbox, IconButton, Tbody, Td, Tr, Flex } from '@strapi/design-system';
import {
BaseCheckbox,
IconButton,
Tbody,
Td,
Tr,
Flex,
lightTheme,
Status,
Typography,
} from '@strapi/design-system';
import { useTracking, useFetchClient, useAPIErrorHandler } from '@strapi/helper-plugin';
import { Trash, Duplicate, Pencil } from '@strapi/icons';
import { AxiosError } from 'axios';
import PropTypes from 'prop-types';
import { useIntl } from 'react-intl';
import { Link, useHistory } from 'react-router-dom';

import { useEnterprise } from '../../../../../hooks/useEnterprise';
import { getFullName } from '../../../../../utils';
import { usePluginsQueryParams } from '../../../../hooks';
import { getTrad } from '../../../../utils';
import CellContent from '../CellContent';

const REVIEW_WORKFLOW_COLUMNS_CE = () => null;

export const TableRows = ({
canCreate,
canDelete,
contentType,
features: { hasDraftAndPublish, hasReviewWorkflows },
headers,
entriesToDelete,
onClickDelete,
Expand All @@ -33,6 +47,18 @@ export const TableRows = ({
const { trackUsage } = useTracking();
const pluginsQueryParams = usePluginsQueryParams();
const { formatAPIError } = useAPIErrorHandler(getTrad);
const ReviewWorkflowsStage = useEnterprise(
REVIEW_WORKFLOW_COLUMNS_CE,
async () =>
(
await import(
'../../../../../../../ee/admin/content-manager/pages/ListView/ReviewWorkflowsColumn'
)
).ReviewWorkflowsStageEE,
{
enabled: hasReviewWorkflows,
}
);

/**
*
Expand Down Expand Up @@ -74,6 +100,11 @@ export const TableRows = ({
}
};

// block rendering until the review stage component is fully loaded in EE
if (!ReviewWorkflowsStage) {
return null;
}

Comment on lines +104 to +107
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This won't block rednering on content-types that don't have review workflows enabled 🤔? Maybe also check hasReviewWorkflows?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In CE the component will be defined (so this condition won't match), but in EE ReviewWorkflowsStage can be null until the component has been loaded. We could handle this using a loading state, but in this instance I think it is better not to.

/**
* Table Cells with actions e.g edit, delete, duplicate have `stopPropagation`
* to prevent the row from being selected.
Expand Down Expand Up @@ -113,20 +144,59 @@ export const TableRows = ({
/>
</Td>
)}

{headers.map(({ key, cellFormatter, name, ...rest }) => {
if (hasDraftAndPublish && name === 'publishedAt') {
return (
<Td key={key}>
<Status
width="min-content"
showBullet={false}
variant={data.publishedAt ? 'success' : 'secondary'}
size="S"
>
<Typography
fontWeight="bold"
textColor={`${data.publishedAt ? 'success' : 'secondary'}700`}
>
{formatMessage({
id: getTrad(
`containers.List.${data.publishedAt ? 'published' : 'draft'}`
),
defaultMessage: data.publishedAt ? 'Published' : 'Draft',
})}
</Typography>
</Status>
</Td>
);
}

if (hasReviewWorkflows && name === 'strapi_reviewWorkflows_stage') {
return (
<Td key={key}>
{data.strapi_reviewWorkflows_stage ? (
<ReviewWorkflowsStage
color={
data.strapi_reviewWorkflows_stage.color ?? lightTheme.colors.primary600
}
name={data.strapi_reviewWorkflows_stage.name}
/>
) : (
<Typography textColor="neutral800">-</Typography>
)}
</Td>
);
}

return (
<Td key={key}>
{typeof cellFormatter === 'function' ? (
cellFormatter(data, { key, name, ...rest })
) : (
<CellContent
content={data[name.split('.')[0]]}
name={name}
contentType={contentType}
{...rest}
rowId={data.id}
/>
)}
<CellContent
content={data[name.split('.')[0]]}
name={name}
contentType={contentType}
{...rest}
rowId={data.id}
/>
</Td>
);
})}
Expand Down Expand Up @@ -212,6 +282,10 @@ TableRows.propTypes = {
uid: PropTypes.string.isRequired,
}).isRequired,
entriesToDelete: PropTypes.array,
features: PropTypes.shape({
hasDraftAndPublish: PropTypes.bool.isRequired,
hasReviewWorkflows: PropTypes.bool.isRequired,
}).isRequired,
headers: PropTypes.array.isRequired,
onClickDelete: PropTypes.func,
onSelectRow: PropTypes.func,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,6 @@ import {
HeaderLayout,
useNotifyAT,
Flex,
Typography,
Status,
} from '@strapi/design-system';
import {
NoPermissions,
Expand All @@ -33,7 +31,6 @@ import {
} from '@strapi/helper-plugin';
import { ArrowLeft, Cog, Plus } from '@strapi/icons';
import axios from 'axios';
import getReviewWorkflowsColumn from 'ee_else_ce/content-manager/components/DynamicTable/CellContent/ReviewWorkflowsStage/getTableColumn';
import isEqual from 'lodash/isEqual';
import PropTypes from 'prop-types';
import { stringify } from 'qs';
Expand All @@ -45,6 +42,7 @@ import { bindActionCreators, compose } from 'redux';
import styled from 'styled-components';

import { INJECT_COLUMN_IN_TABLE } from '../../../exposedHooks';
import { useEnterprise } from '../../../hooks/useEnterprise';
import { selectAdminPermissions } from '../../../pages/App/selectors';
import { InjectionZone } from '../../../shared/components';
import AttributeFilter from '../../components/AttributeFilter';
Expand All @@ -67,6 +65,8 @@ const ConfigureLayoutBox = styled(Box)`
}
`;

const REVIEW_WORKFLOW_COLUMNS_CE = null;

function ListView({
canCreate,
canDelete,
Expand Down Expand Up @@ -107,8 +107,24 @@ function ListView({
const { pathname } = useLocation();
const { push } = useHistory();
const { formatMessage } = useIntl();
const hasDraftAndPublish = options?.draftAndPublish || false;
const fetchClient = useFetchClient();

const hasDraftAndPublish = options?.draftAndPublish ?? false;
const hasReviewWorkflows = options?.reviewWorkflows ?? false;

const reviewWorkflowColumns = useEnterprise(
REVIEW_WORKFLOW_COLUMNS_CE,
async () =>
(
await import(
'../../../../../ee/admin/content-manager/pages/ListView/ReviewWorkflowsColumn/constants'
)
).REVIEW_WORKFLOW_COLUMNS_EE,
{
enabled: !!options?.reviewWorkflows,
}
);

const { post, del } = fetchClient;

const bulkPublishMutation = useMutation(
Expand Down Expand Up @@ -388,24 +404,8 @@ function ListView({
};
});

if (!hasDraftAndPublish) {
return formattedHeaders;
}

// this should not exist. Ideally we would use registerHook() similar to what has been done
// in the i18n plugin. In order to do that review-workflows should have been a plugin. In
// a future iteration we need to find a better pattern.

// In CE this will return null - in EE a column definition including the custom formatting component.
const reviewWorkflowColumn = getReviewWorkflowsColumn(layout);

if (reviewWorkflowColumn) {
formattedHeaders.push(reviewWorkflowColumn);
}

return [
...formattedHeaders,
{
if (hasDraftAndPublish) {
formattedHeaders.push({
key: '__published_at_temp_key__',
name: 'publishedAt',
fieldSchema: {
Expand All @@ -419,25 +419,29 @@ function ListView({
searchable: false,
sortable: true,
},
// eslint-disable-next-line react/no-unstable-nested-components
cellFormatter(cellData) {
const isPublished = cellData.publishedAt;
const variant = isPublished ? 'success' : 'secondary';

return (
<Status width="min-content" showBullet={false} variant={variant} size="S">
<Typography fontWeight="bold" textColor={`${variant}700`}>
{formatMessage({
id: getTrad(`containers.List.${isPublished ? 'published' : 'draft'}`),
defaultMessage: isPublished ? 'Published' : 'Draft',
})}
</Typography>
</Status>
);
},
},
];
}, [runHookWaterfall, displayedHeaders, layout, hasDraftAndPublish, formatMessage]);
});
}

if (reviewWorkflowColumns) {
// Make sure the column header label is translated
if (typeof reviewWorkflowColumns.metadatas.label !== 'string') {
reviewWorkflowColumns.metadatas.label = formatMessage(
reviewWorkflowColumns.metadatas.label
);
}

formattedHeaders.push(reviewWorkflowColumns);
}

return formattedHeaders;
}, [
runHookWaterfall,
displayedHeaders,
layout,
reviewWorkflowColumns,
hasDraftAndPublish,
formatMessage,
]);

const subtitle = canRead
? formatMessage(
Expand Down Expand Up @@ -580,6 +584,10 @@ function ListView({
canCreate={canCreate}
canDelete={canDelete}
contentType={contentType}
features={{
hasDraftAndPublish,
hasReviewWorkflows,
}}
headers={tableHeaders}
rows={data}
withBulkActions
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,14 @@ describe('useEnterprise (EE)', () => {
await waitFor(() => expect(result.current).toStrictEqual(EE_DATA_FIXTURE));
});

test('Returns CE data, when enabled is set to false', async () => {
const { result } = setup(CE_DATA_FIXTURE, async () => EE_DATA_FIXTURE, {
enabled: false,
});

await waitFor(() => expect(result.current).toStrictEqual(CE_DATA_FIXTURE));
});

test('Returns a custom defaultValue on first render followed by the EE data', async () => {
const { result } = setup(CE_DATA_FIXTURE, async () => EE_DATA_FIXTURE, {
defaultValue: false,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,15 @@ function isEnterprise() {
export function useEnterprise(
ceData,
eeCallback,
{ defaultValue = null, combine = (ceData, eeData) => eeData } = {}
{ defaultValue = null, combine = (ceData, eeData) => eeData, enabled = true } = {}
) {
const eeCallbackRef = useCallbackRef(eeCallback);
const combineCallbackRef = useCallbackRef(combine);

// We have to use a nested object here, because functions (e.g. Components)
// can not be stored as value directly
const [{ data }, setData] = React.useState({
data: isEnterprise() ? defaultValue : ceData,
data: isEnterprise() && enabled ? defaultValue : ceData,
});

React.useEffect(() => {
Expand All @@ -27,10 +27,10 @@ export function useEnterprise(
setData({ data: combineCallbackRef(ceData, eeData) });
}

if (isEnterprise()) {
if (isEnterprise() && enabled) {
importEE();
}
}, [ceData, eeCallbackRef, combineCallbackRef]);
}, [ceData, eeCallbackRef, combineCallbackRef, enabled]);

return data;
}
Loading