Files
2024-02-15 17:01:50 +00:00

135 lines
2.9 KiB
TypeScript

import type {StoreDefinition} from 'reflux';
import {createStore} from 'reflux';
import type {Plugin} from 'sentry/types';
interface InternalDefinition {
plugins: Map<string, Plugin> | null;
state: {
error: Error | null;
loading: boolean;
pageLinks: string | null;
plugins: Plugin[];
};
updating: Map<string, Plugin>;
}
interface PluginStoreDefinition extends StoreDefinition, InternalDefinition {
getState: () => InternalDefinition['state'];
onFetchAll: (options?: {resetLoading?: boolean}) => void;
onFetchAllError: (err) => void;
onFetchAllSuccess: (data: Plugin[], links: {pageLinks?: string}) => void;
onUpdate: (id: string, updateObj: Partial<Plugin>) => void;
onUpdateError: (id: string, err: Error) => void;
onUpdateSuccess: (id: string) => void;
reset: () => void;
}
const defaultState = {
loading: true,
plugins: [],
error: null,
pageLinks: null,
};
const storeConfig: PluginStoreDefinition = {
plugins: null,
state: {...defaultState},
updating: new Map(),
reset() {
// reset our state
this.plugins = null;
this.state = {...defaultState};
this.updating = new Map();
return this.state;
},
getInitialState() {
return this.getState();
},
getState() {
const {plugins: _plugins, ...state} = this.state;
return {
...state,
plugins: this.plugins ? Array.from(this.plugins.values()) : [],
};
},
init() {
// XXX: Do not use `this.listenTo` in this store. We avoid usage of reflux
// listeners due to their leaky nature in tests.
this.reset();
},
triggerState() {
this.trigger(this.getState());
},
onFetchAll({resetLoading} = {}) {
if (resetLoading) {
this.state.loading = true;
this.state.error = null;
this.plugins = null;
}
this.triggerState();
},
onFetchAllSuccess(data, {pageLinks}) {
this.plugins = new Map(data.map(plugin => [plugin.id, plugin]));
this.state.pageLinks = pageLinks || null;
this.state.loading = false;
this.triggerState();
},
onFetchAllError(err) {
this.plugins = null;
this.state.loading = false;
this.state.error = err;
this.triggerState();
},
onUpdate(id: string, updateObj: Partial<Plugin>) {
if (!this.plugins) {
return;
}
const plugin = this.plugins.get(id);
if (!plugin) {
return;
}
const newPlugin = {
...plugin,
...updateObj,
};
this.plugins.set(id, newPlugin);
this.updating.set(id, plugin);
this.triggerState();
},
onUpdateSuccess(id: string) {
this.updating.delete(id);
},
onUpdateError(id: string, err) {
const origPlugin = this.updating.get(id);
if (!origPlugin || !this.plugins) {
return;
}
this.plugins.set(id, origPlugin);
this.updating.delete(id);
this.state.error = err;
this.triggerState();
},
};
const PluginStore = createStore(storeConfig);
export default PluginStore;