Skip to content

Commit

Permalink
Merge branch 'release/4.7.2' into main
Browse files Browse the repository at this point in the history
  • Loading branch information
brandonkelly committed Feb 7, 2024
2 parents 887b4ca + 723a228 commit cf03b11
Show file tree
Hide file tree
Showing 25 changed files with 148 additions and 107 deletions.
11 changes: 11 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,16 @@
# Release Notes for Craft CMS 4

## 4.7.2 - 2024-02-07

- It’s now possible to select the temp asset volume within Assets fields, if the temp upload location includes a subpath. ([#14246](https://github.com/craftcms/cms/pull/14246))
- Fixed a bug where it wasn’t possible to set the “Formatting Locale” user preference back to “Same as language” once another value had been selected.
- Fixed a bug where layout components provided by disabled plugins weren’t getting omitted. ([#14236](https://github.com/craftcms/cms/pull/14236))
- Fixed a bug where “Move to the left” and “Move to the right” actions within field layout designers weren’t always getting enabled when they should, if a new tab was added.
- Fixed a bug where “Move to the left” and “Move to the right” actions within field layout designers were labelled incorrectly for right-to-left languages.
- Fixed a bug where users with “Create entries” permission but not “Delete entries” weren’t allowed to delete their own unpublished drafts. ([#14294](https://github.com/craftcms/cms/issues/14294))
- Fixed a bug where Yii-provided Chinese translations weren’t getting picked up in the control panel. ([#14287](https://github.com/craftcms/cms/issues/14287))
- Fixed an alignment bug with sortable structure views. ([#14299](https://github.com/craftcms/cms/issues/14299))

## 4.7.1 - 2024-01-29

- Unpublished drafts no longer show “Created at” or “Updated at” metadata values. ([#14204](https://github.com/craftcms/cms/issues/14204))
Expand Down
23 changes: 10 additions & 13 deletions packages/craftcms-vue/admintable/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -104,21 +104,19 @@
</template>
<template slot="title" slot-scope="props">
<span
v-if="props.rowData.status !== undefined"
v-if="props.rowData.status"
class="status"
:class="{enabled: props.rowData.status}"
></span>
<a
:class="{'cell-bold': props.rowData.status === undefined}"
:class="{'cell-bold': !props.rowData.status}"
v-if="props.rowData.url"
:href="props.rowData.url"
>{{ props.rowData.title }}</a
>
<span
:class="{'cell-bold': props.rowData.status === undefined}"
v-else
>{{ props.rowData.title }}</span
>
<span :class="{'cell-bold': !props.rowData.status}" v-else>{{
props.rowData.title
}}</span>
</template>

<template slot="handle" slot-scope="props">
Expand All @@ -134,7 +132,7 @@
}}<template
v-if="
props.rowData.menu.showCount ||
props.rowData.menu.showCount === undefined
typeof props.rowData.menu.showCount === 'undefined'
"
>
({{ props.rowData.menu.items.length }})</template
Expand Down Expand Up @@ -172,8 +170,7 @@
@click="handleDetailRow(props.rowData.id)"
v-if="
props.rowData.detail.content &&
(!props.rowData.detail.handle ||
props.rowData.detail.handle == undefined) &&
!props.rowData.detail.handle &&
(Object.keys(props.rowData.detail.content).length ||
props.rowData.detail.content.length)
"
Expand Down Expand Up @@ -202,7 +199,7 @@
v-on:finishloading="loading(false)"
v-on:reload="remove(props.rowIndex, props.rowData.id)"
v-if="
props.rowData._showDelete == undefined ||
typeof props.rowData._showDelete === 'undefined' ||
props.rowData._showDelete == true
"
></admin-table-delete-button>
Expand Down Expand Up @@ -830,8 +827,8 @@
canReorder() {
if (
this.$refs.vuetable == undefined ||
this.$refs.vuetable.tableData == undefined
typeof this.$refs.vuetable === 'undefined' ||
typeof this.$refs.vuetable.tableData === 'undefined'
) {
return false;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@
:class="{
...(act.class ? act.class : {}),
...{
error: act.error !== undefined && act.error,
error: act.error,
disabled:
act.allowMultiple !== undefined &&
!act.allowMultiple &&
Expand All @@ -53,7 +53,7 @@
:data-ajax="act.ajax"
@click.prevent="
!(
act.allowMultiple !== undefined &&
typeof act.allowMultiple !== 'undefined' &&
!act.allowMultiple &&
hasMultipleSelected
)
Expand Down Expand Up @@ -136,7 +136,7 @@
this.$emit('click', param, value, action, ajax);
// Is the action button the one to deal with the click?
if (handleClick !== undefined && !handleClick) {
if (typeof handleClick !== 'undefined' && !handleClick) {
return;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,26 +35,23 @@
computed: {
success() {
var successMessage =
this.successMessage !== undefined
? Craft.t('site', this.successMessage, {name: this.name})
: Craft.t('app', '“{name}” deleted.', {name: this.name});
var successMessage = this.successMessage
? Craft.t('site', this.successMessage, {name: this.name})
: Craft.t('app', '“{name}” deleted.', {name: this.name});
return Craft.escapeHtml(successMessage);
},
confirm() {
var confirmationMessage =
this.confirmationMessage !== undefined
? Craft.t('site', this.confirmationMessage, {name: this.name})
: Craft.t('app', 'Are you sure you want to delete “{name}”?', {
name: this.name,
});
var confirmationMessage = this.confirmationMessage
? Craft.t('site', this.confirmationMessage, {name: this.name})
: Craft.t('app', 'Are you sure you want to delete “{name}”?', {
name: this.name,
});
return Craft.escapeHtml(confirmationMessage);
},
failed() {
var failMessage =
this.failMessage !== undefined
? Craft.t('site', this.failMessage, {name: this.name})
: Craft.t('app', 'Couldn’t delete “{name}”.', {name: this.name});
var failMessage = this.failMessage
? Craft.t('site', this.failMessage, {name: this.name})
: Craft.t('app', 'Couldn’t delete “{name}”.', {name: this.name});
return Craft.escapeHtml(failMessage);
},
},
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
<template>
<div>
<div
v-if="
rowData.detail.content &&
(!rowData.detail.showAsList || rowData.detail.showAsList === undefined)
"
v-if="rowData.detail.content && !rowData.detail.showAsList"
v-html="rowData.detail.content"
></div>
<div v-if="rowData.detail.content && rowData.detail.showAsList">
Expand Down
2 changes: 2 additions & 0 deletions src/base/ApplicationTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
use craft\i18n\Formatter;
use craft\i18n\I18N;
use craft\i18n\Locale;
use craft\log\Dispatcher;
use craft\mail\Mailer;
use craft\markdown\GithubMarkdown;
use craft\markdown\Markdown;
Expand Down Expand Up @@ -199,6 +200,7 @@
* @property-read string $installedSchemaVersion The installed schema version
* @method AssetManager getAssetManager() Returns the asset manager component.
* @method Connection getDb() Returns the database connection component.
* @method Dispatcher getLog() Returns the log dispatcher component.
* @method Formatter getFormatter() Returns the formatter component.
* @method I18N getI18n() Returns the internationalization (i18n) component.
* @method Security getSecurity() Returns the security component.
Expand Down
2 changes: 1 addition & 1 deletion src/config/app.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
return [
'id' => 'CraftCMS',
'name' => 'Craft CMS',
'version' => '4.7.1',
'version' => '4.7.2',
'schemaVersion' => '4.5.3.0',
'minVersionRequired' => '3.7.11',
'basePath' => dirname(__DIR__), // Defines the @app alias
Expand Down
8 changes: 6 additions & 2 deletions src/controllers/UsersController.php
Original file line number Diff line number Diff line change
Expand Up @@ -1143,7 +1143,7 @@ public function actionEditUser(mixed $userId = null, ?User $user = null, ?array
ArrayHelper::multisort($allLocales, fn(Locale $locale) => $locale->getDisplayName());

$localeOptions = [
['label' => Craft::t('app', 'Same as language'), 'value' => ''],
['label' => Craft::t('app', 'Same as language'), 'value' => '__blank__'],
];
array_push($localeOptions, ...array_map(fn(Locale $locale) => [
'label' => $locale->getDisplayName(Craft::$app->language),
Expand Down Expand Up @@ -1484,9 +1484,13 @@ public function actionSaveUser(): ?Response

if ($isCurrentUser) {
// Save their preferences too
$preferredLocale = $this->request->getBodyParam('preferredLocale', $user->getPreference('locale')) ?: null;
if ($preferredLocale === '__blank__') {
$preferredLocale = null;
}
$preferences = [
'language' => $this->request->getBodyParam('preferredLanguage', $user->getPreference('language')),
'locale' => $this->request->getBodyParam('preferredLocale', $user->getPreference('locale')) ?: null,
'locale' => $preferredLocale,
'weekStartDay' => $this->request->getBodyParam('weekStartDay', $user->getPreference('weekStartDay')),
'alwaysShowFocusRings' => (bool)$this->request->getBodyParam('alwaysShowFocusRings', $user->getPreference('alwaysShowFocusRings')),
'useShapes' => (bool)$this->request->getBodyParam('useShapes', $user->getPreference('useShapes')),
Expand Down
2 changes: 1 addition & 1 deletion src/elements/Entry.php
Original file line number Diff line number Diff line change
Expand Up @@ -1438,7 +1438,7 @@ public function canDelete(User $user): bool
return true;
}

if ($this->getIsDraft() && $this->getIsDerivative()) {
if ($this->getIsDraft()) {
/** @var static|DraftBehavior $this */
return (
$this->creatorId === $user->id ||
Expand Down
47 changes: 34 additions & 13 deletions src/fields/Assets.php
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,14 @@ protected function defineRules(): array
];

$rules[] = [
['sources', 'defaultUploadLocationSource', 'restrictedLocationSource'], 'validateNotTempVolume',
[
'sources',
'defaultUploadLocationSource',
'restrictedLocationSource',
'defaultUploadLocationSubpath',
'restrictedLocationSubpath',
],
'validateNotTempVolume',
];

$rules[] = [['previewMode'], 'in', 'range' => [self::PREVIEW_MODE_FULL, self::PREVIEW_MODE_THUMBS], 'skipOnEmpty' => false];
Expand All @@ -255,18 +262,32 @@ protected function defineRules(): array
*/
public function validateNotTempVolume(string $attribute): void
{
[$tempVolume] = Craft::$app->getAssets()->getTempVolumeAndSubpath();
[$tempVolume, $tempSubpath] = Craft::$app->getAssets()->getTempVolumeAndSubpath();
if ($tempVolume !== null) {
$tempVolumeKey = "volume:$tempVolume->uid";
$inputSources = $this->getInputSources();

if (
(in_array($attribute, ['source', 'sources']) && in_array($tempVolumeKey, $inputSources)) ||
($attribute == 'defaultUploadLocationSource' && $this->defaultUploadLocationSource === $tempVolumeKey) ||
($attribute == 'restrictedLocationSource' && $this->restrictedLocationSource === $tempVolumeKey)
) {
// intentionally not translating this since it's short-lived (>= 4.7, < 5.0) and dev-facing only.
$this->addError($attribute, "Volume “{$tempVolume->name}” is used to store temporary asset uploads, so it cannot be used in an Assets field.");
if (empty($tempSubpath)) {
if (
(in_array($attribute, ['source', 'sources']) && in_array($tempVolumeKey, $inputSources)) ||
($attribute == 'defaultUploadLocationSource' && $this->defaultUploadLocationSource === $tempVolumeKey) ||
($attribute == 'restrictedLocationSource' && $this->restrictedLocationSource === $tempVolumeKey)
) {
// intentionally not translating this since it's short-lived (>= 4.7, < 5.0) and dev-facing only.
$this->addError($attribute, "Temporary asset uploads are being stored in $tempVolume->name, so the same volume cannot be used by an Assets field.");
}
} else {
if (
($attribute == 'defaultUploadLocationSource' &&
$this->defaultUploadLocationSource === $tempVolumeKey &&
$this->defaultUploadLocationSubpath == $tempSubpath) ||
($attribute == 'restrictedLocationSource' &&
$this->restrictedLocationSource === $tempVolumeKey &&
$this->restrictedLocationSubpath == $tempSubpath)
) {
// intentionally not translating this since it's short-lived (>= 4.7, < 5.0) and dev-facing only.
$this->addError($attribute, "Temporary asset uploads are being stored in $tempVolume->name/$tempSubpath, so the same location cannot be used by an Assets field.");
}
}
}
}
Expand All @@ -278,15 +299,15 @@ public function getSourceOptions(): array
{
$sourceOptions = [];
/** @var Volume|null $tempVolume */
[$tempVolume] = Craft::$app->getAssets()->getTempVolumeAndSubpath();
[$tempVolume, $tempSubpath] = Craft::$app->getAssets()->getTempVolumeAndSubpath();
if ($tempVolume) {
$tempVolumeKey = 'volume:' . $tempVolume->uid;
} else {
$tempVolumeKey = null;
}

foreach (Asset::sources('settings') as $volume) {
if ($tempVolumeKey !== null && $volume['key'] === $tempVolumeKey) {
if ($tempVolumeKey !== null && $volume['key'] === $tempVolumeKey && empty($tempSubpath)) {
// only allow it if already selected
if (
(!is_array($this->sources) || !in_array($tempVolumeKey, $this->sources)) &&
Expand Down Expand Up @@ -715,13 +736,13 @@ public function getInputSources(?ElementInterface $element = null): array|string
$sources = array_merge($this->sources);
} else {
$sources = [];
[$tempVolume] = Craft::$app->getAssets()->getTempVolumeAndSubpath();
[$tempVolume, $tempSubpath] = Craft::$app->getAssets()->getTempVolumeAndSubpath();
$tempVolumeKey = $tempVolume ? "volume:$tempVolume->uid" : null;

foreach (Craft::$app->getElementSources()->getSources(Asset::class) as $source) {
if (
$source['type'] !== ElementSources::TYPE_HEADING &&
$source['key'] !== $tempVolumeKey
($source['key'] !== $tempVolumeKey || !empty($tempSubpath))
) {
$sources[] = $source['key'];
}
Expand Down
2 changes: 1 addition & 1 deletion src/fields/BaseOptionsField.php
Original file line number Diff line number Diff line change
Expand Up @@ -323,7 +323,7 @@ public function normalizeValue(mixed $value, ?ElementInterface $element = null):
$value = Json::decodeIfJson($value);
} elseif ($value === '' && $this->multi) {
$value = [];
} elseif ($value === '__BLANK__') {
} elseif (strtolower($value) === '__blank__') {
$value = '';
} elseif ($value === null && $this->isFresh($element)) {
$value = $this->defaultValue();
Expand Down
4 changes: 2 additions & 2 deletions src/fields/Country.php
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ public static function valueType(): string
*/
public function normalizeValue(mixed $value, ElementInterface $element = null): mixed
{
return !in_array($value, ['', '__BLANK__']) ? $value : null;
return !in_array(strtolower($value), ['', '__blank__']) ? $value : null;
}

/**
Expand All @@ -52,7 +52,7 @@ public function normalizeValue(mixed $value, ElementInterface $element = null):
protected function inputHtml(mixed $value, ?ElementInterface $element = null): string
{
$options = Craft::$app->getAddresses()->getCountryRepository()->getList(Craft::$app->language);
array_unshift($options, ['label' => '', 'value' => '__BLANK__']);
array_unshift($options, ['label' => ' ', 'value' => '__blank__']);

return Cp::selectizeHtml([
'id' => $this->getInputId(),
Expand Down
9 changes: 6 additions & 3 deletions src/fields/Dropdown.php
Original file line number Diff line number Diff line change
Expand Up @@ -86,9 +86,12 @@ private function inputHtmlInternal(mixed $value, ?ElementInterface $element, boo
$hasBlankOption = false;
foreach ($options as &$option) {
if (isset($option['value']) && $option['value'] === '') {
$option['value'] = '__BLANK__';
$option['value'] = '__blank__';
$hasBlankOption = true;
}
if (isset($option['label']) && $option['label'] === '') {
$option['label'] = ' ';
}
}

if (!$value->valid) {
Expand All @@ -104,7 +107,7 @@ private function inputHtmlInternal(mixed $value, ?ElementInterface $element, boo

// Add a blank option to the beginning if one doesn't already exist
if (!$hasBlankOption) {
array_unshift($options, ['label' => '', 'value' => '__BLANK__']);
array_unshift($options, ['label' => ' ', 'value' => '__blank__']);
}
}
}
Expand All @@ -122,7 +125,7 @@ private function inputHtmlInternal(mixed $value, ?ElementInterface $element, boo
protected function encodeValue(MultiOptionsFieldData|OptionData|string|null $value): string|array|null
{
$encValue = parent::encodeValue($value);
return $encValue === null || $encValue === '' ? '__BLANK__' : $encValue;
return $encValue === null || $encValue === '' ? '__blank__' : $encValue;
}

/**
Expand Down
1 change: 0 additions & 1 deletion src/i18n/PhpMessageSource.php
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,6 @@ protected function getMessageFilePath($category, $language): string
'de-CH' => 'de',
'fr-CA' => 'fr',
'nb', 'nn' => 'nb-NO',
'zh' => 'zh-CN',
default => $language,
};
}
Expand Down
9 changes: 7 additions & 2 deletions src/models/FieldLayoutTab.php
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,7 @@ public function getElements(): array
public function setElements(array $elements): void
{
$fieldsService = Craft::$app->getFields();
$pluginsService = Craft::$app->getPlugins();
$this->_elements = [];

foreach ($elements as $layoutElement) {
Expand All @@ -296,8 +297,12 @@ public function setElements(array $elements): void
}
}

$layoutElement->setLayout($this->getLayout());
$this->_elements[] = $layoutElement;
// if layout element belongs to a plugin, ensure the plugin is installed
$pluginHandle = $pluginsService->getPluginHandleByClass($layoutElement::class);
if ($pluginHandle === null || $pluginsService->isPluginEnabled($pluginHandle)) {
$layoutElement->setLayout($this->getLayout());
$this->_elements[] = $layoutElement;
}
}
}

Expand Down
Loading

0 comments on commit cf03b11

Please sign in to comment.