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

[3.x] Refine grids code to correct actions access and visibility (revised) #15919

Draft
wants to merge 39 commits into
base: 3.x
Choose a base branch
from
Draft
Changes from 1 commit
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
2fdb2b9
Updates batch 1
Nov 25, 2021
bed51b8
Code Refinements, Batch 1
Nov 29, 2021
0303997
Remove type declarations from class properties
Nov 29, 2021
0347792
Delete index.css
Jul 16, 2022
6fec418
Fix code quality issues
Sep 7, 2023
7b8d069
Update modMediaSource.php
Sep 7, 2023
b56ccea
Resolve conflicts
smg6511 May 7, 2024
0fe31ac
Updates batch 1
Nov 25, 2021
3a30c37
Code Refinements, Batch 1
Nov 29, 2021
44869ba
Resolve conflicts
smg6511 May 7, 2024
331f18e
Update modx.grid.role.js
smg6511 Sep 6, 2024
9978ec0
Update modx.grid.role.js
smg6511 Sep 6, 2024
b259e26
Revert edit and remove prop names and visibility
smg6511 Sep 6, 2024
2b0fa68
Base js updates and default lexicon update
smg6511 Sep 9, 2024
da701e1
Context area updates
smg6511 Sep 9, 2024
2cab251
Media Source are updates
smg6511 Sep 9, 2024
a330366
Namespaces updates
smg6511 Sep 9, 2024
ca69470
Finalize namespaces
smg6511 Sep 26, 2024
c942ec0
Finalize contexts
smg6511 Sep 26, 2024
49c759d
Finalize roles
smg6511 Sep 26, 2024
8799205
Finalize sources
smg6511 Sep 26, 2024
7adf926
Update modx.panel.user.group.js
smg6511 Sep 26, 2024
8a7f813
Update _utility.scss
smg6511 Sep 26, 2024
97cad9b
Update modx.panel.filetree.js
smg6511 Oct 21, 2024
638a142
Update modx.tree.js
smg6511 Oct 24, 2024
016eb81
Role updates
smg6511 Oct 29, 2024
4e8695d
Media Source updates
smg6511 Oct 29, 2024
0490769
Context updates
smg6511 Oct 29, 2024
5724f12
Update modx.grid.js
smg6511 Oct 29, 2024
9da688c
Update modx.panel.filetree.js
smg6511 Oct 29, 2024
426647d
More Context tweaks
smg6511 Oct 29, 2024
f4b53c4
Lexicon updates
smg6511 Oct 29, 2024
bfa828a
Dashboards updates
smg6511 Oct 29, 2024
edfe422
WIP Policies and Policy Templates
smg6511 Oct 29, 2024
8dbe031
Update modx.namespace.panel.js
smg6511 Oct 29, 2024
ca122b3
Update modx.grid.user.js
smg6511 Oct 29, 2024
d5c7316
Update utilities.js
smg6511 Oct 29, 2024
5dbf124
Update .eslintrc.js
smg6511 Oct 29, 2024
74285b1
CQ Fixups
smg6511 Oct 29, 2024
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
Prev Previous commit
Next Next commit
Update modx.grid.js
Adds a few shared methods for generating common grid UI elements
  • Loading branch information
smg6511 committed Oct 29, 2024
commit 5724f12b8d323daa9d26cd934a51b1cd10967f19
190 changes: 176 additions & 14 deletions manager/assets/modext/widgets/core/modx.grid.js
Original file line number Diff line number Diff line change
Expand Up @@ -257,39 +257,55 @@ Ext.extend(MODx.grid.Grid, Ext.grid.EditorGridPanel, {
this.getView().refresh(false);
},

/**
* Executes auto save of the row after edits are complete and optional success callback
* @param {Ext.Event} e Extended event data including:
* * column
* * row
* * field (name)
* * grid (full grid object)
* * record (full Ext record object including store, data, json, etc.)
* * originalValue
* * value (current)
*/
saveRecord: function(e) {
e.record.data.menu = null;
const p = this.config.saveParams || {};
Ext.apply(e.record.data, p);
const
d = Ext.util.JSON.encode(e.record.data),
data = Ext.util.JSON.encode(e.record.data),
url = this.config.saveUrl || (this.config.url || this.config.connector)
;
MODx.Ajax.request({
url: url,
params: {
action: this.config.save_action || 'updateFromGrid',
data: d
data: data
},
listeners: {
success: {
fn: function(r) {
fn: function(response) {
if (this.config.save_callback) {
Ext.callback(this.config.save_callback, this.config.scope || this, [r]);
Ext.callback(this.config.save_callback, this.config.scope || this, [response]);
}
e.record.commit();
if (!this.config.preventSaveRefresh) {
const gridRefresh = new Ext.util.DelayedTask(() => this.refresh());
gridRefresh.delay(200);
}
this.fireEvent('afterAutoSave', r);
const
/** @var {Object} eventData Plucking only the needed event props to forward in the post-save event */
eventData = { field: e.field, originalValue: e.originalValue, value: e.value },
responseData = { ...response, eventData }
;
this.fireEvent('afterAutoSave', responseData);
},
scope: this
},
failure: {
fn: function(r) {
fn: function(response) {
e.record.reject();
this.fireEvent('afterAutoSave', r);
this.fireEvent('afterAutoSave', response);
},
scope: this
}
Expand Down Expand Up @@ -781,7 +797,7 @@ Ext.extend(MODx.grid.Grid, Ext.grid.EditorGridPanel, {
*
* @return {Array}
*/
getRemovableItemsFromSelection: function(itemIdType = 'string') {
getRemovableItemsFromSelection: function(itemIdType = 'int') {
const selections = this.getSelectionModel().getSelections(),
pk = this.config.primaryKey || 'id',
removableItems = []
Expand Down Expand Up @@ -856,11 +872,14 @@ Ext.extend(MODx.grid.Grid, Ext.grid.EditorGridPanel, {
*
* @param {String} gridName The object identifier (e.g., 'source', 'context', etc)
* @param {String} removeAction The remove processor to call
* @param {String} pkDataType Indicates the primary key data type (string or integer)
* @param {String} pkType Indicates the primary key data type (string or int)
*/
removeSelected: function(gridName, removeAction, pkDataType = 'string') {
const removableSelections = this.getRemovableItemsFromSelection(pkDataType);
let modalText;
removeSelected: function(gridName, removeAction, pkType = 'int') {
const removableSelections = this.getRemovableItemsFromSelection(pkType);
let
modalText,
actionKey
;
if (removableSelections.length === 0) {
return false;
}
Expand All @@ -869,19 +888,30 @@ Ext.extend(MODx.grid.Grid, Ext.grid.EditorGridPanel, {
} else {
modalText = _(`${gridName}_remove_multiple_confirm`) || _('confirm_remove_multiple');
}
switch (gridName) {
case 'policy_template':
actionKey = 'templates';
break;
default:
actionKey = gridName.endsWith('y')
? `${gridName.substring(0, gridName.length - 1)}ies`
: `${gridName}s`
;
}
MODx.msg.confirm({
title: _('selected_remove'),
text: modalText,
url: this.config.url,
params: {
action: removeAction,
[`${gridName}s`]: removableSelections.join(',')
[actionKey]: removableSelections.join(',')
},
listeners: {
success: {
fn: function(r) {
fn: function(response) {
this.getSelectionModel().clearSelections(true);
this.refresh();
this.fireEvent('afterRemoveRow', { ...response, itemsRemoved: removableSelections });
},
scope: this
}
Expand Down Expand Up @@ -1613,6 +1643,138 @@ Ext.extend(MODx.grid.Grid, Ext.grid.EditorGridPanel, {
config.dependentResets = dependentFilterResets;
}
return config;
},

/**
* Builds the standard "Creator" column model object. This column displays for
* objects that have built-in system values as well as values installed/entered
* by Extras and/or Users
* @param {String} objectType Identifier for object being worked with
* @returns {Object} The configuration for the "Creator" column
*/
getCreatorColumnConfig: function(objectType) {
return {
header: _('grid_column_creator_header'),
dataIndex: 'creator',
id: `modx-${objectType}--creator`,
width: 70,
align: 'center',
tooltip: _('grid_column_creator_description'),
menuDisabled: true
};
},

/**
* Builds the bulk actions button, containing a menu of various actions
* (typically only contains a delete action)
* @param {String} objectType Identifier for object being worked with
* @param {String} deleteAction Processor path for the removal action
* @param {String} pkType Specifies the object's primary key type (int or string)
* @param {...any} moreActions Additional button identifiers or config objects
* to add to the bulk actions menu
* @returns {Object} The complete bulk actions config
*/
getBulkActionsButton: function(objectType, deleteAction, pkType = 'int', ...moreActions) {
const
menuItems = [],
additionalMenuItems = [],
hasMoreActions = moreActions.length > 0
;
if (hasMoreActions) {
/** @var standardButtons Button configs for actions that are used in select grids, such as the Users and Form Customization (Sets) grids */
const standardButtons = {
activate: {
text: _('selected_activate'),
itemId: 'modx-bulk-menu-opt-activate',
handler: this.activateSelected,
scope: this
},
deactivate: {
text: _('selected_deactivate'),
itemId: 'modx-bulk-menu-opt-deactivate',
handler: this.deactivateSelected,
scope: this
}
};
moreActions.forEach(action => {
if (typeof action === 'string') {
const key = action.toLowerCase();
if (Object.hasOwn(standardButtons, key)) {
additionalMenuItems.push(standardButtons[key]);
}
}
});
menuItems.push(...additionalMenuItems);
menuItems.push('-');
}
menuItems.push({
text: _('selected_remove'),
itemId: 'modx-bulk-menu-opt-remove',
handler: this.removeSelected.createDelegate(this, [objectType, deleteAction, pkType]),
scope: this
});
return {
text: _('bulk_actions'),
menu: menuItems,
listeners: {
render: {
fn: function(btn) {
if (!this.userCanDelete && !hasMoreActions) {
btn.hide();
}
},
scope: this
},
click: {
fn: function(btn) {
const
removableItems = this.getRemovableItemsFromSelection(pkType),
menuOptRemove = btn.menu.getComponent('modx-bulk-menu-opt-remove')
;
if (removableItems.length === 0) {
menuOptRemove.disable();
} else {
menuOptRemove.enable();
}
if (hasMoreActions) {
const selections = this.getSelectionModel().getSelections();
additionalMenuItems.forEach(item => {
const itemCmp = btn.menu.getComponent(item.itemId);
if (selections.length === 0) {
itemCmp.disable();
} else {
itemCmp.enable();
}
});
}
},
scope: this
}
}
};
},

/**
* Gets the view configuration for grids having row-specific editing permissions
* @param {Boolean} hasBulkActions Whether the grid has a bulk actions option
* (uses the checkbox selection model to select multiple rows)
* @param {Boolean} hasObjectLevelPermissions Whether individual rows might have
* differing permissions, based on the specific object they represent
* @returns {Object} The complete view config
*/
getViewConfig: function(hasBulkActions = true, hasObjectLevelPermissions = true) {
return {
forceFit: true,
scrollOffset: 0,
getRowClass: function(record, index, rowParams, store) {
// Adds the returned class to the row container's css classes
if (hasObjectLevelPermissions && this.grid.userCanDeleteRecord(record)) {
return '';
}
const rowClasses = hasBulkActions ? 'disable-selection' : '' ;
return record.json.isProtected ? `modx-protected-row ${rowClasses}` : rowClasses ;
}
};
}
});

Expand Down