@genialis/resolwe
Version:
Resolwe frontend libraries
338 lines (337 loc) • 11.9 kB
TypeScript
import * as Rx from 'rx';
import * as angular from 'angular';
/**
* A shared store action contains a `type` property and any number of other
* custom properties. Action types starting with `@@internal/` are reserved
* for internal use.
*/
export interface Action {
type: string;
[propertyName: string]: any;
}
declare type MethodReturns<Actions> = Actions extends {
[key in keyof Actions]: (() => infer Return) | infer Else;
} ? Return : never;
declare type FilterActions<Return> = Return extends {
type: infer R;
} ? Return : never;
export declare type GetActions<Actions> = FilterActions<MethodReturns<Actions>> | {
type: '...';
};
/**
* A thunk is a function, which mediates the dispatch of an action. It may
* be dispatched in the same way as an action.
*/
export interface Thunk {
(dispatcher: Dispatcher, getState: () => any): any;
}
export interface SharedStoreQuery<T, U> {
(state: Rx.Observable<T>): Rx.Observable<U>;
}
export declare class Actions {
static SET: "@@internal/SET";
set(value: any): {
type: "@@internal/SET";
value: any;
};
}
/**
* A shared store represents state that is shared between multiple components in
* a predictable way. Components update the store by dispatching actions to
* it using the `dispatch` method.
*
* Each shared store also provides a way for the components to subscribe to any
* changes in the store's state.
*
* Consider defining actions for use in a shared store separately from the store,
* in the `actions` subdirectory. See [[SharedStoreManager]] for details.
*
* Don't forget to call constructor with actions as an argument when extending
* this class.
*/
export declare abstract class SharedStore<T, U> {
private _subject;
private _dispatcher;
private _queries;
private _actions;
private _storeId;
constructor(actions?: U);
/**
* Returns a unique identifier for this shared store.
*/
readonly storeId: string;
/**
* Returns store actions.
*/
readonly actions: U;
/**
* Internal dispatcher implementation.
*
* NOTE: This method is public because there is no way to define private
* but accessible to other classes within this module in TypeScript.
*/
_dispatch(action: Action): void;
/**
* Dispatches an action to this shared store.
*
* @param action Action to dispatch
*/
dispatch(action: GetActions<U> | GetActions<Actions> | Thunk): any;
/**
* Performs internal reduce actions implemented for each shared store.
*
* @param state Existing shared store state
* @param action Action to perform
* @return New shared store state
*/
private _reduceInternal;
/**
* Performs the given action on the underlying state.
*
* Subclasses may override this method to implement arbitrary complex
* actions on the data store. This method MUST NOT mutate the existing
* state. Instead, it MUST return an immutable copy.
*
* @param value Existing shared store state
* @param action Operation to perform
* @return New shared store state
*/
protected abstract reduce(state: T, action: GetActions<U>): T;
/**
* Provides the initial state for this shared store. This state is
* used when the store is initialized.
*/
protected abstract initialState(): T;
/**
* This method gets called when the data store's state is loaded from
* an external source (when the SET action is dispatched to the store).
*
* It is called before the new state has been set. The default implementation
* does nothing.
*
* @param state Old state
* @param nextState New state
* @return Possibly modified state that should be used instead
*/
protected onStateLoad(state: T, nextState: T): T;
/**
* A helper method for defining shared store queries. If the query is already
* defined, the existing observable is returned.
*
* @param name Query name
* @param query Query function
* @return Resulting query observable
*/
protected defineQuery<V>(name: string, query: SharedStoreQuery<T, V>): Rx.Observable<V>;
/**
* Returns the current value stored in the store.
*
* You MUST ensure that the resulting object is NOT mutated in any way. Any
* mutation may cause undefined behavior.
*/
value(): T;
/**
* Returns an observable of the store's value.
*
* You MUST ensure that the observed value is NOT mutated in any way. Any
* mutation may cause undefined behavior.
*/
observable(): Rx.Observable<T>;
/**
* Returns a value that should be used when saving store state.
*
* By default, this will return the same as [[value]].
*/
saveValue(): T;
}
/**
* [[SimpleSharedStore]] is a helper class intended to be used as a type in conjunction with
* [[SharedStoreProvider]]'s `create` method where only SET action is used.
*
* In this case no subclassing of store and actions is needed because only SET action is used.
* This is convenient for use cases where you only need to set a value that you can subscribe
* to from other components.
*/
export declare abstract class SimpleSharedStore<T> extends SharedStore<T, typeof undefined> {
}
/**
* Used to dispatch actions to shared stores.
*/
export declare class Dispatcher extends Rx.Subject<Action> {
private _getState;
/**
* Configures a dispatcher function for this dispatcher.
*
* @param dispatcher The dispatcher function
*/
setDispatcher(dispatcher: (action: Action) => void, getState?: () => any): void;
/**
* Dispatches an action via this dispatcher.
*/
dispatch(action: Action | Thunk): any;
}
export interface SharedStoreFactory<T, U> {
new (...args: any[]): SharedStore<T, U>;
}
export interface ActionFactory {
new (...args: any[]): any;
}
/**
* Shared store provider, enabling registration of shared stores. All stores
* must be registered in the application configuration phase.
*/
export declare class SharedStoreProvider {
private _stores;
private _provide;
constructor($provide: angular.auto.IProvideService);
/**
* A list of registered stores.
*/
readonly stores: string[];
/**
* Creates a new shared store.
*
* When choosing an identifier for the store, you should write it using
* kebab-case and not include the string 'store' either as a prefix or
* a suffix.
*
* This method may only be called in the application's configuration
* phase.
*
* @param storeId Identifier of the shared store (must be globally unique)
* @param initialState Optional initial state of the shared store
*/
create<T>(storeId: string, initialState?: T): void;
/**
* Registers a new shared store. A store with the same name must not already
* be registered.
*
* This method may only be called in the application's configuration
* phase.
*
* @param storeId Identifier of the shared store (must be globally unique)
* @param Shared store class
*/
register<T>(storeId: string, storeType: SharedStoreFactory<T, any>): void;
/**
* Registers a new actions class.
*
* This method may only be called in the application's configuration
* phase.
*
* @param actionsId Identifier of the actions class (must be globally unique)
* @param Actions class
*/
registerActions(actionsId: string, actionsType: ActionFactory): void;
$get($injector: angular.auto.IInjectorService, dispatcher: Dispatcher): SharedStoreManager;
}
/**
* Manager of all shared stores (see [[SharedStore]]) in an application. Each store
* requires a globally unique identifier, which is also used during state serialization.
*
* In order to use shared stores, you must first create them. The best way to do
* this is inside your module's `config` function as follows:
* ```
* module.config((sharedStoreManagerProvider: SharedStoreProvider) => {
* // Create the selected ROSE2 data items shared store.
* sharedStoreManagerProvider.create('rose2-selected-data-item');
* });
* ```
*
* The store may then be used as input to shared state defined on stateful
* components (see [[StatefulComponentBase]]) and can also be injected using
* a specific token. If a store is named `my-nice-items`, it will be injectable
* by using the token `myNiceItemsStore`.
*
* If you wish to define shared stores which support additional actions, you
* should subclass [[SharedStore]] and register your store by using [[register]]
* as follows:
* ```
* class ComplexActions {
* static ADD_ITEM = 'complex/add_item';
* public addItem(value: types.SampleData) {
* return { type: ComplexActions.ADD_ITEM, item: value };
* }
* }
*
* class ComplexStore extends SharedStore<types.SampleData[], ComplexActions> {
* // @ngInject
* constructor(complexActions: ComplexActions) {
* super(complexActions);
* }
*
* protected initialState(): types.SampleData[] {
* return [];
* }
*
* protected reduce(state: types.SampleData[], action: any): void {
* switch (action.type) {
* case ADD_ITEM: {
* return _.union(state, action.item);
* }
* // ...
* }
* }
* }
*
* module.config((sharedStoreManagerProvider: SharedStoreProvider) => {
* sharedStoreManagerProvider.registerActions('complex', ComplexActions);
* sharedStoreManagerProvider.register('complex', ComplexStore);
* });
* ```
*
* When creating a new shared store, a good design practice is to separate
* actions into the `actions` directory and implement actions as methods on
* the actions class named after your store (eg. for store `FooStore` put
* actions into `FooActions`).
*
* Stores themselves should only implement the state management functionality
* and most business logic should be contained in the actions class. For
* example, if actions require some asynchronous operations to be performed
* on a remote backend all this functionality should be put into the actions
* class and not into the store.
*
* All actions classes should be registered via the [[SharedStoreProvider]]
* and support Angular dependency injection. Actions classes are injectable
* under the token `idActions` where the `id` part is the value defined by
* `actionsId`, formatted in camelCase. The constructor of an actions
* class may also inject other dependencies.
*
* For convenience, you may inject your actions class in your shared store
* class under the public attribute `actions`. This way one may get the
* actions class simply by accessing `store.actions` when given a shared
* store instance.
*/
export declare class SharedStoreManager {
private _provider;
private _dispatcher;
private _injector;
constructor($injector: angular.auto.IInjectorService, dispatcher: Dispatcher, sharedStoreManagerProvider: SharedStoreProvider);
/**
* Returns a previously registered store. It is an error to request a store
* which doesn't exist.
*
* @param storeId Identifier of the shared store
* @return Shared store instance
*/
getStore<T>(storeId: string): SharedStore<T, any>;
/**
* Dispatches an action to all shared stores.
*
* @param action Action to dispatch
*/
dispatch(action: Action | Thunk): any;
/**
* Internal global dispatch implementation.
*/
private _dispatch;
/**
* Serializes the values of all shared stores.
*/
saveState(): any;
/**
* Loads serialized values of all shared stores. Existing values are overwritten.
*/
loadState(state: any): void;
}
export {};