<commit_before>import _ from 'lodash';
import {gettext} from 'core/utils';
import {appConfig} from 'appConfig';
import {ISearchOptions} from '../services/SearchService';
import {IPackagesService} from 'types/Services/Packages';

SearchResults.$inject = [
    '$location',
    'preferencesService',
    'packages',
    'asset',
    '$timeout',
    'api',
    'search',
    'session',
    '$rootScope',
    'superdeskFlags',
    'notify',
];

const HEX_REG_EXP = /[a-f0-9]{24}/;

function isObjectId(value) {
    return value != null && value.length === 24 && HEX_REG_EXP.test(value);
}

/**
 * @ngdoc directive
 * @module superdesk.apps.search
 * @name sdSearchResults
 *
 * @requires $location
 * @requires preferencesService
 * @requires packages
 * @requires asset
 * @requires $timeout
 * @requires api
 * @requires search
 * @requires session
 * @requires $rootScope
 *
 * @description Item list with sidebar preview
 */
export function SearchResults(
    $location,
    preferencesService,
    packages: IPackagesService,
    asset,
    $timeout,
    api,
    search,
    session,
    $rootScope,
    superdeskFlags,
    notify,
) { // uff - should it use injector instead?
    var preferencesUpdate = {
        'archive:view': {
            allowed: [
                'mgrid',
                'compact',
            ],
            category: 'archive',
            view: 'mgrid',
            default: 'mgrid',
            label: 'Users archive view format',
            type: 'string',
        },
    };

    return {
        require: '^sdSearchContainer',
        templateUrl: asset.templateUrl('apps/search/views/search-results.html'),
        link: function(scope, elem, attr, controller) {
            var containerElem = elem.find('.shadow-list-holder');
            var GRID_VIEW = 'mgrid',
                LIST_VIEW = 'compact';

            var projections = search.getProjectedFields();
            var multiSelectable = attr.multiSelectable !== undefined;

            scope.previewingBroadcast = false;
            superdeskFlags.flags.previewing = false;

            // allow controller overwrite getSearch
            const getSearch = typeof scope.search.getSearch === 'function'
                ? scope.search.getSearch
                : () => $location.search();

            const queryOptions: ISearchOptions = {
                hidePreviousVersions: scope.search.hideNested === true,
            };

            var criteria = search.query(getSearch(), queryOptions).getCriteria(true),
                oldQuery = _.omit(getSearch(), '_id');

            scope.flags = controller.flags;
            scope.selected = scope.selected || {};
            scope.showHistoryTab = true;

            scope.context = 'search';
            scope.$on('item:deleted:archived', itemDelete);
            scope.$on('item:fetch', queryItems);
            scope.$on('item:update', updateItem);
            scope.$on('item:deleted', scheduleIfShouldUpdate);
            scope.$on('item:unlink', queryItems);
            scope.$on('item:spike', scheduleIfShouldUpdate);
            scope.$on('item:unspike', scheduleIfShouldUpdate);
            scope.$on('item:duplicate', queryItems);
            scope.$on('item:translate', queryItems);
            scope.$on('item:marked_desks', queryItems);

            // used by superdesk-fi
            scope.showtags = attr.showtags !== 'false';

            // Custom components for item fields
            scope.customRender = scope.search.customRender || {};

            scope.$on('ingest:update', (event, args) => {
                if (!scope.showRefresh) {
                    queryItems(event, args);
                }
            });

            scope.$on('content:update', queryItems);
            scope.$on('item:move', scheduleIfShouldUpdate);

            scope.$on('aggregations:changed', queryItems);

            scope.$on('broadcast:preview', (event, args) => {
                scope.previewingBroadcast = true;
                scope.preview(args.item);
            });

            scope.$on('broadcast:created', (event, args) => {
                scope.previewingBroadcast = true;
                queryItems();
                scope.preview(args.item);
            });

            scope.$watch('selected', (newVal, oldVal) => {
                if (!newVal && scope.previewingBroadcast) {
                    scope.previewingBroadcast = false;
                }
            });

            scope.$watch(function getSearchParams() {
                return _.omit(getSearch(), ['_id', 'item', 'action']);
            }, (newValue, oldValue) => {
                if (newValue !== oldValue) {
                    scope.refreshList();
                }
            }, true);

            // public api - called by list when needed
            scope.fetchNext = function() {
                render(null, true);
            };

            var nextUpdate;

            function updateItem(e, data) {
                var item = _.find(scope.items._items, {_id: data.item._id});

                if (item) {
                    angular.extend(item, data.item);
                }
            }

            /**
             * Schedule an update if it's not there yet
             */
            function queryItems(event?, data?) {
                if (isObjectId(scope.search.repo.search)) {
                    // external provider, don't refresh on any event
                    return;
                }

                if (!nextUpdate) {
                    if (scope.search.repo.search !== 'local' && !getSearch().q && !(data && data.force)) {
                        return; // ignore updates with external content
                    }

                    scope.loading = true;
                    nextUpdate = $timeout(() => {
                        _queryItems(event, data)
                            .finally(() => {
                                scope.$applyAsync(() => {
                                    nextUpdate = null;
                                });
                            });
                    }, 1000, false);
                }
            }

            /**
             * Function for fetching total items and filling scope for the first time.
             */
            function _queryItems(event?, data?) {
                criteria = search.query(getSearch(), queryOptions).getCriteria(true);
                criteria.source.size = 50;
                var originalQuery;

                // when forced refresh or query then keep query size default as set 50 above.
                if (!(data && data.force)) {
                    // To compare current scope of items, consider fetching same number of items.
                    if (scope.items && scope.items._items.length > 50) {
                        criteria.source.size = scope.items._items.length;
                    }
                }

                if (data && (data.item || data.items || data.item_id) && scope.showRefresh && !data.force) {
                    // if we know the ids of the items then try to fetch those only
                    originalQuery = angular.extend({}, criteria.source.query);

                    let items = data.items || {};

                    if (data.item || data.item_id) {
                        items[data.item || data.item_id] = 1;
                    }

                    criteria.source.query = search.getItemQuery(data.items);
                } else {
                    criteria.aggregations = $rootScope.aggregations;
                }

                criteria.source.from = 0;
                scope.total = null;
                criteria.es_highlight = search.getElasticHighlight();
                criteria.projections = JSON.stringify(projections);

                if (getSearch().params) {
                    criteria.params = JSON.parse(getSearch().params);
                }

                return api.query(getProvider(criteria), criteria).then((items) => {
                    if (appConfig.features.autorefreshContent && data != null) {
                        data.force = true;
                    }

                    if (!scope.showRefresh && data && !data.force && data.user !== session.identity._id) {
                        const _data = {
                            newItems: items,
                            scopeItems: scope.items,
                            scrollTop: containerElem.scrollTop(),
                            isItemPreviewing: !!scope.selected.preview,
                        };

                        scope.showRefresh = search.canShowRefresh(_data);
                    }

                    if (!scope.showRefresh || data && data.force) {
                        scope.total = items._meta.total;
                        scope.$applyAsync(() => {
                            render(items, null, true);
                        });
                    } else {
                        // update scope items only with the matching fetched items
                        scope.items = search.updateItems(items, scope.items);
                    }

                    if (originalQuery) {
                        criteria.source.query = originalQuery;
                    }
                }, (error) => {
                    notify.error(gettext('Failed to run the query!'));
                    console.error(error, getProvider(criteria));
                })
                    .finally(() => {
                        scope.loading = false;
                    });
            }

            function scheduleIfShouldUpdate(event, data) {
                if (data && data.item && _.includes(['item:spike', 'item:unspike', 'item:deleted'], event.name)) {
                    // item was spiked/unspikes from the list
                    extendItem(data.item, {
                        gone: true,
                        _etag: data.item,
                    });
                    queryItems(event, data);
                } else if (data && data.from_stage) {
                    // item was moved from current stage
                    extendItem(data.item, {
                        gone: true,
                        _etag: data.from_stage, // this must change to make it re-render
                    });
                    queryItems(event, data);
                }
            }

            function extendItem(itemId, updates) {
                scope.$apply(() => {
                    scope.items._items = scope.items._items.map((item) => {
                        if (item._id === itemId) {
                            return angular.extend(item, updates);
                        }

                        return item;
                    });

                    scope.items = angular.extend({}, scope.items); // trigger a watch
                });
            }

            scope.$on('refresh:list', (event, group) => {
                scope.refreshList();
            });

            scope.refreshList = function() {
                scope.showRefresh = false;
                queryItems(null, {force: true});
                if (containerElem[0].scrollTop > 0) {
                    containerElem[0].scrollTop = 0;
                }
            };

            /*
             * Function to get the search endpoint name based on the criteria
             *
             * @param {Object} _criteria
             * @returns {string}
             */
            function getProvider(_criteria) {
                var provider = 'search';

                if (_criteria.repo && _criteria.repo.indexOf(',') === -1) {
                    provider = _criteria.repo;
                }

                if (scope.search.repo.search && scope.search.repo.search !== 'local') {
                    provider = scope.search.repo.search;
                }

                if (isObjectId(provider)) {
                    _criteria.repo = provider;
                    provider = 'search_providers_proxy';
                }

                if (provider === 'local') {
                    provider = 'search';
                }

                return provider;
            }

            /*
             * Function for fetching the elements from the database
             *
             * @param {items}
             */
            function render(items, next, force?) {
                scope.loading = true;
                if (items) {
                    setScopeItems(items, force);
                } else if (next) {
                    scope.loading = true;
                    criteria.source.from = (criteria.source.from || 0) + criteria.source.size;
                    criteria.source.size = 50;
                    criteria.projections = JSON.stringify(projections);

                    api
                        .query(getProvider(criteria), criteria)
                        .then(setScopeItems)
                        .finally(() => {
                            scope.loading = false;
                        });
                } else {
                    var query = _.omit(getSearch(), '_id');

                    if (!_.isEqual(_.omit(query, 'page'), _.omit(oldQuery, 'page'))) {
                        $location.search('page', null);
                    }

                    criteria = search.query(getSearch(), queryOptions).getCriteria(true);
                    criteria.source.from = 0;
                    criteria.source.size = 50;
                    criteria.aggregations = $rootScope.aggregations;
                    criteria.es_highlight = search.getElasticHighlight();
                    scope.loading = true;
                    criteria.projections = JSON.stringify(projections);

                    api
                        .query(getProvider(criteria), criteria)
                        .then(setScopeItems)
                        .finally(() => {
                            scope.loading = false;
                        });
                    oldQuery = query;
                }

                function setScopeItems(_items, _force) {
                    scope.items = search.mergeItems(_items, scope.items, next, _force);
                    scope.total_records = _items._meta.total;
                    scope.loading = false;
                }
            }

            /*
             * Function for updating list
             * after item has been deleted
             */
            function itemDelete(e, data) {
                if (session.identity._id === data.user) {
                    queryItems();
                }
            }

            scope.preview = function preview(item) {
                if (multiSelectable) {
                    if (_.findIndex(scope.selectedList, {_id: item._id}) === -1) {
                        scope.selectedList.push(item);
                    } else {
                        _.remove(scope.selectedList, {_id: item._id});
                    }
                }

                if (item) {
                    if (item._type === 'externalsource') {
                        processPreview(item);
                        return;
                    }

                    scope.loading = true;
                    let previewCriteria = search.getSingleItemCriteria(item);

                    api.query(getProvider(previewCriteria), previewCriteria).then((completeItems) => {
                        let completeItem = search.mergeHighlightFields(completeItems._items[0]);

                        processPreview(completeItem);
                    })
                        .finally(() => {
                            scope.loading = false;
                        });
                } else {
                    delete scope.selected.preview;
                    superdeskFlags.flags.previewing = false;
                    sendRowViewEvents();
                }
            };

            /**
             * @ngdoc method
             * @name sdSearchResults#sendRowViewEvents
             * @private
             * @param {Object} item
             * @description If singLine:view preference is set, an item is being previewed, config has narrowView list
             * then, sends rowview event
             */
            function sendRowViewEvents(item?) {
                let sendEvent = scope.singleLine
                    && superdeskFlags.flags.authoring
                    && appConfig.list != null
                    && appConfig.list.narrowView;

                let evnt = item ? 'rowview:narrow' : 'rowview:default';

                if (sendEvent) {
                    $rootScope.$broadcast(evnt);
                }
            }

            /**
             * @ngdoc method
             * @name sdSearchResults#processPreview
             * @private
             * @param {Object} item
             * @description Sets the preview item
             */
            function processPreview(item) {
                scope.selected.preview = item;

                if (!_.isNil(scope.selected.preview)) {
                    scope.showHistoryTab = scope.selected.preview.state !== 'ingested' &&
                    !_.includes(['archived', 'externalsource'], scope.selected.preview._type);

                    superdeskFlags.flags.previewing = true;
                    sendRowViewEvents(item);
                }

                $location.search('_id', item ? item._id : null);
            }

            scope.openLightbox = function openLightbox() {
                scope.selected.view = scope.selected.preview;
            };

            scope.closeLightbox = function closeLightbox() {
                scope.selected.view = null;
            };

            scope.openSingleItem = function(packageItem) {
                packages.fetchItem(packageItem).then((item) => {
                    scope.selected.view = item;
                });
            };

            scope.setview = setView;

            var savedView;

            preferencesService.get('archive:view').then((result) => {
                savedView = result.view;
                scope.view = !!savedView && savedView !== 'undefined' ? savedView : 'mgrid';
            });

            scope.$on('key:v', toggleView);

            scope.$on('open:archived_kill', (evt, item, action) => {
                scope.selected.archived_kill = item;
                scope.selected.archived_kill_action = action;
            });

            scope.$on('open:resend', (evt, item) => {
                scope.selected.resend = item;
            });

            function setView(view) {
                scope.view = view || 'mgrid';
                preferencesUpdate['archive:view'].view = view || 'mgrid';
                preferencesService.update(preferencesUpdate, 'archive:view');
            }

            function toggleView() {
                var nextView = scope.view === LIST_VIEW ? GRID_VIEW : LIST_VIEW;

                return setView(nextView);
            }

            /**
             * Generates Identifier to be used by track by expression.
             */
            scope.uuid = function(item) {
                return search.generateTrackByIdentifier(item);
            };

            // init
            $rootScope.aggregations = 0;
            _queryItems();
        },
    };
}
<commit_msg>fix search provider not updating<commit_after>import _ from 'lodash';
import {gettext} from 'core/utils';
import {appConfig} from 'appConfig';
import {ISearchOptions} from '../services/SearchService';
import {IPackagesService} from 'types/Services/Packages';

SearchResults.$inject = [
    '$location',
    'preferencesService',
    'packages',
    'asset',
    '$timeout',
    'api',
    'search',
    'session',
    '$rootScope',
    'superdeskFlags',
    'notify',
];

const HEX_REG_EXP = /[a-f0-9]{24}/;

function isObjectId(value) {
    return value != null && value.length === 24 && HEX_REG_EXP.test(value);
}

/**
 * @ngdoc directive
 * @module superdesk.apps.search
 * @name sdSearchResults
 *
 * @requires $location
 * @requires preferencesService
 * @requires packages
 * @requires asset
 * @requires $timeout
 * @requires api
 * @requires search
 * @requires session
 * @requires $rootScope
 *
 * @description Item list with sidebar preview
 */
export function SearchResults(
    $location,
    preferencesService,
    packages: IPackagesService,
    asset,
    $timeout,
    api,
    search,
    session,
    $rootScope,
    superdeskFlags,
    notify,
) { // uff - should it use injector instead?
    var preferencesUpdate = {
        'archive:view': {
            allowed: [
                'mgrid',
                'compact',
            ],
            category: 'archive',
            view: 'mgrid',
            default: 'mgrid',
            label: 'Users archive view format',
            type: 'string',
        },
    };

    return {
        require: '^sdSearchContainer',
        templateUrl: asset.templateUrl('apps/search/views/search-results.html'),
        link: function(scope, elem, attr, controller) {
            var containerElem = elem.find('.shadow-list-holder');
            var GRID_VIEW = 'mgrid',
                LIST_VIEW = 'compact';

            var projections = search.getProjectedFields();
            var multiSelectable = attr.multiSelectable !== undefined;

            scope.previewingBroadcast = false;
            superdeskFlags.flags.previewing = false;

            // allow controller overwrite getSearch
            const getSearch = typeof scope.search.getSearch === 'function'
                ? scope.search.getSearch
                : () => $location.search();

            const queryOptions: ISearchOptions = {
                hidePreviousVersions: scope.search.hideNested === true,
            };

            var criteria = search.query(getSearch(), queryOptions).getCriteria(true),
                oldQuery = _.omit(getSearch(), '_id');

            scope.flags = controller.flags;
            scope.selected = scope.selected || {};
            scope.showHistoryTab = true;

            scope.context = 'search';
            scope.$on('item:deleted:archived', itemDelete);
            scope.$on('item:fetch', queryItems);
            scope.$on('item:update', updateItem);
            scope.$on('item:deleted', scheduleIfShouldUpdate);
            scope.$on('item:unlink', queryItems);
            scope.$on('item:spike', scheduleIfShouldUpdate);
            scope.$on('item:unspike', scheduleIfShouldUpdate);
            scope.$on('item:duplicate', queryItems);
            scope.$on('item:translate', queryItems);
            scope.$on('item:marked_desks', queryItems);

            // used by superdesk-fi
            scope.showtags = attr.showtags !== 'false';

            // Custom components for item fields
            scope.customRender = scope.search.customRender || {};

            scope.$on('ingest:update', (event, args) => {
                if (!scope.showRefresh) {
                    queryItems(event, args);
                }
            });

            scope.$on('content:update', queryItems);
            scope.$on('item:move', scheduleIfShouldUpdate);

            scope.$on('aggregations:changed', queryItems);

            scope.$on('broadcast:preview', (event, args) => {
                scope.previewingBroadcast = true;
                scope.preview(args.item);
            });

            scope.$on('broadcast:created', (event, args) => {
                scope.previewingBroadcast = true;
                queryItems();
                scope.preview(args.item);
            });

            scope.$watch('selected', (newVal, oldVal) => {
                if (!newVal && scope.previewingBroadcast) {
                    scope.previewingBroadcast = false;
                }
            });

            scope.$watch(function getSearchParams() {
                return _.omit(getSearch(), ['_id', 'item', 'action']);
            }, (newValue, oldValue) => {
                if (newValue !== oldValue) {
                    scope.refreshList();
                }
            }, true);

            // public api - called by list when needed
            scope.fetchNext = function() {
                render(null, true);
            };

            var nextUpdate;

            function updateItem(e, data) {
                var item = _.find(scope.items._items, {_id: data.item._id});

                if (item) {
                    angular.extend(item, data.item);
                }
            }

            /**
             * Schedule an update if it's not there yet
             */
            function queryItems(event?, data?) {
                if (isObjectId(scope.search.repo.search) && event != null) {
                    // external provider, don't refresh on events
                    return;
                }

                if (!nextUpdate) {
                    if (scope.search.repo.search !== 'local' && !getSearch().q && !(data && data.force)) {
                        return; // ignore updates with external content
                    }

                    scope.loading = true;
                    nextUpdate = $timeout(() => {
                        _queryItems(event, data)
                            .finally(() => {
                                scope.$applyAsync(() => {
                                    nextUpdate = null;
                                });
                            });
                    }, 1000, false);
                }
            }

            /**
             * Function for fetching total items and filling scope for the first time.
             */
            function _queryItems(event?, data?) {
                criteria = search.query(getSearch(), queryOptions).getCriteria(true);
                criteria.source.size = 50;
                var originalQuery;

                // when forced refresh or query then keep query size default as set 50 above.
                if (!(data && data.force)) {
                    // To compare current scope of items, consider fetching same number of items.
                    if (scope.items && scope.items._items.length > 50) {
                        criteria.source.size = scope.items._items.length;
                    }
                }

                if (data && (data.item || data.items || data.item_id) && scope.showRefresh && !data.force) {
                    // if we know the ids of the items then try to fetch those only
                    originalQuery = angular.extend({}, criteria.source.query);

                    let items = data.items || {};

                    if (data.item || data.item_id) {
                        items[data.item || data.item_id] = 1;
                    }

                    criteria.source.query = search.getItemQuery(data.items);
                } else {
                    criteria.aggregations = $rootScope.aggregations;
                }

                criteria.source.from = 0;
                scope.total = null;
                criteria.es_highlight = search.getElasticHighlight();
                criteria.projections = JSON.stringify(projections);

                if (getSearch().params) {
                    criteria.params = JSON.parse(getSearch().params);
                }

                return api.query(getProvider(criteria), criteria).then((items) => {
                    if (appConfig.features.autorefreshContent && data != null) {
                        data.force = true;
                    }

                    if (!scope.showRefresh && data && !data.force && data.user !== session.identity._id) {
                        const _data = {
                            newItems: items,
                            scopeItems: scope.items,
                            scrollTop: containerElem.scrollTop(),
                            isItemPreviewing: !!scope.selected.preview,
                        };

                        scope.showRefresh = search.canShowRefresh(_data);
                    }

                    if (!scope.showRefresh || data && data.force) {
                        scope.total = items._meta.total;
                        scope.$applyAsync(() => {
                            render(items, null, true);
                        });
                    } else {
                        // update scope items only with the matching fetched items
                        scope.items = search.updateItems(items, scope.items);
                    }

                    if (originalQuery) {
                        criteria.source.query = originalQuery;
                    }
                }, (error) => {
                    notify.error(gettext('Failed to run the query!'));
                    console.error(error, getProvider(criteria));
                })
                    .finally(() => {
                        scope.loading = false;
                    });
            }

            function scheduleIfShouldUpdate(event, data) {
                if (data && data.item && _.includes(['item:spike', 'item:unspike', 'item:deleted'], event.name)) {
                    // item was spiked/unspikes from the list
                    extendItem(data.item, {
                        gone: true,
                        _etag: data.item,
                    });
                    queryItems(event, data);
                } else if (data && data.from_stage) {
                    // item was moved from current stage
                    extendItem(data.item, {
                        gone: true,
                        _etag: data.from_stage, // this must change to make it re-render
                    });
                    queryItems(event, data);
                }
            }

            function extendItem(itemId, updates) {
                scope.$apply(() => {
                    scope.items._items = scope.items._items.map((item) => {
                        if (item._id === itemId) {
                            return angular.extend(item, updates);
                        }

                        return item;
                    });

                    scope.items = angular.extend({}, scope.items); // trigger a watch
                });
            }

            scope.$on('refresh:list', (event, group) => {
                scope.refreshList();
            });

            scope.refreshList = function() {
                scope.showRefresh = false;
                queryItems(null, {force: true});
                if (containerElem[0].scrollTop > 0) {
                    containerElem[0].scrollTop = 0;
                }
            };

            /*
             * Function to get the search endpoint name based on the criteria
             *
             * @param {Object} _criteria
             * @returns {string}
             */
            function getProvider(_criteria) {
                var provider = 'search';

                if (_criteria.repo && _criteria.repo.indexOf(',') === -1) {
                    provider = _criteria.repo;
                }

                if (scope.search.repo.search && scope.search.repo.search !== 'local') {
                    provider = scope.search.repo.search;
                }

                if (isObjectId(provider)) {
                    _criteria.repo = provider;
                    provider = 'search_providers_proxy';
                }

                if (provider === 'local') {
                    provider = 'search';
                }

                return provider;
            }

            /*
             * Function for fetching the elements from the database
             *
             * @param {items}
             */
            function render(items, next, force?) {
                scope.loading = true;
                if (items) {
                    setScopeItems(items, force);
                } else if (next) {
                    scope.loading = true;
                    criteria.source.from = (criteria.source.from || 0) + criteria.source.size;
                    criteria.source.size = 50;
                    criteria.projections = JSON.stringify(projections);

                    api
                        .query(getProvider(criteria), criteria)
                        .then(setScopeItems)
                        .finally(() => {
                            scope.loading = false;
                        });
                } else {
                    var query = _.omit(getSearch(), '_id');

                    if (!_.isEqual(_.omit(query, 'page'), _.omit(oldQuery, 'page'))) {
                        $location.search('page', null);
                    }

                    criteria = search.query(getSearch(), queryOptions).getCriteria(true);
                    criteria.source.from = 0;
                    criteria.source.size = 50;
                    criteria.aggregations = $rootScope.aggregations;
                    criteria.es_highlight = search.getElasticHighlight();
                    scope.loading = true;
                    criteria.projections = JSON.stringify(projections);

                    api
                        .query(getProvider(criteria), criteria)
                        .then(setScopeItems)
                        .finally(() => {
                            scope.loading = false;
                        });
                    oldQuery = query;
                }

                function setScopeItems(_items, _force) {
                    scope.items = search.mergeItems(_items, scope.items, next, _force);
                    scope.total_records = _items._meta.total;
                    scope.loading = false;
                }
            }

            /*
             * Function for updating list
             * after item has been deleted
             */
            function itemDelete(e, data) {
                if (session.identity._id === data.user) {
                    queryItems();
                }
            }

            scope.preview = function preview(item) {
                if (multiSelectable) {
                    if (_.findIndex(scope.selectedList, {_id: item._id}) === -1) {
                        scope.selectedList.push(item);
                    } else {
                        _.remove(scope.selectedList, {_id: item._id});
                    }
                }

                if (item) {
                    if (item._type === 'externalsource') {
                        processPreview(item);
                        return;
                    }

                    scope.loading = true;
                    let previewCriteria = search.getSingleItemCriteria(item);

                    api.query(getProvider(previewCriteria), previewCriteria).then((completeItems) => {
                        let completeItem = search.mergeHighlightFields(completeItems._items[0]);

                        processPreview(completeItem);
                    })
                        .finally(() => {
                            scope.loading = false;
                        });
                } else {
                    delete scope.selected.preview;
                    superdeskFlags.flags.previewing = false;
                    sendRowViewEvents();
                }
            };

            /**
             * @ngdoc method
             * @name sdSearchResults#sendRowViewEvents
             * @private
             * @param {Object} item
             * @description If singLine:view preference is set, an item is being previewed, config has narrowView list
             * then, sends rowview event
             */
            function sendRowViewEvents(item?) {
                let sendEvent = scope.singleLine
                    && superdeskFlags.flags.authoring
                    && appConfig.list != null
                    && appConfig.list.narrowView;

                let evnt = item ? 'rowview:narrow' : 'rowview:default';

                if (sendEvent) {
                    $rootScope.$broadcast(evnt);
                }
            }

            /**
             * @ngdoc method
             * @name sdSearchResults#processPreview
             * @private
             * @param {Object} item
             * @description Sets the preview item
             */
            function processPreview(item) {
                scope.selected.preview = item;

                if (!_.isNil(scope.selected.preview)) {
                    scope.showHistoryTab = scope.selected.preview.state !== 'ingested' &&
                    !_.includes(['archived', 'externalsource'], scope.selected.preview._type);

                    superdeskFlags.flags.previewing = true;
                    sendRowViewEvents(item);
                }

                $location.search('_id', item ? item._id : null);
            }

            scope.openLightbox = function openLightbox() {
                scope.selected.view = scope.selected.preview;
            };

            scope.closeLightbox = function closeLightbox() {
                scope.selected.view = null;
            };

            scope.openSingleItem = function(packageItem) {
                packages.fetchItem(packageItem).then((item) => {
                    scope.selected.view = item;
                });
            };

            scope.setview = setView;

            var savedView;

            preferencesService.get('archive:view').then((result) => {
                savedView = result.view;
                scope.view = !!savedView && savedView !== 'undefined' ? savedView : 'mgrid';
            });

            scope.$on('key:v', toggleView);

            scope.$on('open:archived_kill', (evt, item, action) => {
                scope.selected.archived_kill = item;
                scope.selected.archived_kill_action = action;
            });

            scope.$on('open:resend', (evt, item) => {
                scope.selected.resend = item;
            });

            function setView(view) {
                scope.view = view || 'mgrid';
                preferencesUpdate['archive:view'].view = view || 'mgrid';
                preferencesService.update(preferencesUpdate, 'archive:view');
            }

            function toggleView() {
                var nextView = scope.view === LIST_VIEW ? GRID_VIEW : LIST_VIEW;

                return setView(nextView);
            }

            /**
             * Generates Identifier to be used by track by expression.
             */
            scope.uuid = function(item) {
                return search.generateTrackByIdentifier(item);
            };

            // init
            $rootScope.aggregations = 0;
            _queryItems();
        },
    };
}

{'fraction_non_alphanumeric': 0.10935758895021898, 'fraction_numerical': 0.0016585037186763068, 'mean_word_length': 1.2208793738489871, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 55, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4256300', 'n_tokens_mistral': 9483, 'n_tokens_neox': 8766, 'n_words': 1863}