npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@agile-central-technical-services/utils-ancestor-pi-app-filter

v2.3.2

Published

A portfolio item ancestor filter plugin for Technical Services apps

Readme

@agile-central-technical-services/utils-ancestor-pi-app-filter

An app plugin that adds an ancestor portfolio item filter and project scoping to the app, or, if placed on a page containing a version of this plugin configured as a publisher, will listen for an ancestor filter from the publisher app.

The plugin will:

  • add an app setting that controls if ancestor filtering is enabled
  • If the setting is enabled
    • search the app for a container with the id of Utils.AncestorPiAppFilter.RENDER_AREA_ID (or a specified id) and add a portfolio type picker, a portfolio item picker and a project scoping control.
    • listen for events from any apps using this plugin as a publisher
    • if a publisher is detected, the local portfolio type and picker will be hidden and filter values from the publisher used instead.
  • Dispatch a ready event when the control is ready for use.
  • Dispatch a select event when the selected portfolio item is changed (or a publisher has changed selections)
  • Make the current portfolio item available as a Rally.data.wsapi.Filter relative to a given type. (e.g. An Epic ancestor for a HierarchicalRequirement becomes PortfolioItem.Parent = /portfolioitem/epic/1234)
  • Make the current project scope setting available as a function call.
  • If the given type doesn't have the selected portfolio item type as an ancestor, a null filter is returned (ObjectID = 0).
  • To ensure the filter is fully initialized, the appliation should wait for the ready event before getting the current ancestor filter.

Screenshots

The added filter controls.

Screenshot

The added filter settings.

Screenshot

When configured as a filter publisher.

Screenshot

When enabled and on a page containing a publisher app.

Screenshot

Examples

Publisher examples:

Listener examples:

Installation

  1. Install using npm (or yarn) npm install '@agile-central-technical-services/utils-ancestor-pi-app-filter' -D
  2. Add the file to the javascript section of config.json
     "javascript": [
        "node_modules/@agile-central-technical-services/utils-ancestor-pi-app-filter/index.js",
        ...

Example publisher usage

Ext.define("PiAncestorFilterBroadcaster", {
    extend: 'Rally.app.App',
    // Add an area where the filter controls will render.
    items: [{
        id: Utils.AncestorPiAppFilter.RENDER_AREA_ID,
        xtype: 'container',
        flex: 1,
        layout: {
            type: 'hbox',
            align: 'middle',
            defaultMargins: '0 10 10 0',
        }
    }],

    launch: function() {
        this.ancestorFilterPlugin = Ext.create('Utils.AncestorPiAppFilter', {
            ptype: 'UtilsAncestorPiAppFilter',
            pluginId: 'ancestorFilterPlugin',
            publisher: true,    // Publish events to other apps using this plugin
            settingsConfig: {
                labelWidth: 150,
                margin: 10
            },
            listeners: {
                scope: this,
                ready: function(plugin) {
                    // Plugin ready, begin listening for selection changes
                    plugin.addListener({
                        scope: this,
                        select: function() {
                            // Notify any listeners of the new filter values
                            this.ancestorFilterPlugin.notifySubscribers();
                        }
                    });
                    // Notify any listeners of the current selections
                    this.ancestorFilterPlugin.notifySubscribers();
                },
            }
        });
        // Must add the filter at runtime (instead of in config) to make sure we can
        // catch its ready event.
        this.addPlugin(this.ancestorFilterPlugin);
    }
});

Example stand-alone or listener usage

Ext.define("custom-grid-with-deep-export", {
    extend: 'Rally.app.App',
    items: [{
        id: Utils.AncestorPiAppFilter.RENDER_AREA_ID,
        xtype: 'container',
        flex: 1,
        layout: {
            type: 'hbox',
            align: 'middle',
            defaultMargins: '0 10 10 0',
        }
    }]
    
    launch: function() {
       ...
        this.ancestorFilterPlugin = Ext.create('Utils.AncestorPiAppFilter', {
            ptype: 'UtilsAncestorPiAppFilter',
            pluginId: 'ancestorFilterPlugin',
            // Set to false to prevent the '-- None --' selection option if your app can't support
            // querying by a null ancestor (e.g. Lookback _ItemHierarchy)
            allowNoEntry: true,
            settingsConfig: {
                labelWidth: 150,
                margin: 10
            },
            listeners: {
                scope: this,
                ready: function(plugin) {
                    plugin.addListener({
                        scope: this,
                        select: function() {
                            this.loadData();
                        }
                    });
                    this.loadData();
                }
            }
        });
        this.addPlugin(this.ancestorFilterPlugin);
    },
    
    loadData: function() {
        ...
        // Get current ancestor portfolio item filter
        var ancestorFilter = this.ancestorFilterPlugin.getFilterForType(artifactType);
        if (ancestorFilter) {
            filters = filters.and(ancestorFilter);
        }
        
        // Get current project scoping
        var dataContext = this.getContext.getDataContext();
        if ( this.ancestorFilterPlugin.getIgnoreProjectScope() ) {
            dataContext.project = null
        }
        ...
    }

Developer Notes

To Update

  1. npm version patch - This will update the package.json to a new version and create a git tag (e.g. v1.0.1). It will also run the postversion script to push the changes and tag to GitHub.
  2. npm publish --access public - This will publish the new version to npmjs.org
  3. Create the new release in `utils_file-utils/releases'

Test Plan

Settings

  • PASS - Retain values after settings close and reopen
  • PASS - Retain values after app reload
  • PASS - Label width customizable by config.settingsConfig
  • PASS - Show ancestor filter shows/hides ancestor filter
  • PASS - Show ignore scope shows/hides ignore scope
  • NOT IMPLEMENTED - Ignore scope by default provides default value for ignore scope control
  • PASS - Ignore scope by default value used ONLY if ignore scope control not shown

Controls

Publisher / Subscriber indicator

  • PASS - has mouseover explaining icon

PI Type Picker

  • PASS - pi types
  • PASS - changing types resets pi picker
  • PASS - lowest level selected by default
  • PASS - type remembered after reload
  • PASS - changing type notifies subscribers
  • PASS - unaffected by changes to controls in expanded listener

PI Picker

  • PASS - has clear option
  • PASS - has none option
  • PASS - has pis that match currently selected pi type
  • PASS - has pis across entire workspace
  • PASS - pi remembered after reload
  • PASS - changing pi notifies subscribers
  • PASS - unaffected by changes to controls in expanded listener

Scope Control

  • PASS - Current Project is default
  • PASS - choice remembered after reload
  • PASS - changing choice notifies subscribers
  • PASS - unaffected by changes to controls in expanded listener

As Publisher

  • PASS - Shows publisher icon

As Subscriber

  • PASS - Shows subscriber icon
  • PASS - Hides all controls
  • PASS - Hides all controls even when own app settings show them
  • NOT IMPLEMENTED - Uses publisher settings when expanded
  • PASS - Uses app settings for controls when expanded
  • PASS - Uses publisher filters when not expanded
  • PASS - Automatically becomes subscriber when publisher added to page