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

fix #6070: hierarchical sorting #7163

Merged
merged 19 commits into from
Aug 8, 2024
73 changes: 57 additions & 16 deletions sirepo/package_data/static/js/raydata.js
Original file line number Diff line number Diff line change
Expand Up @@ -446,7 +446,7 @@ SIREPO.app.directive('scansTable', function() {
<tr>
<th style="width: 20px; height: 40px; white-space: nowrap" data-ng-show="showPdfColumn"><input type="checkbox" data-ng-checked="pdfSelectAllScans" data-ng-click="togglePdfSelectAll()"/> <span style="vertical-align: top">PDF</span></th>
<th data-ng-repeat="column in columnHeaders track by $index" class="raydata-removable-column" style="width: 100px; height: 40px; white-space: nowrap">
<span data-ng-if="columnIsSortable(column)" style="color:lightgray;" data-ng-class="arrowClass(column)"></span>
<span data-ng-if="columnIsSortable(column)" style="{{ arrowStyle(column) }}" data-ng-class="arrowClass(column)"></span>
<span data-ng-attr-style="{{ columnIsSortable(column) ? 'cursor: pointer;' : '' }}" data-ng-click="sortCol(column)">{{ column }}</span>
<button type="submit" class="btn btn-info btn-xs raydata-remove-column-button" data-ng-if="showDeleteButton($index)" data-ng-click="deleteCol(column)"><span class="glyphicon glyphicon-remove"></span></button>
</th>
Expand Down Expand Up @@ -502,10 +502,11 @@ SIREPO.app.directive('scansTable', function() {
let scanArgs = {
pageCount: 0,
pageNumber: 0,
sortColumn: $scope.analysisStatus == 'queued' ? 'queue order' : 'start',
sortOrder: $scope.analysisStatus == 'queued',
sortColumns: defaultSortColumns(),
};

const MAX_NUM_SORT_COLUMNS = 3;

const errorOptions = {
modelName: $scope.modelName,
onError: data => {
Expand Down Expand Up @@ -540,6 +541,14 @@ SIREPO.app.directive('scansTable', function() {
}
}

function defaultSortColumns() {
if ($scope.analysisStatus == 'queued') {
return [['queue order', true]];
} else {
return [['start', false]];
}
}

function findScan(scanId) {
return $scope.scans[
$scope.scans.findIndex(s => s.rduid === scanId)
Expand Down Expand Up @@ -579,8 +588,7 @@ SIREPO.app.directive('scansTable', function() {
}
scanArgs.pageCount = scanInfo.pageCount || 0;
scanArgs.pageNumber = scanInfo.pageNumber;
scanArgs.sortColumn = scanInfo.sortColumn;
scanArgs.sortOrder = scanInfo.sortOrder;
scanArgs.sortColumns = scanInfo.sortColumns;
updatePageLocation();
}

Expand Down Expand Up @@ -629,8 +637,7 @@ SIREPO.app.directive('scansTable', function() {
pageNumber: scanArgs.pageNumber,
searchText: m.searchText,
searchTerms: buildSearchTerms(m.searchTerms),
sortColumn: scanArgs.sortColumn,
sortOrder: scanArgs.sortOrder,
sortColumns: scanArgs.sortColumns
}
},
errorOptions
Expand Down Expand Up @@ -711,13 +718,29 @@ SIREPO.app.directive('scansTable', function() {
}

$scope.arrowClass = column => {
if (scanArgs.sortColumn !== column) {
return {};
let r = {};
scanArgs.sortColumns.forEach((sortField) => {
if (sortField[0] === column) {
r= {
glyphicon: true,
[`glyphicon-arrow-${sortField[1] ? 'up' : 'down'}`]: true,
};
}
});
return r;
};

$scope.arrowStyle = column => {
let r = '';
for (const [i, sortField] of scanArgs.sortColumns.entries()) {
if (sortField[0] === column) {
// logic for alpha value assumes that sortColumns are in descending priority and MAX_NUM_SORT_COLUMNS is 3
let a = i === 0 ? 1 : (-0.3 * i) + 0.8;
rorour marked this conversation as resolved.
Show resolved Hide resolved
r = `color: rgba(0, 0, 0, ${a})`;
break;
}
}
return {
glyphicon: true,
[`glyphicon-arrow-${scanArgs.sortOrder ? 'up' : 'down'}`]: true,
};
return r;
};

$scope.canNextPage = () => {
Expand Down Expand Up @@ -843,15 +866,33 @@ SIREPO.app.directive('scansTable', function() {
};

$scope.columnIsSortable = (column) => {
return column !== 'stop';
return ! (column === 'stop' || $scope.scans.length > 0 && $scope.scans[0][column] !== null && typeof $scope.scans[0][column] === 'object');
};


$scope.sortCol = column => {
if (! $scope.columnIsSortable(column)) {
return;
}
scanArgs.sortColumn = column;
scanArgs.sortOrder = ! scanArgs.sortOrder;
let inList = false;
scanArgs.sortColumns.forEach((sortField, i) => {
if (sortField[0] === column) {
inList = true;
sortField[1] = ! sortField[1];
scanArgs.sortColumns.splice(i, 1);
scanArgs.sortColumns.unshift(sortField);
}
});
if (! inList) {
if ($scope.analysisStatus !== 'allStatuses') {
scanArgs.sortColumns = [[column, true]];
} else {
scanArgs.sortColumns.unshift([column, true]);
if (scanArgs.sortColumns.length > MAX_NUM_SORT_COLUMNS) {
scanArgs.sortColumns.pop();
}
}
}
sendScanRequest(true, true);
};

Expand Down
47 changes: 23 additions & 24 deletions sirepo/raydata/scan_monitor.py
Original file line number Diff line number Diff line change
Expand Up @@ -348,25 +348,6 @@ def _search_params(req_data):
}
return q

def _sort_params(req_data):
c = _default_columns(req_data.catalogName).get(
req_data.sortColumn, req_data.sortColumn
)
s = [
(
c,
pymongo.ASCENDING if req_data.sortOrder else pymongo.DESCENDING,
),
]
if c != "time":
s.append(
(
"time",
pymongo.DESCENDING,
)
)
return s

c = sirepo.raydata.databroker.catalog(req_data.catalogName)
pc = math.ceil(
len(
Expand Down Expand Up @@ -530,6 +511,24 @@ async def _sr_post(self, *args, **kwargs):
self.write(await self._incoming(PKDict(pkjson.load_any(self.request.body))))


def _sort_params(req_data):
r = []
has_time = False
for x in req_data.sortColumns:
n = _default_columns(req_data.catalogName).get(x[0], x[0])
if n == "time":
has_time = True
r.append(
[
n,
pymongo.ASCENDING if x[1] else pymongo.DESCENDING,
]
)
if not has_time:
r.append(["time", pymongo.DESCENDING])
return r


async def _init_analysis_processors():
global _ANALYSIS_PROCESSOR_TASKS

Expand Down Expand Up @@ -730,9 +729,10 @@ def _get_start_field(metadata, column):

def _scan_info_result(scans, page_count, req_data):
def _compare_values(v1, v2):
sort_column = _sort_params(req_data)[0][0]
# very careful compare - needs to account for missing values or mismatched types
v1 = v1.get(req_data.sortColumn)
v2 = v2.get(req_data.sortColumn)
v1 = v1.get(sort_column)
v2 = v2.get(sort_column)
if v1 is None and v2 is None:
return 0
if v1 is None:
Expand Down Expand Up @@ -765,16 +765,15 @@ def _compare_values(v1, v2):
s = sorted(
s,
key=functools.cmp_to_key(_compare_values),
reverse=not req_data.sortOrder,
reverse=not _sort_params(req_data)[0][1],
)
return PKDict(
data=PKDict(
scans=s,
cols=_display_columns(all_columns),
pageCount=page_count,
pageNumber=req_data.pageNumber,
sortColumn=req_data.sortColumn,
sortOrder=req_data.sortOrder,
sortColumns=req_data.sortColumns,
)
)

Expand Down