Skip to content

Commit

Permalink
Merge pull request #13237 from craftcms/feature/source-path-keys--v3
Browse files Browse the repository at this point in the history
Feature/source path keys  v3
  • Loading branch information
brandonkelly committed May 23, 2023
2 parents ddc6e4e + f19a054 commit b1794fc
Show file tree
Hide file tree
Showing 12 changed files with 154 additions and 12 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Expand Up @@ -2,6 +2,8 @@

## Unreleased

- Asset indexes now remember their previously-selected source path. ([#13147](https://github.com/craftcms/cms/issues/13147))
- Added `craft\base\ElementInterface::sourcePath()`.
- Improved `craft\helpers\FileHelper::getExtensionByMimeType()` for some ambiguous, web-friendly MIME types.
- Removed the OAuth 2.0 Client library, as it’s no longer used in core.
- Fixed a bug where activation emails sent to newly-created users could link to the front-end site, if they were granted control panel access via a user group. ([#13204](https://github.com/craftcms/cms/issues/13204))
Expand Down
8 changes: 8 additions & 0 deletions src/base/Element.php
Expand Up @@ -684,6 +684,14 @@ public static function findSource(string $sourceKey, ?string $context = null): ?
return null;
}

/**
* @inheritdoc
*/
public static function sourcePath(string $sourceKey, string $stepKey, ?string $context): ?array
{
return null;
}

/**
* @inheritdoc
* @since 3.5.0
Expand Down
11 changes: 11 additions & 0 deletions src/base/ElementInterface.php
Expand Up @@ -293,6 +293,17 @@ public static function sources(string $context = null): array;
*/
public static function findSource(string $sourceKey, ?string $context = null): ?array;

/**
* Returns the source path for a given source key, step key, and context.
*
* @param string $sourceKey
* @param string $stepKey
* @param string|null $context
* @return array[]|null
* @since 3.8.12
*/
public static function sourcePath(string $sourceKey, string $stepKey, ?string $context): ?array;

/**
* Returns all of the field layouts associated with elements from the given source.
*
Expand Down
18 changes: 18 additions & 0 deletions src/controllers/ElementIndexesController.php
Expand Up @@ -128,6 +128,24 @@ public function getElementQuery(): ElementQueryInterface
return $this->elementQuery;
}

/**
* Returns the source path for the given source key, step key, and context.
*
* @since 3.8.12
*/
public function actionSourcePath(): Response
{
/** @var string|ElementInterface $elementType */
$elementType = $this->elementType;
$stepKey = $this->request->getRequiredBodyParam('stepKey');
$sourcePath = $elementType::sourcePath($this->sourceKey, $stepKey, $this->context);

return $this->asJson([
'sourcePath' => $sourcePath,
]);
}


/**
* Renders and returns an element index container, plus its first batch of elements.
*
Expand Down
22 changes: 22 additions & 0 deletions src/elements/Asset.php
Expand Up @@ -335,6 +335,28 @@ public static function findSource(string $sourceKey, ?string $context = null): ?
return null;
}

public static function sourcePath(string $sourceKey, string $stepKey, ?string $context): ?array
{
if (!preg_match('/^folder:([\w\-]+)$/', $stepKey, $match)) {
return null;
}

$folder = Craft::$app->getAssets()->getFolderByUid($match[1]);

if (!$folder) {
return null;
}

$path = [$folder->getSourcePathInfo()];

while ($parent = $folder->getParent()) {
array_unshift($path, $parent->getSourcePathInfo());
$folder = $parent;
}

return $path;
}

/**
* @inheritdoc
* @since 3.5.0
Expand Down
1 change: 1 addition & 0 deletions src/fields/Assets.php
Expand Up @@ -716,6 +716,7 @@ protected function inputTemplateVariables($value = null, ElementInterface $eleme
$variables['defaultSourcePath'] = array_map(function(VolumeFolder $folder) {
return $folder->getSourcePathInfo();
}, $folders);
$variables['preferStoredSource'] = true;
}
}

Expand Down
2 changes: 2 additions & 0 deletions src/models/VolumeFolder.php
Expand Up @@ -130,6 +130,7 @@ public function getSourcePathInfo(): ?array
// Is this a root folder?
if (!$this->parentId) {
$info += [
'key' => "folder:$this->uid",
'icon' => 'home',
'label' => Craft::t('app', '{volume} root', [
'volume' => Html::encode(Craft::t('site', $volume->name)),
Expand All @@ -140,6 +141,7 @@ public function getSourcePathInfo(): ?array
$canRename = $canCreate & $userSession->checkPermission("deleteFilesAndFoldersInVolume:$volume->uid");

$info += [
'key' => "folder:$this->uid",
'label' => Html::encode($this->name),
'criteria' => [
'folderId' => $this->id,
Expand Down
1 change: 1 addition & 0 deletions src/templates/_components/fieldtypes/Assets/input.html
Expand Up @@ -53,6 +53,7 @@
hideSidebar: hideSidebar ?? false,
defaultSource: defaultSource ?? null,
defaultSourcePath: defaultSourcePath ?? null,
preferStoredSource: preferStoredSource ?? false,
showSourcePath: showSourcePath ?? true,
indexSettings: {
showFolders: showFolders ?? true,
Expand Down
2 changes: 1 addition & 1 deletion src/web/assets/cp/dist/cp.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion src/web/assets/cp/dist/cp.js.map

Large diffs are not rendered by default.

95 changes: 85 additions & 10 deletions src/web/assets/cp/src/js/BaseElementIndex.js
Expand Up @@ -56,7 +56,7 @@ Craft.BaseElementIndex = Garnish.Base.extend(
$scoreSortAttribute: null,
$structureSortAttribute: null,

_sourcePath: null,
sourcePaths: null,
$sourcePathOuterContainer: null,
$sourcePathInnerContainer: null,
$sourcePathOverflowBtnContainer: null,
Expand Down Expand Up @@ -98,6 +98,8 @@ Craft.BaseElementIndex = Garnish.Base.extend(
this.$container = $container;
this.setSettings(settings, Craft.BaseElementIndex.defaults);

this.sourcePaths = {};

// Set the state objects
// ---------------------------------------------------------------------

Expand Down Expand Up @@ -301,15 +303,68 @@ Craft.BaseElementIndex = Garnish.Base.extend(
// Select the initial source + source path
// ---------------------------------------------------------------------

// Grab the localStorage step key up front, so we don's lose track of it when the default source's default
// source path is selected
const stepKey = this.getSelectedSourceState('sourcePathStep');

this.selectDefaultSource();

const sourcePath = this.getDefaultSourcePath();
if (sourcePath !== null) {

// If no default source path was explicitly configured, use the localStorage key
if (!sourcePath && stepKey) {
this.loadSourcePathByKey(stepKey).then((sourcePath) => {
if (sourcePath) {
// Filter out any source path steps that are above the source's root
const lastSourceKey = this.sourceKey.split('/').slice(-1)[0];
const sourceRootIndex = sourcePath.findIndex(
(p) => p.key === lastSourceKey
);
if (sourceRootIndex !== -1) {
this.sourcePath = sourcePath.slice(sourceRootIndex);
}
}
this.afterSetInitialSource();
});
} else {
this.sourcePath = sourcePath;
this.afterSetInitialSource();
}
},

afterInit: function () {
this.onAfterInit();
},

loadSourcePathByKey: function (stepKey) {
return new Promise((resolve, reject) => {
// If the step key is equal to the current source key, then it represents the root. No source path needed.
if (stepKey === this.sourceKey) {
resolve([]);
return;
}

const params = this.getViewParams();
params.stepKey = stepKey;

Craft.sendActionRequest('POST', 'element-indexes/source-path', {
data: params,
})
.then(({data}) => {
resolve(data.sourcePath);
})
.catch(reject);
});
},

afterSetInitialSource: function () {
// Resize handler
// ---------------------------------------------------------------------

if (this.settings.context === 'index') {
this.addListener(Garnish.$win, 'resize', 'handleResize');
}

this.handleResize();

// Load the first batch of elements!
Expand All @@ -321,10 +376,6 @@ Craft.BaseElementIndex = Garnish.Base.extend(
this.updateElements(true);
},

afterInit: function () {
this.onAfterInit();
},

handleResize: function () {
if (this.sourcePath.length && this.settings.showSourcePath) {
this._updateSourcePathVisibility();
Expand Down Expand Up @@ -485,6 +536,16 @@ Craft.BaseElementIndex = Garnish.Base.extend(
},

getDefaultSourceKey: function () {
if (
this.settings.preferStoredSource &&
this.instanceState.selectedSource
) {
// Discard the defaults and go with localStorage
this.settings.defaultSource = null;
this.settings.defaultSourcePath = null;
return this.instanceState.selectedSource;
}

let sourceKey = null;

if (this.settings.defaultSource) {
Expand Down Expand Up @@ -553,14 +614,15 @@ Craft.BaseElementIndex = Garnish.Base.extend(
* @returns {Object[]}
*/
get sourcePath() {
return this._sourcePath || [];
return this.sourcePaths[this.sourceKey] || [];
},

/**
* @param {Object[]|null} sourcePath
*/
set sourcePath(sourcePath) {
this._sourcePath = sourcePath && sourcePath.length ? sourcePath : null;
this.sourcePaths[this.sourceKey] =
sourcePath && sourcePath.length ? sourcePath : null;

if (this.$sourcePathOuterContainer) {
this.$sourcePathOuterContainer.remove();
Expand All @@ -570,7 +632,7 @@ Craft.BaseElementIndex = Garnish.Base.extend(
this.$sourcePathActionsBtn = null;
}

if (this._sourcePath && this.settings.showSourcePath) {
if (this.sourcePaths[this.sourceKey] && this.settings.showSourcePath) {
const actions = this.getSourcePathActions();

this.$sourcePathOuterContainer = $('<div/>', {
Expand Down Expand Up @@ -751,6 +813,16 @@ Craft.BaseElementIndex = Garnish.Base.extend(
}
}

// Store the source path
this.setSelecetedSourceState(
'sourcePathStep',
(this.sourcePaths[this.sourceKey]
? this.sourcePaths[this.sourceKey][
this.sourcePaths[this.sourceKey].length - 1
].key
: null) || null
);

this.onSourcePathChange();
},

Expand Down Expand Up @@ -1601,7 +1673,9 @@ Craft.BaseElementIndex = Garnish.Base.extend(

this.selectViewMode(viewMode);

this.sourcePath = this.$source.data('default-source-path');
this.sourcePath =
this.sourcePaths[this.sourceKey] ||
this.$source.data('default-source-path');

this.onSelectSource();

Expand Down Expand Up @@ -2755,6 +2829,7 @@ Craft.BaseElementIndex = Garnish.Base.extend(
defaultSiteId: null,
defaultSource: null,
defaultSourcePath: null,
preferStoredSource: false,
showSourcePath: true,
canHaveDrafts: false,

Expand Down
2 changes: 2 additions & 0 deletions src/web/assets/cp/src/js/BaseElementSelectorModal.js
Expand Up @@ -296,6 +296,7 @@ Craft.BaseElementSelectorModal = Garnish.Modal.extend(
defaultSiteId: this.settings.defaultSiteId,
defaultSource: this.settings.defaultSource,
defaultSourcePath: this.settings.defaultSourcePath,
preferStoredSource: this.settings.preferStoredSource,
showSourcePath: this.settings.showSourcePath,
},
this.settings.indexSettings
Expand Down Expand Up @@ -323,6 +324,7 @@ Craft.BaseElementSelectorModal = Garnish.Modal.extend(
defaultSiteId: null,
defaultSource: null,
defaultSourcePath: null,
preferStoredSource: false,
showSourcePath: true,
bodyAction: 'elements/get-modal-body',
indexSettings: {},
Expand Down

0 comments on commit b1794fc

Please sign in to comment.