Skip to content

Commit

Permalink
ENH Add Readonly field status
Browse files Browse the repository at this point in the history
  • Loading branch information
Sabina Talipova committed Jan 23, 2024
1 parent 483debe commit 6a80f83
Show file tree
Hide file tree
Showing 14 changed files with 81 additions and 87 deletions.
2 changes: 1 addition & 1 deletion client/dist/styles/bundle.css

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions client/src/components/LinkField/LinkField.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ const LinkField = ({
actions,
isMulti = false,
canCreate,
readonly,
ownerID,
ownerClass,
ownerRelation,
Expand Down Expand Up @@ -192,6 +193,7 @@ const LinkField = ({
isLast={i === linkIDs.length - 1}
isSorting={isSorting}
canCreate={canCreate}
readonly={readonly}
/>);
}
return links;
Expand Down Expand Up @@ -255,6 +257,7 @@ const LinkField = ({
onModalClosed={onModalClosed}
types={types}
canCreate={canCreate}
readonly={readonly}
/> }
{ isMulti && <div className={linksClassName}>
<DndContext modifiers={[restrictToVerticalAxis, restrictToParentElement]}
Expand Down Expand Up @@ -292,6 +295,7 @@ LinkField.propTypes = {
actions: PropTypes.object.isRequired,
isMulti: PropTypes.bool,
canCreate: PropTypes.bool.isRequired,
readonly: PropTypes.bool.isRequired,
ownerID: PropTypes.number.isRequired,
ownerClass: PropTypes.string.isRequired,
ownerRelation: PropTypes.string.isRequired,
Expand Down
1 change: 1 addition & 0 deletions client/src/components/LinkField/tests/LinkField-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ function makeProps(obj = {}) {
},
isMulti: false,
canCreate: true,
readonly: false,
ownerID: 123,
ownerClass: 'Page',
ownerRelation: 'MyRelation',
Expand Down
7 changes: 4 additions & 3 deletions client/src/components/LinkPicker/LinkPicker.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import LinkModalContainer from 'containers/LinkModalContainer';
/**
* Component which allows users to choose a type of link to create, and opens a modal form for it.
*/
const LinkPicker = ({ types, onModalSuccess, onModalClosed, canCreate }) => {
const LinkPicker = ({ types, onModalSuccess, onModalClosed, canCreate, readonly }) => {
const [typeKey, setTypeKey] = useState('');

/**
Expand Down Expand Up @@ -43,7 +43,7 @@ const LinkPicker = ({ types, onModalSuccess, onModalClosed, canCreate }) => {
const allowedTypes = typeArray.filter(type => type.allowed);
const message = i18n._t('LinkField.CANNOT_CREATE_LINK', 'Cannot create link');

if (!canCreate || allowedTypes.length === 0) {
if (!canCreate || allowedTypes.length === 0 || readonly) {
return (
<div className={className}>
<div className="link-picker__cannot-create">
Expand Down Expand Up @@ -72,7 +72,8 @@ LinkPicker.propTypes = {
types: PropTypes.object.isRequired,
onModalSuccess: PropTypes.func.isRequired,
onModalClosed: PropTypes.func,
canCreate: PropTypes.bool.isRequired
canCreate: PropTypes.bool.isRequired,
readonly: PropTypes.bool.isRequired,
};

export {LinkPicker as Component};
Expand Down
2 changes: 1 addition & 1 deletion client/src/components/LinkPicker/LinkPicker.scss
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@
display: none;
}

&.readonly {
&--readonly {
background-color: $gray-100;
}
}
Expand Down
6 changes: 4 additions & 2 deletions client/src/components/LinkPicker/LinkPickerTitle.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ const LinkPickerTitle = ({
isLast,
isSorting,
canCreate,
readonly,
}) => {
const { loading } = useContext(LinkFieldContext);
const {
Expand All @@ -66,7 +67,7 @@ const LinkPickerTitle = ({
'link-picker__link--is-last': isLast,
'link-picker__link--is-sorting': isSorting,
'form-control': true,
'readonly': !canCreate,
'link-picker__link--readonly': readonly || !canCreate,
};
if (versionState) {
classes[`link-picker__link--${versionState}`] = true;
Expand Down Expand Up @@ -95,7 +96,7 @@ const LinkPickerTitle = ({
</small>
</div>
</Button>
{(canDelete && canCreate) &&
{(canDelete && !readonly) &&
<Button disabled={loading} className="link-picker__delete" color="link" onClick={stopPropagation(() => onDelete(id))}>{deleteText}</Button>
}
</div>
Expand All @@ -116,6 +117,7 @@ LinkPickerTitle.propTypes = {
isLast: PropTypes.bool.isRequired,
isSorting: PropTypes.bool.isRequired,
canCreate: PropTypes.bool.isRequired,
readonly: PropTypes.bool.isRequired,
};

export default LinkPickerTitle;
1 change: 1 addition & 0 deletions client/src/components/LinkPicker/tests/LinkPicker-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ function makeProps(obj = {}) {
return {
types: { phone: { key: 'phone', title: 'Phone', icon: 'font-icon-phone', allowed: true } },
canCreate: true,
readonly: false,
onModalSuccess: () => {},
onModalClosed: () => {},
...obj
Expand Down
15 changes: 15 additions & 0 deletions client/src/components/LinkPicker/tests/LinkPickerTitle-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ function makeProps(obj = {}) {
typeIcon: 'font-icon-phone',
canDelete: true,
canCreate: true,
readonly: false,
onDelete: () => {},
onClick: () => {},
isMulti: false,
Expand Down Expand Up @@ -90,3 +91,17 @@ test('LinkPickerTitle main button should not fire the onClick callback while loa
fireEvent.click(container.querySelector('button.link-picker__button'));
expect(mockOnClick).toHaveBeenCalledTimes(0);
});

test('LinkPickerTitle render() should have readonly class if cannot edit', () => {
const { container } = render(<LinkFieldContext.Provider value={{ loading: false }}>
<LinkPickerTitle {...makeProps({ readonly: true })} />
</LinkFieldContext.Provider>);
expect(container.querySelectorAll('.link-picker__link--readonly')).toHaveLength(1);
});

test('LinkPickerTitle render() should not have readonly class if can edit', () => {
const { container } = render(<LinkFieldContext.Provider value={{ loading: false }}>
<LinkPickerTitle {...makeProps({ readonly: false })} />
</LinkFieldContext.Provider>);
expect(container.querySelectorAll('.link-picker__link--readonly')).toHaveLength(0);
});
1 change: 1 addition & 0 deletions client/src/entwine/LinkField.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ jQuery.entwine('ss', ($) => {
isMulti: this.data('is-multi') ?? false,
types: this.data('types') ?? {},
canCreate: inputField.data('can-create') ? true : false,
readonly: inputField.data('readonly') ? true : false,
};
},

Expand Down
44 changes: 32 additions & 12 deletions src/Controllers/LinkFieldController.php
Original file line number Diff line number Diff line change
Expand Up @@ -379,7 +379,7 @@ private function createLinkForm(Link $link, string $operation): Form
// Make readonly if fail can check
if ($operation === 'create' && !$link->canCreate()
|| $operation === 'edit' && !$link->canEdit()
|| $this->isReadOnlyField() && !$link->canEdit()
|| $this->isReadOnlyField()
) {
$form->makeReadonly();
}
Expand All @@ -395,12 +395,10 @@ private function createLinkForm(Link $link, string $operation): Form
*/
private function isReadOnlyField(): bool
{
$request = $this->getRequest();
$ownerClass = $request->getVar('ownerClass') ?: $request->postVar('OwnerClass');
$ownerClass = $this->getOwnerClassFromRequest();
$ownerRelation = $this->ownerRelationFromRequest();
$isReadOnly = Injector::inst()->get($ownerClass)->getCMSFields()->dataFieldByName($ownerRelation)?->isReadonly();

return $isReadOnly ?? false;
return (bool) Injector::inst()->get($ownerClass)->getCMSFields()->dataFieldByName($ownerRelation)?->isReadonly();
}

/**
Expand Down Expand Up @@ -485,20 +483,41 @@ private function typeKeyFromRequest(): string
}

/**
* Get the owner based on the query string params ownerID, ownerClass, ownerRelation
* OR the POST vars OwnerID, OwnerClass, OwnerRelation
* Get the owner class based on the query string param OwnerClass
*/
private function ownerFromRequest(): DataObject
private function getOwnerClassFromRequest(): string
{
$request = $this->getRequest();
$ownerID = (int) ($request->getVar('ownerID') ?: $request->postVar('OwnerID'));
if ($ownerID === 0) {
$this->jsonError(404, _t(__CLASS__ . '.INVALID_OWNER_ID', 'Invalid ownerID'));
}
$ownerClass = $request->getVar('ownerClass') ?: $request->postVar('OwnerClass');
if (!is_a($ownerClass, DataObject::class, true)) {
$this->jsonError(404, _t(__CLASS__ . '.INVALID_OWNER_CLASS', 'Invalid ownerClass'));
}

return $ownerClass;
}

/**
* Get the owner ID based on the query string param OwnerID
*/
private function getOwnerIDFromRequest(): int
{
$request = $this->getRequest();
$ownerID = (int) ($request->getVar('ownerID') ?: $request->postVar('OwnerID'));
if ($ownerID === 0) {
$this->jsonError(404, _t(__CLASS__ . '.INVALID_OWNER_ID', 'Invalid ownerID'));
}

return $ownerID;
}

/**
* Get the owner based on the query string params ownerID, ownerClass, ownerRelation
* OR the POST vars OwnerID, OwnerClass, OwnerRelation
*/
private function ownerFromRequest(): DataObject
{
$ownerID = $this->getOwnerIDFromRequest();
$ownerClass = $this->getOwnerClassFromRequest();
$ownerRelation = $this->ownerRelationFromRequest();
/** @var DataObject $obj */
$obj = Injector::inst()->get($ownerClass);
Expand Down Expand Up @@ -536,6 +555,7 @@ private function ownerRelationFromRequest(): string
if (!$ownerRelation) {
$this->jsonError(404, _t(__CLASS__ . '.INVALID_OWNER_RELATION', 'Invalid ownerRelation'));
}

return $ownerRelation;
}
}
16 changes: 8 additions & 8 deletions src/Form/LinkField.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,10 @@

namespace SilverStripe\LinkField\Form;

use LogicException;
use SilverStripe\Forms\FormField;
use SilverStripe\LinkField\Models\Link;
use SilverStripe\LinkField\Form\Traits\AllowedLinkClassesTrait;
use SilverStripe\LinkField\Form\Traits\LinkFieldGetOwnerTrait;
use SilverStripe\ORM\DataObject;
use SilverStripe\ORM\DataObjectInterface;

/**
* Allows CMS users to edit a Link object.
Expand Down Expand Up @@ -36,15 +33,17 @@ public function setValue($value, $data = null)
public function getSchemaStateDefaults()
{
$data = parent::getSchemaStateDefaults();
$data['canCreate'] = $this->getOwner()->canEdit() && !$this->isReadonly();
$data['canCreate'] = $this->getOwner()->canEdit();
$data['readonly'] = $this->isReadonly();
return $data;
}

protected function getDefaultAttributes(): array
{
$attributes = parent::getDefaultAttributes();
$attributes['data-value'] = $this->Value();
$attributes['data-can-create'] = $this->getOwner()->canEdit() && !$this->isReadonly();
$attributes['data-can-create'] = $this->getOwner()->canEdit();
$attributes['data-readonly'] = $this->isReadonly();
$ownerFields = $this->getOwnerFields();
$attributes['data-owner-id'] = $ownerFields['ID'];
$attributes['data-owner-class'] = $ownerFields['Class'];
Expand All @@ -63,13 +62,14 @@ public function getSchemaDataDefaults()
return $data;
}

/**
/**
* Changes this field to the readonly field.
*/
public function performReadonlyTransformation()
{
$copy = $this->castedCopy(LinkField_Readonly::class);
$clone = $this->castedCopy($this);
$clone->setReadonly(true);

return $copy;
return $clone;
}
}
27 changes: 0 additions & 27 deletions src/Form/LinkField_Readonly.php

This file was deleted.

15 changes: 9 additions & 6 deletions src/Form/MultiLinkField.php
Original file line number Diff line number Diff line change
Expand Up @@ -53,15 +53,17 @@ public function getSchemaStateDefaults()
{
$data = parent::getSchemaStateDefaults();
$data['value'] = $this->getValueArray();
$data['canCreate'] = $this->getOwner()->canEdit() && !$this->isReadonly();
$data['canCreate'] = $this->getOwner()->canEdit();
$data['readonly'] = $this->isReadonly();
return $data;
}

protected function getDefaultAttributes(): array
{
$attributes = parent::getDefaultAttributes();
$attributes['data-value'] = $this->getValueArray();
$attributes['data-can-create'] = $this->getOwner()->canEdit() && !$this->isReadonly();
$attributes['data-can-create'] = $this->getOwner()->canEdit();
$attributes['data-readonly'] = $this->isReadonly();
$ownerFields = $this->getOwnerFields();
$attributes['data-owner-id'] = $ownerFields['ID'];
$attributes['data-owner-class'] = $ownerFields['Class'];
Expand All @@ -72,7 +74,7 @@ protected function getDefaultAttributes(): array
/**
* Extracts the value of this field, normalised as a non-associative array.
*/
protected function getValueArray(): array
private function getValueArray(): array
{
return $this->convertValueToArray($this->Value());
}
Expand Down Expand Up @@ -156,13 +158,14 @@ private function loadFrom(DataObject $record): void
parent::setValue($value);
}

/**
/**
* Changes this field to the readonly field.
*/
public function performReadonlyTransformation()
{
$copy = $this->castedCopy(MultiLinkField_Readonly::class);
$clone = $this->castedCopy($this);
$clone->setReadonly(true);

return $copy;
return $clone;
}
}
27 changes: 0 additions & 27 deletions src/Form/MultiLinkField_Readonly.php

This file was deleted.

0 comments on commit 6a80f83

Please sign in to comment.