I'm currently struggling with this issue when trying to build the administration on my shopware6 instance.
I am not sure to understand what it's expecting with this error
Definition for rule 'vue/require-prop-types' was not found vue/require-prop-types
This is pointing the line 22 which is :
props: {
Here's the index.js file :
import './custom-entity-single-select.scss';
import template from './custom-entity-single-select.html.twig';
const { Component, Mixin, Utils } = Shopware;
const { Criteria, EntityCollection } = Shopware.Data;
const { debounce, get } = Shopware.Utils;
Component.register('custom-entity-single-select', {
template,
inject: { repositoryFactory: 'repositoryFactory', feature: 'feature' },
mixins: [
Mixin.getByName('remove-api-error'),
],
model: {
prop: 'value',
event: 'change',
},
props: {
value: {
required: false,
},
highlightSearchTerm: {
type: Boolean,
required: false,
default: true,
},
placeholder: {
type: String,
required: false,
default: '',
},
resetOption: {
type: String,
required: false,
default: '',
},
labelProperty: {
type: [String, Array],
required: false,
default: 'name',
},
labelCallback: {
type: Function,
required: false,
default: null,
},
entity: {
required: true,
type: String,
},
resultLimit: {
type: Number,
required: false,
default: 25,
},
criteria: {
type: Object,
required: false,
default() {
return (new Criteria(1, this.resultLimit)).getAssociation('stateMachine').addFilter(Criteria.equals('state_machine_state.stateMachine.technicalName', 'order_transaction.state'));
},
},
context: {
type: Object,
required: false,
default() {
return Shopware.Context.api;
},
},
disableAutoClose: {
type: Boolean,
required: false,
default: false,
},
},
data() {
return {
searchTerm: '',
isExpanded: false,
resultCollection: null,
singleSelection: null,
isLoading: false,
// used to track if an item was selected before closing the result list
itemRecentlySelected: false,
lastSelection: null,
};
},
computed: {
inputClasses() {
return {
'is--expanded': this.isExpanded,
};
},
selectionTextClasses() {
return {
'is--placeholder': !this.singleSelection,
};
},
repository() {
return this.repositoryFactory.create(this.entity);
},
/**
* #returns {EntityCollection}
*/
results() {
return this.resultCollection;
},
},
watch: {
value(value) {
// No need to fetch again when the new value is the last one we selected
if (this.lastSelection && this.value === this.lastSelection.id) {
this.singleSelection = this.lastSelection;
this.lastSelection = null;
return;
}
if (value === '' || value === null) {
this.singleSelection = null;
return;
}
this.loadSelected();
},
},
created() {
this.createdComponent();
},
methods: {
createdComponent() {
this.loadSelected();
},
/**
* Fetches the selected entity from the server
*/
loadSelected() {
if (!this.value) {
if (this.resetOption) {
this.singleSelection = {
id: null,
name: this.resetOption,
};
}
return Promise.resolve();
}
this.isLoading = true;
return this.repository.get(this.value, { ...this.context, inheritance: true }, this.criteria).then((item) => {
this.criteria.setIds([]);
this.singleSelection = item;
this.isLoading = false;
return item;
});
},
createCollection(collection) {
return new EntityCollection(collection.source, collection.entity, collection.criteria);
},
isSelected(item) {
return item.id === this.value;
},
debouncedSearch: debounce(function updateSearchTerm() {
this.search();
}, 400),
search() {
if (this.criteria.term === this.searchTerm) {
return Promise.resolve();
}
this.criteria.setPage(1);
this.criteria.setLimit(this.resultLimit);
this.criteria.setTerm(this.searchTerm);
this.resultCollection = null;
const searchPromise = this.loadData().then(() => {
this.resetActiveItem();
});
this.$emit('search', searchPromise);
return searchPromise;
},
paginate() {
if (!this.resultCollection || this.resultCollection.total < this.criteria.page * this.criteria.limit) {
return;
}
this.criteria.setPage(this.criteria.page + 1);
this.loadData();
},
loadData() {
this.isLoading = true;
return this.repository.search(this.criteria, { ...this.context, inheritance: true }).then((result) => {
this.displaySearch(result);
this.isLoading = false;
return result;
});
},
displaySearch(result) {
if (!this.resultCollection) {
this.resultCollection = result;
} else {
result.forEach(item => {
// Prevent duplicate entries
if (!this.resultCollection.has(item.id)) {
this.resultCollection.push(item);
}
});
}
if (this.resetOption) {
if (!this.resultCollection.has(null)) {
this.resultCollection.unshift({
id: null,
name: this.resetOption,
});
}
}
},
displayLabelProperty(item) {
if (typeof this.labelCallback === 'function') {
return this.labelCallback(item);
}
const labelProperties = [];
if (Array.isArray(this.labelProperty)) {
labelProperties.push(...this.labelProperty);
} else {
labelProperties.push(this.labelProperty);
}
return labelProperties.map(labelProperty => {
return this.getKey(item, labelProperty) || this.getKey(item, `translated.${labelProperty}`);
}).join(' ');
},
onSelectExpanded() {
this.isExpanded = true;
// Always start with a fresh list when opening the result list
this.criteria.setPage(1);
this.criteria.setLimit(this.resultLimit);
this.criteria.setTerm('');
this.resultCollection = null;
this.loadData().then(() => {
this.resetActiveItem();
});
// Get the search text of the selected item as prefilled value
this.searchTerm = this.tryGetSearchText(this.singleSelection);
this.$nextTick(() => {
this.$refs.customSelectInput.select();
this.$refs.customSelectInput.focus();
});
},
tryGetSearchText(option) {
if (typeof this.labelCallback === 'function') {
return this.labelCallback(option);
}
let searchText = this.getKey(option, this.labelProperty, '');
if (!searchText) {
searchText = this.getKey(option, `translated.${this.labelProperty}`, '');
}
return searchText;
},
onSelectCollapsed() {
// Empty the selection if the search term is empty
if (this.searchTerm === '' && !this.itemRecentlySelected) {
this.clearSelection();
}
this.$refs.customSelectInput.blur();
this.searchTerm = '';
this.itemRecentlySelected = false;
this.isExpanded = false;
},
closeResultList() {
this.$refs.selectBase.collapse();
},
setValue(item) {
this.itemRecentlySelected = true;
if (!this.disableAutoClose) {
this.closeResultList();
}
// This is a little against v-model. But so we dont need to load the selected item on every selection
// from the server
this.lastSelection = item;
this.$emit('change', item.id, item);
this.$emit('option-select', Utils.string.camelCase(this.entity), item);
},
clearSelection() {
this.$emit('before-selection-clear', this.singleSelection, this.value);
this.$emit('change', null);
this.$emit('option-select', Utils.string.camelCase(this.entity), null);
},
resetActiveItem(pos = 0) {
// Return if the result list is closed before the search request returns
if (!this.$refs.resultsList) {
return;
}
// If an item is selected the second entry is the first search result
if (this.singleSelection) {
pos = 1;
}
this.$refs.resultsList.setActiveItemIndex(pos);
},
onInputSearchTerm(event) {
const value = event.target.value;
this.$emit('search-term-change', value);
this.debouncedSearch();
},
getKey(object, keyPath, defaultValue) {
return get(object, keyPath, defaultValue);
},
},
});
And here you can find the whole gist containing this index.js, the html.twig file and the scss : https://gist.github.com/Youmar0504/2154bd1d16866d14644aa2a3a6fd513f
ALREADY TRIED
value: {
type: String,
required: false,
default: '',
},
value: {
type: Array,
required: false,
default: [],
},
I would assume you have an extra closing '}' at the value prop.
props: {
value: {
required: false,
} <--
},
highlightSearchTerm: {
type: Boolean,
required: false,
default: true,
},
placeholder: {
type: String,
required: false,
default: '',
},
resetOption: {
type: String,
required: false,
default: '',
},
labelProperty: {
type: [String, Array],
required: false,
default: 'name',
},
labelCallback: {
type: Function,
required: false,
default: null,
},
entity: {
required: true,
type: String,
},
resultLimit: {
type: Number,
required: false,
default: 25,
},
criteria: {
type: Object,
required: false,
default() {
return (new Criteria(1, this.resultLimit)).getAssociation('stateMachine').addFilter(Criteria.equals('state_machine_state.stateMachine.technicalName', 'order_transaction.state'));
},
},
context: {
type: Object,
required: false,
default() {
return Shopware.Context.api;
},
},
disableAutoClose: {
type: Boolean,
required: false,
default: false,
},
},
I am trying to use the Rally App Catalog and the custom list app
I would like to add an additional selector (item type) and rename some of the headers on the fly. First I just want the sample to run. As it currently stands, it looks broken to me.
When I use the rally-app-builder build function and then paste the result app.html into a custom app I get a blank page with working app settings.
Here the uncompressed version from my initial attempt.
<script src="https://rally1.rallydev.com/apps/2.1/sdk-debug.js"></script>
<!DOCTYPE html>
<html>
<head>
<title>Custom List</title>
<script type="text/javascript" src="/apps/2.1/sdk.js"></script>
<script type="text/javascript">
Rally.onReady(function() {
(function() {
var Ext = window.Ext4 || window.Ext;
var getHiddenFieldConfig = function(name) {
return {
name: name,
xtype: 'rallytextfield',
hidden: true,
handlesEvents: {
typeselected: function(type) {
this.setValue(null);
}
}
};
};
Ext.define('Rally.apps.customlist.Settings', {
singleton: true,
requires: [
'Rally.ui.combobox.FieldComboBox',
'Rally.ui.combobox.ComboBox',
'Rally.ui.CheckboxField'
],
getFields: function(app) {
this.app = app;
return [{
name: 'type',
xtype: 'rallycombobox',
allowBlank: false,
autoSelect: false,
shouldRespondToScopeChange: true,
context: this.app.getContext(),
initialValue: 'HierarchicalRequirement',
storeConfig: {
model: Ext.identityFn('TypeDefinition'),
sorters: [{
property: 'DisplayName'
}],
fetch: ['DisplayName', 'ElementName', 'TypePath', 'Parent', 'UserListable'],
filters: [{
property: 'UserListable',
value: true
}],
autoLoad: false,
remoteSort: false,
remoteFilter: true
},
displayField: 'DisplayName',
valueField: 'TypePath',
listeners: {
select: function(combo) {
this.app.clearFiltersAndSharedViews();
combo.fireEvent('typeselected', combo.getRecord().get('TypePath'), combo.context);
},
scope: this
},
bubbleEvents: ['typeselected'],
readyEvent: 'ready',
handlesEvents: {
projectscopechanged: function(context) {
this.refreshWithNewContext(context);
}
}
}, {
type: 'query'
}, {
name: 'showControls',
xtype: 'rallycheckboxfield',
fieldLabel: 'Show Control Bar'
},
getHiddenFieldConfig('columnNames'),
getHiddenFieldConfig('order')
];
}
});
})();
(function() {
var Ext = window.Ext4 || window.Ext;
Ext.define('Rally.apps.customlist.CustomListApp', {
extend: 'Rally.app.GridBoardApp',
requires: [
'Deft.Promise',
'Rally.apps.customlist.Settings',
'Rally.data.BulkRecordUpdater',
'Rally.data.ModelTypes',
'Rally.data.PreferenceManager',
'Rally.data.util.Sorter',
'Rally.data.wsapi.Filter',
'Rally.ui.gridboard.plugin.GridBoardInlineFilterControl',
'Rally.ui.gridboard.plugin.GridBoardSharedViewControl',
'Rally.ui.notify.Notifier',
'Rally.util.String'
],
disallowedAddNewTypes: ['user', 'userprofile', 'useriterationcapacity', 'testcaseresult', 'task', 'scmrepository', 'project', 'changeset', 'change', 'builddefinition', 'build', 'program'],
orderedAllowedPageSizes: [10, 25, 50, 100, 200],
readOnlyGridTypes: ['build', 'change', 'changeset'],
statePrefix: 'customlist',
allowExpansionStateToBeSaved: false,
isEditable: true,
config: {
defaultSettings: {
showControls: true
}
},
initComponent: function() {
this.appName = 'CustomList-' + this.getAppId();
this.callParent(arguments);
},
getSettingsFields: function() {
return Rally.apps.customlist.Settings.getFields(this);
},
loadModelNames: function() {
this.modelNames = _.compact([this._getTypeSetting()]);
this._setColumnNames(this._getColumnNamesSetting());
return Deft.Promise.when(this.modelNames);
},
addGridBoard: function() {
this.callParent(arguments);
if (!this.getSetting('showControls')) {
this.gridboard.getHeader().hide();
}
},
loadGridBoard: function() {
if (_.isEmpty(this.modelNames)) {
Ext.defer(function() {
this.fireEvent('settingsneeded', this);
this.publishComponentReady();
}, 1, this);
} else {
this.enableAddNew = this._shouldEnableAddNew();
this.enableRanking = this._shouldEnableRanking();
this.callParent(arguments);
}
},
getGridConfig: function() {
var config = _.merge(this.callParent(arguments), {
allColumnsStateful: true,
enableEditing: !_.contains(this.readOnlyGridTypes, this._getTypeSetting().toLowerCase()),
listeners: {
beforestaterestore: this._onBeforeGridStateRestore,
beforestatesave: this._onBeforeGridStateSave,
scope: this
},
pagingToolbarCfg: {
hidden: !this.getSetting('showControls'),
pageSizes: this.orderedAllowedPageSizes
}
});
var invalidQueryFilters = Rally.util.Filter.findInvalidSubFilters(this._getQueryFilter(), this.models);
if (invalidQueryFilters.length) {
config.store.on('beforeload', function(store) {
Ext.defer(function() {
store.fireEvent('load', store, store.getRootNode(), [], true);
}, 1);
return false;
});
this._showInvalidQueryMessage(config, _.map(invalidQueryFilters, function(filter) {
return 'Could not find the attribute "' + filter.property.split('.')[0] + '" on type "' + this.models[0].displayName + '" in the query segment "' + filter.toString() + '"';
}, this));
}
return config;
},
getColumnCfgs: function() {
return _.union(this.callParent(arguments), _.isEmpty(this.columnNames) && this.enableRanking ? ['DragAndDropRank'] : []);
},
getFilterControlConfig: function() {
return _.merge(this.callParent(arguments), {
listeners: {
beforestaterestore: {
fn: this._onBeforeFilterButtonStateRestore,
scope: this
}
}
});
},
getGridBoardCustomFilterControlConfig: function() {
var context = this.getContext();
var isArtifactModel = this.models[0].isArtifact();
var blackListFields = isArtifactModel ? ['ModelType', 'PortfolioItemType'] : ['ArtifactSearch', 'ModelType'];
var whiteListFields = isArtifactModel ? ['Milestones', 'Tags'] : [];
if (this.models[0].isProject()) {
blackListFields.push('SchemaVersion');
} else if (this.models[0].isRelease()) {
blackListFields.push('ChildrenPlannedVelocity', 'Version');
}
var config = {
ptype: 'rallygridboardinlinefiltercontrol',
inlineFilterButtonConfig: {
stateful: true,
stateId: context.getScopedStateId('custom-list-inline-filter'),
legacyStateIds: [
this.getScopedStateId('owner-filter'),
this.getScopedStateId('custom-filter-button')
],
filterChildren: true,
inlineFilterPanelConfig: {
quickFilterPanelConfig: {
defaultFields: isArtifactModel ? ['ArtifactSearch', 'Owner'] : [],
addQuickFilterConfig: {
blackListFields: blackListFields,
whiteListFields: whiteListFields
}
},
advancedFilterPanelConfig: {
advancedFilterRowsConfig: {
propertyFieldConfig: {
blackListFields: blackListFields,
whiteListFields: whiteListFields
}
}
}
}
}
};
if (isArtifactModel) {
config.inlineFilterButtonConfig.modelNames = this.modelNames;
} else {
config.inlineFilterButtonConfig.model = this.models[0];
}
return config;
},
getSharedViewConfig: function() {
var context = this.getContext();
return {
ptype: 'rallygridboardsharedviewcontrol',
sharedViewConfig: {
stateful: true,
stateId: context.getScopedStateId('custom-list-shared-view'),
enableUrlSharing: this.isFullPageApp !== false
}
};
},
getGridBoardConfig: function() {
var config = this.callParent(arguments);
return _.merge(config, {
listeners: {
viewchange: function() {
this.loadGridBoard();
},
filterchange: function() {
this.gridboard.getGridOrBoard().noDataPrimaryText = undefined;
this.gridboard.getGridOrBoard().noDataSecondaryText = undefined;
},
scope: this
}
});
},
onTreeGridReady: function(grid) {
if (grid.store.getTotalCount() > 10) {
this.gridboard.down('#pagingToolbar').show();
}
this.callParent(arguments);
},
getGridStoreConfig: function() {
var sorters = this._getValidSorters(Rally.data.util.Sorter.sorters(this.getSetting('order')));
if (_.isEmpty(sorters)) {
var rankField = this.getContext().getWorkspace().WorkspaceConfiguration.DragDropRankingEnabled ? 'DragAndDropRank' : 'Rank';
var defaultSort = Rally.data.ModelTypes.areArtifacts(this.modelNames) ? rankField : Rally.data.util.Sorter.getDefaultSort(this.modelNames[0]);
sorters = Rally.data.util.Sorter.sorters(defaultSort);
}
return {
listeners: {
warning: {
fn: this._onGridStoreWarning,
scope: this
}
},
pageSize: 10,
sorters: sorters
};
},
getAddNewConfig: function() {
var config = {
minWidth: 700,
openEditorAfterAddFailure: false,
margin: 0
};
if (!this.getContext().isFeatureEnabled('F6971_REACT_DASHBOARD_PANELS')) {
config.disableAddButton = this.appContainer.slug === 'incompletestories';
}
return _.merge(this.callParent(arguments), config);
},
getFieldPickerConfig: function() {
return _.merge(this.callParent(arguments), {
buttonConfig: {
disabled: !this._userHasPermissionsToEditPanelSettings()
},
gridAlwaysSelectedValues: function() {
return [];
},
gridFieldBlackList: this._getTypeSetting().toLowerCase() === 'task' ? ['Rank'] : []
});
},
getPermanentFilters: function() {
return this._getQueryFilter().concat(this._getTimeboxScopeFilter()).concat(this._getProjectFilter());
},
onTimeboxScopeChange: function() {
this.callParent(arguments);
this.loadGridBoard();
},
clearFiltersAndSharedViews: function() {
var context = this.getContext();
if (this.gridboard) {
this.gridboard.down('rallyinlinefilterpanel').clear();
this.gridboard.down('rallysharedviewcombobox').reset();
}
Ext.create('Rally.data.wsapi.Store', {
model: Ext.identityFn('preference'),
autoLoad: true,
filters: [{
property: 'AppId',
value: context.getAppId()
}, {
property: 'Type',
value: 'View'
}, {
property: 'Workspace',
value: context.getWorkspace()._ref
}],
context: context.getDataContext(),
listeners: {
load: function(store, records) {
if (!_.isEmpty(records)) {
var batchStore = Ext.create('Rally.data.wsapi.batch.Store', {
requester: this,
data: records
});
batchStore.removeAll();
batchStore.sync();
}
store.destroyStore();
},
scope: this
}
});
},
_getTypeSetting: function() {
return this.getSetting('type') || this.getSetting('url');
},
_getColumnNamesSetting: function() {
return this.getSetting('columnNames') ||
(this.getSetting('fetch') || '').split(',');
},
_getQueryFilter: function() {
var query = new Ext.Template(this.getSetting('query')).apply({
projectName: this.getContext().getProject().Name,
projectOid: this.getContext().getProject().ObjectID,
user: this.getContext().getUser()._ref
});
if (query) {
try {
return [Rally.data.wsapi.Filter.fromQueryString(query)];
} catch (e) {
Rally.ui.notify.Notifier.showError({
message: e.message
});
}
}
return [];
},
_getProjectFilter: function() {
return this.modelNames[0].toLowerCase() === 'milestone' ? [
Rally.data.wsapi.Filter.or([{
property: 'Projects',
operator: 'contains',
value: this.getContext().getProjectRef()
}, {
property: 'TargetProject',
operator: '=',
value: null
}])
] : [];
},
_getTimeboxScopeFilter: function() {
var timeboxScope = this.getContext().getTimeboxScope();
var hasTimeboxField = timeboxScope && _.any(this.models, timeboxScope.isApplicable, timeboxScope);
return hasTimeboxField ? [timeboxScope.getQueryFilter()] : [];
},
_shouldEnableAddNew: function() {
return !_.contains(this.disallowedAddNewTypes, this._getTypeSetting().toLowerCase());
},
_shouldEnableRanking: function() {
return this._getTypeSetting().toLowerCase() !== 'task';
},
_setColumnNames: function(columnNames) {
this.columnNames = _.compact(_.isString(columnNames) ? columnNames.split(',') : columnNames);
},
_onBeforeFilterButtonStateRestore: function(filterButton, state) {
if (state && state.filters && state.filters.length) {
var stateFilters = _.map(state.filters, function(filterStr) {
return Rally.data.wsapi.Filter.fromQueryString(filterStr);
});
var validFilters = Rally.util.Filter.removeNonapplicableTypeSpecificFilters(stateFilters, this.models);
state.filters = _.invoke(validFilters, 'toString');
}
},
_hasViewSelected: function() {
var sharedViewConfig = this.getSharedViewConfig().sharedViewConfig;
if (sharedViewConfig && sharedViewConfig.stateId) {
var value = (Ext.state.Manager.get(sharedViewConfig.stateId) || {}).value;
return !_.isEmpty(value);
}
return false;
},
_onBeforeGridStateRestore: function(grid, state) {
if (!state) {
return;
}
if (state.columns) {
var appScopedColumnNames = this._getValidUuids(grid, this.getColumnCfgs());
var userScopedColumnNames = this._getValidUuids(grid, state.columns);
if (this._hasViewSelected()) {
state.columns = userScopedColumnNames;
} else {
// Get the columns that are present in the app scope and not in the user scope
var differingColumns = _.difference(appScopedColumnNames, userScopedColumnNames);
// If there are columns in the app scope that are not in the
// user scope, append them to the user scope to preserve
// user scope column order
if (differingColumns.length > 0) {
state.columns = state.columns.concat(differingColumns);
}
// Filter out any columns that are in the user scope that are not in the
// app scope
state.columns = _.filter(state.columns, function(column) {
return _.contains(appScopedColumnNames, _.isObject(column) ? column.dataIndex : column);
}, this);
}
}
if (state.sorters) {
state.sorters = this._getValidSorters(state.sorters);
if (_.isEmpty(state.sorters)) {
delete state.sorters;
}
}
},
_getValidUuids: function(grid, columns) {
return _.reduce(columns, function(result, column) {
var dataIndex = this._getColumnDataIndex(column);
var field = this._getModelField(grid, dataIndex);
if (field) {
result.push(dataIndex);
}
return result;
}, [], this);
},
_getModelField: function(grid, dataIndex) {
return grid.getModels()[0].getField(dataIndex);
},
_getColumnDataIndex: function(column) {
return _.isObject(column) ? column.dataIndex : column;
},
_onBeforeGridStateSave: function(grid, state) {
var newColumnNames = this._getColumnNamesFromState(state);
if (!_.isEmpty(newColumnNames)) {
this._setColumnNames(newColumnNames);
if (this._userHasPermissionsToEditPanelSettings()) {
this.updateSettingsValues({
settings: {
columnNames: newColumnNames.join(',')
}
});
}
}
},
_onGridStoreWarning: function(store, warnings, operation) {
var couldNotParseWarnings = _.filter(warnings, function(warning) {
return Rally.util.String.startsWith(warning, 'Could not parse ');
});
if (couldNotParseWarnings.length) {
_.assign(operation.resultSet, {
count: 0,
records: [],
total: 0,
totalRecords: 0
});
this._showInvalidQueryMessage(this.gridboard.getGridOrBoard(), couldNotParseWarnings);
}
},
_showInvalidQueryMessage: function(gridOrGridConfig, secondaryTextStrings) {
gridOrGridConfig.noDataPrimaryText = 'Invalid Query';
gridOrGridConfig.noDataSecondaryText = _.map(secondaryTextStrings, function(str) {
return '<div>' + str + '</div>';
}).join('');
},
_getValidSorters: function(sorters) {
return _.filter(sorters, function(sorter) {
return _.any(this.models, function(model) {
var field = model.getField(sorter.property);
return field && field.sortable;
});
}, this);
},
_userHasPermissionsToEditPanelSettings: function() {
return this.isEditable;
},
_getColumnNamesFromState: function(state) {
return _(state && state.columns).map(function(newColumn) {
return _.isObject(newColumn) ? newColumn.dataIndex : newColumn;
}).compact().value();
}
});
})();
Rally.launchApp('Rally.apps.customlist.CustomListApp', {
name: "Custom List",
parentRepos: ""
});
});
</script>
</head>
<body>
</body>
</html>
Ok, I got results by commenting out the following lines in getAddNewConfig:
getAddNewConfig: function () {
var config = {
minWidth: 700,
openEditorAfterAddFailure: false,
margin: 0
};
//if(!this.getContext().isFeatureEnabled('F6971_REACT_DASHBOARD_PANELS')) {
// config.disableAddButton = this.appContainer.slug === 'incompletestories';
//}
return _.merge(this.callParent(arguments), config);
},
It seems that 'this.appContainer.slug' is undefined for me.
Here's the final working CustomListApp.js generated from the comment stream in the answer above. The main tweaks were deleting some old code checking a feature toggle and giving it a default type to display (defect in this case) in the defaultSettings block.
(function() {
var Ext = window.Ext4 || window.Ext;
Ext.define('Rally.apps.customlist.CustomListApp', {
extend: 'Rally.app.GridBoardApp',
requires: [
'Deft.Promise',
'Rally.apps.customlist.Settings',
'Rally.data.BulkRecordUpdater',
'Rally.data.ModelTypes',
'Rally.data.PreferenceManager',
'Rally.data.util.Sorter',
'Rally.data.wsapi.Filter',
'Rally.ui.gridboard.plugin.GridBoardInlineFilterControl',
'Rally.ui.gridboard.plugin.GridBoardSharedViewControl',
'Rally.ui.notify.Notifier',
'Rally.util.String'
],
disallowedAddNewTypes: ['user', 'userprofile', 'useriterationcapacity', 'testcaseresult', 'task', 'scmrepository', 'project', 'changeset', 'change', 'builddefinition', 'build', 'program'],
orderedAllowedPageSizes: [10, 25, 50, 100, 200],
readOnlyGridTypes: ['build', 'change', 'changeset'],
statePrefix: 'customlist',
allowExpansionStateToBeSaved: false,
isEditable: true,
config: {
defaultSettings: {
showControls: true,
type: 'defect' //important to include a default type to display
}
},
initComponent: function () {
this.appName = 'CustomList-' + this.getAppId();
if (this.defaultSettings.url) {
Ext.apply(this.defaultSettings, { type: this.defaultSettings.url });
}
this.callParent(arguments);
},
getSettingsFields: function() {
return Rally.apps.customlist.Settings.getFields(this);
},
loadModelNames: function () {
this.modelNames = _.compact(this.getTypeSetting());
this._setColumnNames(this._getColumnNamesSetting());
return Deft.Promise.when(this.modelNames);
},
addGridBoard: function () {
this.callParent(arguments);
if (!this.getSetting('showControls')) {
this.gridboard.getHeader().hide();
}
},
loadGridBoard: function () {
if (_.isEmpty(this.modelNames)) {
Ext.defer(function () {
this.fireEvent('settingsneeded', this);
this.publishComponentReady();
}, 1, this);
} else {
this.enableAddNew = this._shouldEnableAddNew();
this.enableRanking = this._shouldEnableRanking();
this.callParent(arguments);
}
},
getGridConfig: function () {
var config = _.merge(this.callParent(arguments), {
allColumnsStateful: true,
enableEditing: _.intersection(this.readOnlyGridTypes, this.getTypeSetting()).length === 0,
listeners: {
beforestaterestore: this._onBeforeGridStateRestore,
beforestatesave: this._onBeforeGridStateSave,
scope: this
},
pagingToolbarCfg: {
hidden: !this.getSetting('showControls'),
pageSizes: this.orderedAllowedPageSizes
}
});
var invalidQueryFilters = Rally.util.Filter.findInvalidSubFilters(this._getQueryFilter(), this.models);
if (invalidQueryFilters.length) {
config.store.on('beforeload', function (store) {
Ext.defer(function () {
store.fireEvent('load', store, store.getRootNode(), [], true);
}, 1);
return false;
});
this._showInvalidQueryMessage(config, _.map(invalidQueryFilters, function (filter) {
return 'Could not find the attribute "'+ filter.property.split('.')[0] +'" on type "'+ this.models[0].displayName +'" in the query segment "'+ filter.toString() + '"';
}, this));
}
return config;
},
getColumnCfgs: function() {
return _.union(this.callParent(arguments), _.isEmpty(this.columnNames) && this.enableRanking ? ['DragAndDropRank'] : []);
},
getFilterControlConfig: function () {
return _.merge(this.callParent(arguments), {
listeners: {
beforestaterestore: {
fn: this._onBeforeFilterButtonStateRestore,
scope: this
}
}
});
},
getGridBoardCustomFilterControlConfig: function() {
var context = this.getContext();
var isArtifactModel = this.models[0].isArtifact();
var blackListFields = isArtifactModel ? ['ModelType', 'PortfolioItemType', 'LastResult'] : ['ArtifactSearch', 'ModelType'];
var whiteListFields = isArtifactModel ? ['Milestones', 'Tags'] : [];
if (this.models[0].isProject()) {
blackListFields.push('SchemaVersion');
} else if (this.models[0].isRelease()) {
blackListFields.push('ChildrenPlannedVelocity', 'Version');
}
var config = {
ptype: 'rallygridboardinlinefiltercontrol',
inlineFilterButtonConfig: {
stateful: true,
stateId: context.getScopedStateId('custom-list-inline-filter'),
legacyStateIds: [
this.getScopedStateId('owner-filter'),
this.getScopedStateId('custom-filter-button')
],
filterChildren: true,
inlineFilterPanelConfig: {
quickFilterPanelConfig: {
defaultFields: isArtifactModel ? ['ArtifactSearch', 'Owner'] : [],
addQuickFilterConfig: {
blackListFields: blackListFields,
whiteListFields: whiteListFields
}
},
advancedFilterPanelConfig: {
advancedFilterRowsConfig: {
propertyFieldConfig: {
blackListFields: blackListFields,
whiteListFields: whiteListFields
}
}
}
}
}
};
if (isArtifactModel) {
config.inlineFilterButtonConfig.modelNames = this.modelNames;
} else {
config.inlineFilterButtonConfig.model = this.models[0];
}
return config;
},
getSharedViewConfig: function() {
var context = this.getContext();
return {
ptype: 'rallygridboardsharedviewcontrol',
sharedViewConfig: {
stateful: true,
stateId: context.getScopedStateId('custom-list-shared-view'),
enableUrlSharing: this.isFullPageApp !== false
}
};
},
getGridBoardConfig: function () {
var config = this.callParent(arguments);
return _.merge(config, {
listeners: {
viewchange: function() {
this.loadGridBoard();
},
filterchange: function() {
this.gridboard.getGridOrBoard().noDataPrimaryText = undefined;
this.gridboard.getGridOrBoard().noDataSecondaryText = undefined;
},
scope: this
}
});
},
onTreeGridReady: function (grid) {
if (grid.store.getTotalCount() > 10) {
this.gridboard.down('#pagingToolbar').show();
}
this.callParent(arguments);
},
getGridStoreConfig: function () {
var sorters = this._getValidSorters(Rally.data.util.Sorter.sorters(this.getSetting('order')));
if (_.isEmpty(sorters)) {
var rankField = this.getContext().getWorkspace().WorkspaceConfiguration.DragDropRankingEnabled ? 'DragAndDropRank' : 'Rank';
var defaultSort = Rally.data.ModelTypes.areArtifacts(this.modelNames) ? rankField : Rally.data.util.Sorter.getDefaultSort(this.modelNames[0]);
sorters = Rally.data.util.Sorter.sorters(defaultSort);
}
return {
listeners: {
warning: {
fn: this._onGridStoreWarning,
scope: this
}
},
pageSize: 10,
sorters: sorters
};
},
getAddNewConfig: function () {
var config = {
minWidth: 700,
openEditorAfterAddFailure: false,
margin: 0
};
return _.merge(this.callParent(arguments), config);
},
getFieldPickerConfig: function () {
return _.merge(this.callParent(arguments), {
buttonConfig: {
disabled: !this._userHasPermissionsToEditPanelSettings()
},
gridAlwaysSelectedValues: function () { return []; },
gridFieldBlackList: this._shouldEnableRanking() ? [] : ['Rank']
});
},
getPermanentFilters: function () {
return this._getQueryFilter().concat(this._getTimeboxScopeFilter()).concat(this._getProjectFilter());
},
onTimeboxScopeChange: function() {
this.callParent(arguments);
this.loadGridBoard();
},
clearFiltersAndSharedViews: function() {
var context = this.getContext();
if (this.gridboard) {
this.gridboard.down('rallyinlinefilterpanel').clear();
this.gridboard.down('rallysharedviewcombobox').reset();
}
Ext.create('Rally.data.wsapi.Store', {
model: Ext.identityFn('preference'),
autoLoad: true,
filters: [
{property: 'AppId', value: context.getAppId()},
{property: 'Type', value: 'View'},
{property: 'Workspace', value: context.getWorkspace()._ref}
],
context: context.getDataContext(),
listeners: {
load: function(store, records) {
if(!_.isEmpty(records)) {
var batchStore = Ext.create('Rally.data.wsapi.batch.Store', {
requester: this,
data: records
});
batchStore.removeAll();
batchStore.sync();
}
store.destroyStore();
},
scope: this
}
});
},
getTypeSetting: function() {
return (this.getSetting('type') || this.getSetting('url') || '').toLowerCase().split(',');
},
_getColumnNamesSetting: function() {
return this.getSetting('columnNames') ||
(this.getSetting('fetch') || '').split(',');
},
_getQueryFilter: function () {
var query = new Ext.Template(this.getSetting('query')).apply({
projectName: this.getContext().getProject().Name,
projectOid: this.getContext().getProject().ObjectID,
user: this.getContext().getUser()._ref
});
if (query) {
try {
return [ Rally.data.wsapi.Filter.fromQueryString(query) ];
} catch(e) {
Rally.ui.notify.Notifier.showError({ message: e.message });
}
}
return [];
},
_getProjectFilter: function () {
return this.modelNames[0].toLowerCase() === 'milestone' ? [
Rally.data.wsapi.Filter.or([
{ property: 'Projects', operator: 'contains', value: this.getContext().getProjectRef() },
{ property: 'TargetProject', operator: '=', value: null }
])
] : [];
},
_getTimeboxScopeFilter: function () {
var timeboxScope = this.getContext().getTimeboxScope();
var hasTimeboxField = timeboxScope && _.any(this.models, timeboxScope.isApplicable, timeboxScope);
return hasTimeboxField ? [ timeboxScope.getQueryFilter() ] : [];
},
_shouldEnableAddNew: function() {
return _.intersection(this.disallowedAddNewTypes, this.getTypeSetting()).length === 0;
},
_shouldEnableRanking: function() {
return !_.contains(this.getTypeSetting(), 'task');
},
_setColumnNames: function (columnNames) {
this.columnNames = _.compact(_.isString(columnNames) ? columnNames.split(',') : columnNames);
},
_onBeforeFilterButtonStateRestore: function (filterButton, state) {
if (state && state.filters && state.filters.length) {
var stateFilters = _.map(state.filters, function (filterStr) {
return Rally.data.wsapi.Filter.fromQueryString(filterStr);
});
var validFilters = Rally.util.Filter.removeNonapplicableTypeSpecificFilters(stateFilters, this.models);
state.filters = _.invoke(validFilters, 'toString');
}
},
_hasViewSelected: function() {
var sharedViewConfig = this.getSharedViewConfig().sharedViewConfig;
if (sharedViewConfig && sharedViewConfig.stateId) {
var value = (Ext.state.Manager.get(sharedViewConfig.stateId) || {}).value;
return !_.isEmpty(value);
}
return false;
},
_onBeforeGridStateRestore: function (grid, state) {
if (!state) {
return;
}
if (state.columns) {
var appScopedColumnNames = this._getValidUuids(grid, this.getColumnCfgs());
var userScopedColumnNames = this._getValidUuids(grid, state.columns);
if (this._hasViewSelected()) {
state.columns = userScopedColumnNames;
} else {
// Get the columns that are present in the app scope and not in the user scope
var differingColumns = _.difference(appScopedColumnNames, userScopedColumnNames);
// If there are columns in the app scope that are not in the
// user scope, append them to the user scope to preserve
// user scope column order
if (differingColumns.length > 0) {
state.columns = state.columns.concat(differingColumns);
}
// Filter out any columns that are in the user scope that are not in the
// app scope
state.columns = _.filter(state.columns, function (column) {
return _.contains(appScopedColumnNames, _.isObject(column) ? column.dataIndex : column);
}, this);
}
}
if (state.sorters) {
state.sorters = this._getValidSorters(state.sorters);
if (_.isEmpty(state.sorters)) {
delete state.sorters;
}
}
},
_getValidUuids: function(grid, columns) {
return _.reduce(columns, function(result, column) {
var dataIndex = this._getColumnDataIndex(column);
var field = this._getModelField(grid, dataIndex);
if (field) {
result.push(dataIndex);
}
return result;
}, [], this);
},
_getModelField: function(grid, dataIndex) {
return grid.getModels()[0].getField(dataIndex);
},
_getColumnDataIndex: function(column) {
return _.isObject(column) ? column.dataIndex : column;
},
_onBeforeGridStateSave: function (grid, state) {
var newColumnNames = this._getColumnNamesFromState(state);
if (!_.isEmpty(newColumnNames)) {
this._setColumnNames(newColumnNames);
if (this._userHasPermissionsToEditPanelSettings()) {
this.updateSettingsValues({
settings: {
columnNames: newColumnNames.join(',')
}
});
}
}
},
_onGridStoreWarning: function(store, warnings, operation) {
var couldNotParseWarnings = _.filter(warnings, function(warning){
return Rally.util.String.startsWith(warning, 'Could not parse ');
});
if(couldNotParseWarnings.length) {
_.assign(operation.resultSet, {
count: 0,
records: [],
total: 0,
totalRecords: 0
});
this._showInvalidQueryMessage(this.gridboard.getGridOrBoard(), couldNotParseWarnings);
}
},
_showInvalidQueryMessage: function(gridOrGridConfig, secondaryTextStrings) {
gridOrGridConfig.noDataPrimaryText = 'Invalid Query';
gridOrGridConfig.noDataSecondaryText = _.map(secondaryTextStrings, function(str){
return '<div>' + str + '</div>';
}).join('');
},
_getValidSorters: function (sorters) {
return _.filter(sorters, function (sorter) {
return _.any(this.models, function (model) {
var field = model.getField(sorter.property);
return field && field.sortable;
});
}, this);
},
_userHasPermissionsToEditPanelSettings: function () {
return this.isEditable;
},
_getColumnNamesFromState: function (state) {
return _(state && state.columns).map(function (newColumn) {
return _.isObject(newColumn) ? newColumn.dataIndex : newColumn;
}).compact().value();
}
});
})();