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 🙏

© 2024 – Pkg Stats / Ryan Hefner

@xailabs/altx

v1.4.5

Published

Flux flavor based on alt.js

Downloads

44

Readme

altx

Flux framework developed for the NISV client, built on top of (alt)[http://alt.js.org/]. It extends alt by adding a couple of concepts.

docs

Calls

One of these concepts are calls.
A call provides a way to define an asynchronous procedure, like fetching data from the server or sending data to it.

A call automatically creates alt actions and hanlders and groups them together in a single place.


    import {callFactory} from '@xailabs/altx';
    import Immutable from 'immutable';
    import Api from 'api';

    export default callFactory('loadUsers', {namespace: 'users'}).create({
        dataSource: {
            remote: () => Api.get(Api.endpoints.USERS)
        },
        reducers: {
            loading(state) {
                return state.setIn(['pending', 'loadUsers'], true);
            },
            error(state) {
                return state.setIn(['pending', 'loadUsers'], false);
            },
            success(state, payload) {
                return state
                    .setIn(['pending', 'loadUsers'], false)
                    .set('users', Immutable.fromJS(payload.items));
            }
        }
    });

The call creates three actions:

  • The users:loadUsers.loading action is dispatched when the request is made
  • The users:loadUsers.success action is dispatched when a response with status code below 400 is received
  • The users:loadUsers.error action is dispatched when a response with status code above 400 was reiceved

The actions are namespaced so they don't collide globally, but "inside the call" we simply speak of loading or success in the short form.
The namespace should, by convention, be the name of the responsible store, but it's really just used by the developer, for debugging or understanding logs.

If you need to access the generated actions manually, which is not very common, you'd import the call and access them using its actions property:


    import loadUsers from 'calls/loadUsers';

    // manually dispatching the action:
    loadUsers.actions.success(payload);

    // the generated name 'users:loadUsers.success' is available per UPPERCASE notation
    actionListeners.addActionListener(loadUsers.actions.SUCCESS, (payload) => {...});

Additionally, the call creates three handler methods on the store and binds them to the actions. Each handler uses the reducer defined in the call and sets its result as the next state. Something like:


    @bind(loadUsers.actions.loading)
    _loadUsers_loading(payload) {
        const nextState = loadUsers.reducers.loading(this.state, payload);
        this.setState(nextState);
    }
    @bind(loadUsers.actions.success)
    _loadUsers_success(payload) {
        const nextState = loadUsers.reducers.success(this.state, payload);
        this.setState(nextState);
    }
    @bind(loadUsers.actions.error)
    _loadUsers_error(payload) {
        const nextState = loadUsers.reducers.error(this.state, payload);
        this.setState(nextState);
    }

Each of those methods automatically

Migrating a "call" to altx

This is a changelog of a migration. The functionality loads favourite folders from the server and was previously spread across three files: Action names were defined in FavActions.js, data fetching was defined in FavSource.js and data handling was defined in the store itself, FavStore.js.
There was a manual handling of pending state, and components were listening for a flag isLoadingFolders directly on the store state. This was changed to the call convention of using setIn(['pending', 'callName'], true), however the components only had to change their binding from isLoadingFolders to pending.loadFolders as isLoadingFolders. Due to the flexible decorator syntax, no further changes were needed inside components.

Note that most of the change is just removing stuff. The entire functionality is replaced by the couple of lines at the end of the diff.


    diff --git a/src/app/components/FavDialogs/FavFolderSelect.jsx b/src/app/components/FavDialogs/FavFolderSelect.jsx
    index 151e788..f2a82de 100644
    --- a/src/app/components/FavDialogs/FavFolderSelect.jsx
    +++ b/src/app/components/FavDialogs/FavFolderSelect.jsx
    @@ -15,7 +15,7 @@ import {injectIntl, intlShape, defineMessages, FormattedMessage} from 'react-int
     
     const StoreConnection = connect([ {
         store: FavStore,
    -    props: ['folders', 'isLoadingFolders', 'recentlyUsedFolder']
    +    props: ['folders', 'pending.loadFolders as isLoadingFolders', 'recentlyUsedFolder']
     }]);
     
     const messages = defineMessages({
    diff --git a/src/app/routes/user/routes/favourites/components/folders/FavFoldersPage.jsx b/src/app/routes/user/routes/favourites/components/folders/FavFoldersPage.jsx
    index cc68e72..8d71f44 100644
    --- a/src/app/routes/user/routes/favourites/components/folders/FavFoldersPage.jsx
    +++ b/src/app/routes/user/routes/favourites/components/folders/FavFoldersPage.jsx
    @@ -26,7 +26,7 @@ const messages = defineMessages({
     const Stateful = connect([
         {
             store: FavStore,
    -        props: ['folders', 'isLoadingFolders', 'favs']
    +        props: ['folders', 'pending.loadFolders as isLoadingFolders', 'favs']
         }
     ]);
     
    diff --git a/src/stores/favourites/FavActions.js b/src/stores/favourites/FavActions.js
    index b80521e..e46956b 100644
    --- a/src/stores/favourites/FavActions.js
    +++ b/src/stores/favourites/FavActions.js
    @@ -5,10 +5,6 @@ export default alt.generateActions(
         'handleFolderError',
         'handleItemError',
     
    -    'loadingFolders',
    -    'handleFolders',
    -    'handleFoldersError',
    -
         'loadingFavs',
         'handleFavs',
     
    diff --git a/src/stores/favourites/FavSource.js b/src/stores/favourites/FavSource.js
    index e5ac3b9..0722ac5 100644
    --- a/src/stores/favourites/FavSource.js
    +++ b/src/stores/favourites/FavSource.js
    @@ -2,15 +2,6 @@ import FavActions from './FavActions';
     import Api from 'api';
     
     export default {
    -    // Fetch all available folders
    -    loadFolders() {
    -        return {
    -            loading: FavActions.loadingFolders,
    -            success: FavActions.handleFolders,
    -            error: FavActions.handleFolderError,
    -            remote: (state, options) => Api.get(`${Api.endpoints.FAVOURITES_FOLDERS}?fields=+createdAt,+modifiedAt&sort=name`, null, options)
    -        };
    -    },
         // Fetch all favs in a folder
         loadFavs() {
             return {
    diff --git a/src/stores/favourites/FavStore.js b/src/stores/favourites/FavStore.js
    index 65ff114..b8c62ec 100644
    --- a/src/stores/favourites/FavStore.js
    +++ b/src/stores/favourites/FavStore.js
    @@ -16,15 +16,13 @@ class FavStore extends ImmutableStore {
     
         constructor() {
             super({
    -            isLoadingFolders: false,
                 folders: [],
                 favs: [],
                 isLoadingFavs: false,
                 recentlyUsedFolder: null,
                 folderError: null,
                 itemError: null,
                 pending: {}
             });
             this.exportPublicMethods({
    @@ -40,21 +38,6 @@ class FavStore extends ImmutableStore {
     
         //====================================================================
         //
    -    // LOAD FOLDERS
    -    //
    -    //====================================================================
    -
    -    @bind(FavActions.loadingFolders)
    -    loadingFolders() {
    -        this.change({isLoadingFolders: true});
    -    }
    -    @bind(FavActions.handleFolders)
    -    handleFolders(payload) {
    -        this.change({isLoadingFolders: false, folders: payload.items});
    -    }
    -
    -    //====================================================================
    -    //
         // LOAD FAVS
         //
         //====================================================================
    @@ -118,21 +101,9 @@ class FavStore extends ImmutableStore {
             this.change({favs: favs.delete(deletedIndex)});
         }
     
    -    //====================================================================
    -    //
    -    // ERRORS
    -    //
    -    //====================================================================
    -
    -
    -    @bind(FavActions.handleFolderError)
    -    handleFolderError(folderError) {
    -        this.change({folderError, isLoadingFolders: false, isLoadingFavs: false});
    -        console.error('error getting fav folder: ', folderError);
    -    }
         @bind(FavActions.handleItemError)
         handleItemError(itemError) {
    -        this.change({itemError, isLoadingFavs: false, isLoadingFolders: false});
    +        this.change({itemError, isLoadingFavs: false});
             console.error('error getting fav item: ', itemError);
         }
     }
    diff --git a/src/stores/favourites/calls/index.js b/src/stores/favourites/calls/index.js
    index 66f8a2c..3673c8e 100644
    --- a/src/stores/favourites/calls/index.js
    +++ b/src/stores/favourites/calls/index.js
    @@ -1,6 +1,7 @@
     import {getSources} from '@xailabs/altx';
     const calls = [
         require('./loadActions').default,
    +    require('./loadFolders').default,
     ];
     export default calls;
     
    diff --git a/src/stores/favourites/calls/loadFolders.js b/src/stores/favourites/calls/loadFolders.js
    new file mode 100644
    index 0000000..8e61168
    --- /dev/null
    +++ b/src/stores/favourites/calls/loadFolders.js
    @@ -0,0 +1,22 @@
    +import {callFactory} from '@xailabs/altx';
    +import Api from 'api';
    +import Immutable from 'immutable';
    +/**
    + * loads all fav folders of the current user
    + */
    +export default callFactory('loadFolders', {namespace: 'favs'}).create({
    +    dataSource: {
    +        remote: (state, options) => Api.get(`${Api.endpoints.FAVOURITES_FOLDERS}?fields=+createdAt,+modifiedAt&sort=name`, null, options)
    +    },
    +    reducers: {
    +        loading: (state) => state.setIn(['pending', 'loadFolders'], true),
    +        error: (state) => state.setIn(['pending', 'loadFolders'], false),
    +
    +        success(state, payload) {
    +            return state
    +                .setIn(['pending', 'loadFolders'], false)
    +                .set('folders', Immutable.fromJS(payload.items));
    +        }
    +    }
    +});
    +