Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ENH Add campaign-admin support back in #1548

Open
wants to merge 1 commit into
base: 3.0
Choose a base branch
from
Open
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
2 changes: 1 addition & 1 deletion client/dist/js/TinyMCE_sslink-file.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion client/dist/js/TinyMCE_ssmedia.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion client/dist/js/bundle.js

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions client/src/containers/AssetAdmin/AssetAdmin.js
Original file line number Diff line number Diff line change
Expand Up @@ -742,6 +742,7 @@ class AssetAdmin extends Component {
onClose: this.handleCloseFile,
onSubmit: this.handleSubmitEditor,
onUnpublish: this.handleUnpublish,
addToCampaignSchemaUrl: config.form.addToCampaignForm.schemaUrl
};

return <EditorComponent {...editorProps} />;
Expand Down
3 changes: 3 additions & 0 deletions client/src/containers/AssetAdmin/tests/AssetAdmin-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,9 @@ function makeProps(obj = {}) {
fileSearchForm: {
schemaUrl: '',
},
addToCampaignForm: {
schemaUrl: '',
},
},
},
fileId: null,
Expand Down
36 changes: 35 additions & 1 deletion client/src/containers/Editor/Editor.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { bindActionCreators, compose } from 'redux';
import React, { Component } from 'react';
import CONSTANTS from 'constants/index';
import FormBuilderLoader from 'containers/FormBuilderLoader/FormBuilderLoader';
import FormBuilderModal from 'components/FormBuilderModal/FormBuilderModal';
import * as UnsavedFormsActions from 'state/unsavedForms/UnsavedFormsActions';
import PropTypes from 'prop-types';
import { inject } from 'lib/Injector';
Expand All @@ -31,10 +32,13 @@ class Editor extends Component {
this.handleLoadingSuccess = this.handleLoadingSuccess.bind(this);
this.handleLoadingError = this.handleLoadingError.bind(this);
this.handleFetchingSchema = this.handleFetchingSchema.bind(this);
this.closeModal = this.closeModal.bind(this);
this.openModal = this.openModal.bind(this);
this.createFn = this.createFn.bind(this);
this.editorHeader = this.editorHeader.bind(this);

this.state = {
openModal: false,
loadingForm: false,
loadingError: null,
file: null,
Expand Down Expand Up @@ -87,6 +91,12 @@ class Editor extends Component {
handleAction(event) {
const file = this.state.file;
switch (event.currentTarget.name) {
// intercept the Add to Campaign submit and open the modal dialog instead
case 'action_addtocampaign':
this.openModal();
event.preventDefault();

break;
case 'action_replacefile':
this.replaceFile();
event.preventDefault();
Expand Down Expand Up @@ -152,13 +162,22 @@ class Editor extends Component {
} else {
// If we're already at the top of the form stack, close the editor form
onClose();
this.closeModal();
}

if (event) {
event.preventDefault();
}
}

openModal() {
this.setState({ openModal: true });
}

closeModal() {
this.setState({ openModal: false });
}

replaceFile() {
const hiddenFileInput = document.querySelector('.dz-input-PreviewImage');

Expand Down Expand Up @@ -270,8 +289,9 @@ class Editor extends Component {
if (!this.state.file) {
return null;
}
const { FormBuilderLoaderComponent } = this.props;
const { FormBuilderLoaderComponent, FormBuilderModalComponent } = this.props;
const formSchemaUrl = this.getFormSchemaUrl();
const modalSchemaUrl = `${this.props.addToCampaignSchemaUrl}/${this.props.fileId}`;
const editorClasses = classnames(
'panel', 'form--no-dividers', 'editor', {
'editor--asset-dropzone--disable': !this.props.enableDropzone
Expand All @@ -291,6 +311,7 @@ class Editor extends Component {
<div className="editor__file-preview-message--file-missing">{message}</div>
);
}
const campaignTitle = i18n._t('Admin.ADD_TO_CAMPAIGN', 'Add to campaign');
const Loading = this.props.loadingComponent;

return (<div className={editorClasses}>
Expand All @@ -307,6 +328,16 @@ class Editor extends Component {
file={this.state.file}
/>
{error}
<FormBuilderModalComponent
title={campaignTitle}
identifier="AssetAdmin.AddToCampaign"
isOpen={this.state.openModal}
onClosed={this.closeModal}
schemaUrl={modalSchemaUrl}
bodyClassName="modal__dialog"
responseClassBad="modal__response modal__response--error"
responseClassGood="modal__response modal__response--good"
/>
{ this.state.loadingForm && <Loading />}
</div>
</div>);
Expand All @@ -325,16 +356,19 @@ Editor.propTypes = {
name: PropTypes.string,
value: PropTypes.any,
})),
addToCampaignSchemaUrl: PropTypes.string,
actions: PropTypes.object,
showingSubForm: PropTypes.bool,
nextType: PropTypes.string,
EditorHeaderComponent: PropTypes.oneOfType([PropTypes.object, PropTypes.func]),
FormBuilderLoaderComponent: PropTypes.oneOfType([PropTypes.object, PropTypes.func]),
FormBuilderModalComponent: PropTypes.oneOfType([PropTypes.object, PropTypes.func]),
};

Editor.defaultProps = {
EditorHeaderComponent: EditorHeader,
FormBuilderLoaderComponent: FormBuilderLoader,
FormBuilderModalComponent: FormBuilderModal,
};

function mapDispatchToProps(dispatch) {
Expand Down
36 changes: 26 additions & 10 deletions client/src/containers/Editor/tests/Editor-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -78,12 +78,20 @@ function makeProps(obj = {}) {
FormBuilderLoaderComponent: ({ createFn, onAction, schemaUrl }) => (
<div data-testid="test-form-builder-loader" onClick={() => onAction(...nextParams)} data-schema-url={schemaUrl}>{createFn(...createFnParams)}</div>
),
FormBuilderModalComponent: ({ isOpen }) => <div data-testid="test-form-builder-modal" data-is-open={isOpen}/>,
...obj
};
}

async function awaitLoader() {
await screen.findByTestId('test-form-builder-loader');
async function openModal() {
const loader = await screen.findByTestId('test-form-builder-loader');
nextParams = [{
preventDefault: () => null,
currentTarget: {
name: 'action_addtocampaign'
}
}];
fireEvent.click(loader);
nextParams = [{
preventDefault: () => null,
currentTarget: {
Expand All @@ -109,12 +117,16 @@ test('Editor handleClose Closing editor', async () => {
/>
);
resolveBackendGet(makeReadFileResponse());
awaitLoader();
openModal();
let modal = await screen.findByTestId('test-form-builder-modal');
expect(modal.getAttribute('data-is-open')).toBe('true');
const header = await screen.findByTestId('test-editor-header');
nextAction = 'cancel';
fireEvent.click(header);
expect(popFormStackEntry).not.toHaveBeenCalled();
expect(onClose).toHaveBeenCalled();
modal = await screen.findByTestId('test-form-builder-modal');
expect(modal.getAttribute('data-is-open')).toBe('false');
expect(header.getAttribute('data-show-button')).toBe(buttonStates.SWITCH);
});

Expand All @@ -135,12 +147,16 @@ test('Editor handleClose Closing sub form', async () => {
/>
);
resolveBackendGet(makeReadFileResponse());
awaitLoader();
openModal();
let modal = await screen.findByTestId('test-form-builder-modal');
expect(modal.getAttribute('data-is-open')).toBe('true');
const header = await screen.findByTestId('test-editor-header');
nextAction = 'cancel';
fireEvent.click(header);
expect(popFormStackEntry).toHaveBeenCalled();
expect(onClose).not.toHaveBeenCalled();
modal = await screen.findByTestId('test-form-builder-modal');
expect(modal.getAttribute('data-is-open')).toBe('true');
expect(header.getAttribute('data-show-button')).toBe(buttonStates.SWITCH);
});

Expand Down Expand Up @@ -173,7 +189,7 @@ test('Editor editorHeader Top Form with detail in dialog', async () => {
/>
);
resolveBackendGet(makeReadFileResponse());
awaitLoader();
openModal();
const header = await screen.findByTestId('test-editor-header');
nextAction = 'details';
fireEvent.click(header);
Expand All @@ -192,7 +208,7 @@ test('Editor editorHeader Sub form in dialog', async () => {
/>
);
resolveBackendGet(makeReadFileResponse());
awaitLoader();
openModal();
const header = await screen.findByTestId('test-editor-header');
expect(header.getAttribute('data-show-button')).toBe(buttonStates.ALWAYS_BACK);
});
Expand All @@ -212,7 +228,7 @@ test('Editor editorHeader Form for folder', async () => {
type: 'folder',
})
});
awaitLoader();
openModal();
const header = await screen.findByTestId('test-editor-header');
expect(header.getAttribute('data-show-button')).toBe(buttonStates.SWITCH);
});
Expand All @@ -226,7 +242,7 @@ test('Editor getFormSchemaUrl Plain URL', async () => {
/>
);
resolveBackendGet(makeReadFileResponse());
awaitLoader();
openModal();
const loader = await screen.findByTestId('test-form-builder-loader');
expect(loader.getAttribute('data-schema-url')).toBe('edit/file/123');
});
Expand All @@ -240,7 +256,7 @@ test('Editor getFormSchemaUrl Plain URL', async () => {
/>
);
resolveBackendGet(makeReadFileResponse());
awaitLoader();
openModal();
const loader = await screen.findByTestId('test-form-builder-loader');
expect(loader.getAttribute('data-schema-url')).toBe('edit/file/123?q=search');
});
Expand All @@ -257,7 +273,7 @@ test('Editor getFormSchemaUrl Plain URL', async () => {
/>
);
resolveBackendGet(makeReadFileResponse());
awaitLoader();
openModal();
const loader = await screen.findByTestId('test-form-builder-loader');
expect(loader.getAttribute('data-schema-url')).toBe('edit/file/123?q=search&foo=bar');
});
3 changes: 2 additions & 1 deletion code/Controller/AssetAdmin.php
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
use SilverStripe\ORM\DataList;
use SilverStripe\Forms\DateField;
use SilverStripe\ORM\DataQuery;
use SilverStripe\Core\ArrayLib;

/**
* AssetAdmin is the 'file store' section of the CMS.
Expand Down Expand Up @@ -212,7 +213,7 @@ public function getClientConfig(): array

$parentClientConfig = parent::getClientConfig();
$modalController = ModalController::singleton();
return array_merge($parentClientConfig, [
return ArrayLib::array_merge_recursive($parentClientConfig, [
Comment on lines -215 to +216
Copy link
Member

Choose a reason for hiding this comment

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

What's this change for?

Copy link
Member Author

Choose a reason for hiding this comment

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

That 'form.addToCampaignUrl' added in AddToCampaignExtension::updateClientConfig() isn't overridden - this method is calling parent::getClientConfig(); before updating $parentClientConfig()

'reactRouter' => true,
'bustCache' => static::config()->get('bust_cache'),
'endpoints' => array_merge($parentClientConfig['endpoints'], [
Expand Down
48 changes: 46 additions & 2 deletions tests/php/Forms/FileFormBuilderTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
use SilverStripe\Core\Config\Config;
use SilverStripe\Dev\SapphireTest;
use SilverStripe\Forms\LiteralField;
use SilverStripe\CampaignAdmin\Extensions\FileFormFactoryExtension;

class FileFormBuilderTest extends SapphireTest
{
Expand Down Expand Up @@ -51,6 +52,9 @@ protected function tearDown(): void

public function testEditFileForm()
{
// Ensure campaign-admin extension is not applied!
Config::modify()->remove(FileFormFactory::class, 'extensions');

$this->logInWithPermission('ADMIN');

$file = $this->objFromFixture(File::class, 'file1');
Expand Down Expand Up @@ -91,14 +95,37 @@ public function testEditFileForm()
$this->assertNotNull($form->Actions()->fieldByName('PopoverActions.action_replacefile'));
$this->assertNotNull($form->Actions()->fieldByName('PopoverActions.action_delete'));
$this->assertNull($form->Actions()->fieldByName('PopoverActions.action_unpublish'));

if (class_exists(FileFormFactoryExtension::class)) {
// Add to campaign should not be there by default
$this->assertNull($form->Actions()->fieldByName('PopoverActions.action_addtocampaign'));

// Add extension for campaign-admin
Config::modify()->merge(
FileFormFactory::class,
'extensions',
[FileFormFactoryExtension::class]
);

$builder = new FileFormFactory();
$form = $builder->getForm($controller, 'EditForm', ['Record' => $file, 'RequireLinkText' => false]);

// Add to campaign should now be available
$this->assertNotNull($form->Actions()->fieldByName('PopoverActions.action_addtocampaign'));
}
}

public function testEditFileFormWithPermissions()
{
// Add extension to simulate different permissions
File::add_extension(FileExtension::class);

$this->logInWithPermission('CMS_ACCESS_AssetAdmin');
if (class_exists(FileFormFactoryExtension::class)) {
FileFormFactory::add_extension(FileFormFactoryExtension::class);
$this->logInWithPermission('CMS_ACCESS_CampaignAdmin');
} else {
$this->logInWithPermission('CMS_ACCESS_AssetAdmin');
}

/** @var File $file */
$file = $this->objFromFixture(File::class, 'file1');
Expand All @@ -112,7 +139,9 @@ public function testEditFileFormWithPermissions()
$this->assertNull($form->Actions()->fieldByName('PopoverActions'));
$this->assertNull($form->Actions()->fieldByName('PopoverActions.action_delete'));
$this->assertNull($form->Actions()->fieldByName('PopoverActions.action_replacefile'));

if (class_exists(FileFormFactoryExtension::class)) {
$this->assertNull($form->Actions()->fieldByName('PopoverActions.action_addtocampaign'));
}
$this->assertNull($form->Actions()->fieldByName('PopoverActions.action_unpublish'));

FileExtension::$canDelete = false;
Expand All @@ -121,6 +150,9 @@ public function testEditFileFormWithPermissions()
$form = $builder->getForm($controller, 'EditForm', ['Record' => $file, 'RequireLinkText' => false]);
$this->assertNull($form->Actions()->fieldByName('PopoverActions.action_delete'));
$this->assertNull($form->Actions()->fieldByName('PopoverActions.action_replacefile'));
if (class_exists(FileFormFactoryExtension::class)) {
$this->assertNotNull($form->Actions()->fieldByName('PopoverActions.action_addtocampaign'));
}
$this->assertNull($form->Actions()->fieldByName('PopoverActions.action_unpublish'));

FileExtension::$canDelete = true;
Expand All @@ -129,6 +161,9 @@ public function testEditFileFormWithPermissions()
$form = $builder->getForm($controller, 'EditForm', ['Record' => $file]);
$this->assertNotNull($form->Actions()->fieldByName('PopoverActions.action_delete'));
$this->assertNull($form->Actions()->fieldByName('PopoverActions.action_replacefile'));
if (class_exists(FileFormFactoryExtension::class)) {
$this->assertNull($form->Actions()->fieldByName('PopoverActions.action_addtocampaign'));
}
$this->assertNull($form->Actions()->fieldByName('PopoverActions.action_unpublish'));

FileExtension::$canDelete = false;
Expand All @@ -137,6 +172,9 @@ public function testEditFileFormWithPermissions()
$form = $builder->getForm($controller, 'EditForm', ['Record' => $file]);
$this->assertNull($form->Actions()->fieldByName('PopoverActions.action_delete'));
$this->assertNotNull($form->Actions()->fieldByName('PopoverActions.action_replacefile'));
if (class_exists(FileFormFactoryExtension::class)) {
$this->assertNull($form->Actions()->fieldByName('PopoverActions.action_addtocampaign'));
}
$this->assertNull($form->Actions()->fieldByName('PopoverActions.action_unpublish'));

FileExtension::$canDelete = true;
Expand All @@ -147,8 +185,14 @@ public function testEditFileFormWithPermissions()
$form = $builder->getForm($controller, 'EditForm', ['Record' => $file, 'RequireLinkText' => false]);
$this->assertNotNull($form->Actions()->fieldByName('PopoverActions.action_delete'));
$this->assertNotNull($form->Actions()->fieldByName('PopoverActions.action_replacefile'));
if (class_exists(FileFormFactoryExtension::class)) {
$this->assertNotNull($form->Actions()->fieldByName('PopoverActions.action_addtocampaign'));
}
$this->assertNotNull($form->Actions()->fieldByName('PopoverActions.action_unpublish'));

if (class_exists(FileFormFactoryExtension::class)) {
FileFormFactory::remove_extension(FileFormFactoryExtension::class);
}
File::remove_extension(FileExtension::class);
}

Expand Down
3 changes: 3 additions & 0 deletions tests/php/Forms/FolderCreateFormFactoryTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ class FolderCreateFormFactoryTest extends SapphireTest
{
public function testEditFileForm()
{
// Ensure campaign-admin extension is not applied!
Config::modify()->remove(FileFormFactory::class, 'extensions');

$this->logInWithPermission('ADMIN');

$controller = new AssetAdmin();
Expand Down
Loading