blob: 380542c23d06297f57a42c974f56a60ff5137610 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import {Observable, merge} from 'rxjs';
import {share, distinctUntilChanged, startWith, filter, map, pluck, withLatestFrom, mapTo} from 'rxjs/operators';
import {RejectType, TransitionService} from '@uirouter/angularjs';
import isEqual from 'lodash/isEqual';
configSelectionManager.$inject = ['$transitions'];
export default function configSelectionManager($transitions: TransitionService) {
/**
* Determines what items should be marked as selected and if something is being edited at the moment.
*/
return ({itemID$, selectedItemRows$, visibleRows$, loadedItems$}) => {
// Aborted transitions happen when form has unsaved changes, user attempts to leave
// but decides to stay after screen asks for leave confirmation.
const abortedTransitions$ = Observable.create((observer) => {
return $transitions.onError({}, (t) => observer.next(t));
}).pipe(filter((t) => t.error().type === RejectType.ABORTED));
const firstItemID$ = visibleRows$.pipe(
withLatestFrom(itemID$, loadedItems$),
filter(([rows, id, items]) => !id && rows && rows.length === items.length),
pluck('0', '0', 'entity', '_id')
);
const selectedItemRowsIDs$ = selectedItemRows$.pipe(map((rows) => rows.map((r) => r._id)), share());
const singleSelectionEdit$ = selectedItemRows$.pipe(filter((r) => r && r.length === 1), pluck('0', '_id'));
const selectedMultipleOrNone$ = selectedItemRows$.pipe(filter((r) => r.length > 1 || r.length === 0));
const loadedItemIDs$ = loadedItems$.pipe(map((rows) => new Set(rows.map((r) => r._id))), share());
const currentItemWasRemoved$ = loadedItemIDs$.pipe(
withLatestFrom(
itemID$.pipe(filter((v) => v && v !== 'new')),
/**
* Without startWith currentItemWasRemoved$ won't emit in the following scenario:
* 1. User opens items page (no item id in location).
* 2. Selection manager commands to edit first item.
* 3. User removes said item.
*/
selectedItemRowsIDs$.pipe(startWith([]))
),
filter(([existingIDs, itemID, selectedIDs]) => !existingIDs.has(itemID)),
map(([existingIDs, itemID, selectedIDs]) => selectedIDs.filter((id) => id !== itemID)),
share()
);
// Edit first loaded item or when there's only one item selected
const editGoes$ = merge(firstItemID$, singleSelectionEdit$).pipe(
// Don't go to non-existing items.
// Happens when user naviagtes to older history and some items were already removed.
withLatestFrom(loadedItemIDs$),
filter(([id, loaded]) => id && loaded.has(id)),
pluck('0')
);
// Stop edit when multiple or none items are selected or when current item was removed
const editLeaves$ = merge(
selectedMultipleOrNone$.pipe(mapTo({})),
currentItemWasRemoved$.pipe(mapTo({location: 'replace', custom: {justIDUpdate: true}}))
).pipe(share());
const selectedItemIDs$ = merge(
// Select nothing when creating an item or select current item
itemID$.pipe(filter((id) => id), map((id) => id === 'new' ? [] : [id])),
// Restore previous item selection when transition gets aborted
abortedTransitions$.pipe(withLatestFrom(itemID$, (_, id) => [id])),
// Select all incoming selected rows
selectedItemRowsIDs$
).pipe(
// If nothing's selected and there are zero rows, ui-grid will behave as if all rows are selected
startWith([]),
// Some scenarios cause same item to be selected multiple times in a row,
// so it makes sense to filter out duplicate entries
distinctUntilChanged(isEqual),
share()
);
return {selectedItemIDs$, editGoes$, editLeaves$};
};
}