Files
2026-06-17 14:00:51 +02:00

294 lines
9.5 KiB
JavaScript

/**
* Create a roster view.
*
* @type undefined
* @param {scope} $scope the controller's scope
* @param {loader} $translatePartialLoader I18N support provider
* @param {angularService} $http Angular HTTP provider
* @param {angularService} $log Angular logger
* @param {angularService} jmriWebSocket JMRI web socket provider
* @param {angularService} pfViewUtils Patternfly utilities for handling data views
* @param {angularService} $filter Patternfly filter service
*/
angular.module('jmri.app').controller('RosterCtrl', function RosterCtrl($scope, $translate, $translatePartialLoader, $http, $log, jmriWebSocket, pfViewUtils, $filter) {
// load translations
$translatePartialLoader.addPart('web/roster');
// true if loading indicator should be shown; false otherwise
$scope.loading = true;
// columns for table view with default text
$scope.columns = [
{header: 'ID', itemField: 'name'},
{header: 'DCC Address', itemField: 'address'},
{header: 'Road Name', itemField: 'road'},
{header: 'Road Number', itemField: 'number'},
{header: 'Owner', itemField: 'owner'}
];
// translate column headers
for (var i in $scope.columns) {
var c = $scope.columns[i];
$translate('ROSTER.FIELD.' + c.itemField).then(function(translation) {
c.header = translation;
}, function(translationId) {
$log.error('Unable to translate ' + translationId);
});
$scope.columns[i] = c;
}
// the roster items, initially an empty list
$scope.allItems = [];
$scope.items = $scope.allItems;
//
// Cards/List/Table Views
//
$scope.listConfig = {
selectionMatchProp: 'name',
checkDisabled: false,
itemsAvailable: true,
onCheckBoxChange: handleCheckBoxChange
};
$scope.emptyStateConfig = {
icon: 'pficon-warning-triangle-o', // replace with pficon-add-circle-o once patternfly/angular-patterfly#510 is addressed
title: 'No Roster Entries',
info: 'There are no roster entries to show. If this is unexpected, review the roster preferences in JMRI.',
helpLink: {
label: 'For more information please see',
urlLabel: 'JMRI: DecoderPro User Guide',
url: '/help/en/html/apps/DecoderPro/Roster.shtml'
}
};
$scope.emptyStateActions = [
{name: 'Upload Roster Entry', title: 'Upload a roster entry.', actionFn: uploadEntry, type: 'main'}
];
$translate(['ROSTER.EMPTY.TITLE', 'ROSTER.EMPTY.INFO', 'ROSTER.EMPTY.HELP.LABEL', 'ROSTER.EMPTY.HELP.URL_LABEL', 'ROSTER.ACTION.UPLOAD.FULLNAME', 'ROSTER.ACTION.UPLOAD.TITLE'])
.then(function(translations) {
$scope.emptyStateConfig.title = translations['ROSTER.EMPTY.TITLE'];
$scope.emptyStateConfig.info = translations['ROSTER.EMPTY.INFO'];
$scope.emptyStateConfig.helpLink.label = translations['ROSTER.EMPTY.HELP.LABEL'];
$scope.emptyStateConfig.helpLink.urlLabel = translations['ROSTER.EMPTY.HELP.URL_LABEL'];
$scope.emptyStateActions[0].name = translations['ROSTER.ACTION.UPLOAD.FULLNAME'];
$scope.emptyStateActions[0].title = translations['ROSTER.ACTION.UPLOAD.TITLE'];
}, function(translationIds) {
$log.error('Unable to translate emptyStateConfig elements');
});
$scope.tableConfig = {
onCheckBoxChange: handleCheckBoxChange,
selectionMatchProp: 'name',
itemsAvailable: true,
};
$scope.dtOptions = {
dom: 't'
}
//
// Toolbar
//
// View handling
var viewSelected = function(viewId) {
$scope.viewType = viewId;
$scope.sortConfig.show = ($scope.viewType === 'tableView' ? false : true);
};
$scope.viewsConfig = {
views: [pfViewUtils.getListView(), pfViewUtils.getCardView(), pfViewUtils.getTableView()],
onViewSelect: viewSelected
};
$scope.viewsConfig.currentView = $scope.viewsConfig.views[0].id;
$scope.viewType = $scope.viewsConfig.currentView;
// Filter handling
var matchesFilter = function (item, filter) {
var match = true;
var re = new RegExp(filter.value, 'i');
if (filter.id === 'name') {
match = item.name.match(re) !== null;
} else if (filter.id === 'road') {
match = item.road.match(re) !== null;
} else if (filter.id === 'number') {
match = item.number.match(re) !== null;
} else if (filter.id === 'address') {
match = item.address === parseInt(filter.value);
} else if (filter.id === 'owner') {
match = item.owner.match(re) !== null;
}
return match;
};
var matchesFilters = function (item, filters) {
var matches = true;
filters.forEach(function(filter) {
if (!matchesFilter(item, filter)) {
matches = false;
return false;
}
});
return matches;
};
var applyFilters = function (filters) {
$scope.items = [];
if (filters && filters.length > 0) {
$scope.allItems.forEach(function (item) {
if (matchesFilters(item, filters)) {
$scope.items.push(item);
}
});
} else {
$scope.items = $scope.allItems;
}
};
var filterChange = function(filters) {
applyFilters(filters);
$scope.toolbarConfig.filterConfig.resultsCount = $scope.items.length;
};
$scope.filterConfig = {
fields: [
{id: 'name', title: 'ID', placeholder: 'Filter by ID...', filterType: 'text'},
{id: 'address', title: 'DCC Address', placeholder: 'Filter by DCC Address...', filterType: 'text'},
{id: 'road', title: 'Road Name', placeholder: 'Filter by Road Name...', filterType: 'text'},
{id: 'number', title: 'Road Number', placeholder: 'Filter by Road Number...', filterType: 'text'},
{id: 'owner', title: 'Owner', placeholder: 'Filter by Owner...', filterType: 'text'}
],
resultsCount: $scope.items.length,
totalCount: $scope.allItems.length,
appliedFilters: [],
onFilterChange: filterChange
};
for (var i in $scope.filterConfig.fields) {
var f = $scope.filterConfig.fields[i];
$translate('ROSTER.FIELD.' + f.id).then(function(translation) {
f.title = translation;
}, function(translationId) {
$log.error('Unable to translate ' + translationId);
});
$translate('ROSTER.FILTER_PLACEHOLDER', f.title, 'filterTitle').then(function(translation) {
f.placeholder = translation;
}, function(translationId) {
$log.error('Unable to translate ' + translationId);
});
$scope.filterConfig.fields[i] = f;
}
var compareFn = function(item1, item2) {
var compValue = 0;
if ($scope.sortConfig.currentField.id === 'name') {
compValue = item1.name.localeCompare(item2.name);
} else if ($scope.sortConfig.currentField.id === 'address') {
compValue = item1.address - item2.address;
} else if ($scope.sortConfig.currentField.id === 'road') {
compValue = item1.road.localeCompare(item2.road);
} else if ($scope.sortConfig.currentField.id === 'number') {
compValue = item1.number - item2.number;
} else if ($scope.sortConfig.currentField.id === 'owner') {
compValue = item1.owner.localeCompare(item2.owner);
}
if (!$scope.sortConfig.isAscending) {
compValue = compValue * -1;
}
return compValue;
};
var sortChange = function (sortId, isAscending) {
$scope.items.sort(compareFn);
};
$scope.sortConfig = {
fields: [
{id: 'name', title: 'ID', sortType: 'alpha'},
{id: 'address', title: 'DCC Address', sortType: 'numeric'},
{id: 'road', title: 'Road Name', sortType: 'alpha'},
{id: 'number', title: 'Road Number', sortType: 'numeric'},
{id: 'owner', title: 'Owner', sortType: 'alpha'}
],
onSortChange: sortChange
};
for (var i in $scope.sortConfig.fields) {
var c = $scope.sortConfig.fields[i];
$translate('ROSTER.FIELD.' + c.id).then(function(translation) {
c.title = translation;
}, function(translationId) {
$log.error('Unable to translate ' + translationId);
});
$scope.sortConfig.fields[i] = c;
}
$scope.toolbarConfig = {
viewsConfig: $scope.viewsConfig,
filterConfig: $scope.filterConfig,
sortConfig: $scope.sortConfig
// actionsConfig: $scope.actionsConfig
};
//
// Handlers
//
function handleCheckBoxChange (item) {
var selectedItems = $filter('filter')($scope.allItems, {selected: true});
if (selectedItems) {
$scope.toolbarConfig.filterConfig.selectedCount = selectedItems.length;
}
}
function uploadEntry() {
}
//
// Websockets
//
// register a listener for sensors with the jmriWebSocket service
// this listener determines if a notification needs to be shown or cleared
// this.webSocket = jmriWebSocket.register();
$http.get('/json/roster').then(
// handle a successful get for the roster
function(response) {
if (Array.isArray(response.data)) {
for (var i in response.data) {
var entry = response.data[i];
if (entry.type === 'rosterEntry') {
$scope.allItems.push(entry.data);
$scope.toolbarConfig.filterConfig.totalCount = $scope.allItems.length;
}
}
$scope.items = $scope.allItems;
filterChange($scope.toolbarConfig.filterConfig.appliedFilters);
} else {
var entry = response.data;
if (entry.type === 'rosterEntry') {
$scope.allItems.push(entry.data);
$scope.toolbarConfig.filterConfig.totalCount = $scope.allItems.length;
$scope.items = $scope.allItems;
filterChange($scope.toolbarConfig.filterConfig.appliedFilters);
}
}
jmriWebSocket.get('roster', {});
$scope.loading = false;
},
// handle a failed get for the roster
function(response) {
$log.error('Unable to query JMRI web server for roster.');
$scope.loading = false;
}
);
});