New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

@openshift/dynamic-plugin-sdk-utils

Package Overview
Dependencies
Maintainers
5
Versions
32
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@openshift/dynamic-plugin-sdk-utils - npm Package Compare versions

Comparing version 1.0.0-alpha3 to 1.0.0-alpha4

57

dist/index.d.ts

@@ -0,1 +1,5 @@

import { PluginStore } from '@openshift/dynamic-plugin-sdk';
import * as React from 'react';
import { Store, AnyAction } from 'redux';
import { ActionType } from 'typesafe-actions';
import { K8sVerb } from '@openshift/dynamic-plugin-sdk/src/types/core';

@@ -174,12 +178,2 @@

declare const commonFetch: (url: string, requestInit?: RequestInit | undefined, timeout?: number | undefined, isK8sAPIRequest?: boolean | undefined) => Promise<Response>;
declare const commonFetchText: (url: string, requestInit?: RequestInit | undefined, timeout?: number | undefined, isK8sAPIRequest?: boolean | undefined) => Promise<string>;
declare const commonFetchJSON: {
<TResult>(url: string, requestInit?: RequestInit | undefined, timeout?: number | undefined, isK8sAPIRequest?: boolean | undefined): Promise<TResult>;
put<TResult_1>(url: string, data: unknown, requestInit?: RequestInit | undefined, timeout?: number | undefined, isK8sAPIRequest?: boolean | undefined): Promise<TResult_1>;
post<TResult_2>(url: string, data: unknown, requestInit?: RequestInit | undefined, timeout?: number | undefined, isK8sAPIRequest?: boolean | undefined): Promise<TResult_2>;
patch<TResult_3>(url: string, data: unknown, requestInit?: RequestInit | undefined, timeout?: number | undefined, isK8sAPIRequest?: boolean | undefined): Promise<TResult_3>;
delete<TResult_4>(url: string, data?: unknown, requestInit?: RequestInit | undefined, timeout?: number | undefined, isK8sAPIRequest?: boolean | undefined): Promise<TResult_4>;
};
declare type K8sResourceIdentifier = {

@@ -299,2 +293,43 @@ apiGroup?: string;

declare type InitAPIDiscovery = (store: Store<unknown, ActionType<AnyAction>>) => void;
declare type AppInitSDKProps = {
/** Only child is your Application */
children: React.ReactElement;
configurations: {
apiDiscovery?: InitAPIDiscovery;
appFetch: UtilsConfig['appFetch'];
pluginStore: PluginStore;
wsAppSettings: UtilsConfig['wsAppSettings'];
};
};
/**
* Initializes the host application to work with Kubernetes and related SDK utilities.
* Add this at app-level to make use of app's redux store and pass configurations prop needed to initialize the app, preferred to have it under Provider.
* It checks for store instance if present or not.
* If the store is there then the reference is persisted to be used in SDK else it creates a new store and passes it to the children with the provider
* @component AppInitSDK
* @example
* ```tsx
* return (
* <Provider store={store}>
* <AppInitSDK configurations={{ appFetch, pluginStore, wsAppSettings }}>
* <App />
* </AppInitSDK>
* </Provider>
* )
* ```
*/
declare const AppInitSDK: React.FC<AppInitSDKProps>;
declare const commonFetch: (url: string, requestInit?: RequestInit | undefined, timeout?: number | undefined, isK8sAPIRequest?: boolean | undefined) => Promise<Response>;
declare const commonFetchText: (url: string, requestInit?: RequestInit | undefined, timeout?: number | undefined, isK8sAPIRequest?: boolean | undefined) => Promise<string>;
declare const commonFetchJSON: {
<TResult>(url: string, requestInit?: RequestInit | undefined, timeout?: number | undefined, isK8sAPIRequest?: boolean | undefined): Promise<TResult>;
put<TResult_1>(url: string, data: unknown, requestInit?: RequestInit | undefined, timeout?: number | undefined, isK8sAPIRequest?: boolean | undefined): Promise<TResult_1>;
post<TResult_2>(url: string, data: unknown, requestInit?: RequestInit | undefined, timeout?: number | undefined, isK8sAPIRequest?: boolean | undefined): Promise<TResult_2>;
patch<TResult_3>(url: string, data: unknown, requestInit?: RequestInit | undefined, timeout?: number | undefined, isK8sAPIRequest?: boolean | undefined): Promise<TResult_3>;
delete<TResult_4>(url: string, data?: unknown, requestInit?: RequestInit | undefined, timeout?: number | undefined, isK8sAPIRequest?: boolean | undefined): Promise<TResult_4>;
};
declare type WatchK8sResult<R extends K8sResourceCommon | K8sResourceCommon[]> = [

@@ -480,2 +515,2 @@ data: R,

export { BulkMessageHandler, CloseHandler, DestroyHandler, ErrorHandler, K8sModelCommon, K8sResourceCommon, MessageHandler, OpenHandler, UtilsConfig, WebSocketFactory, WebSocketOptions, WebSocketState, commonFetch, commonFetchJSON, commonFetchText, getK8sResourceURL, getUtilsConfig, isUtilsConfigSet, k8sCreateResource, k8sDeleteResource, k8sGetResource, k8sListResource, k8sListResourceItems, k8sPatchResource, k8sUpdateResource, setUtilsConfig, useK8sWatchResource };
export { AppInitSDK, BulkMessageHandler, CloseHandler, DestroyHandler, ErrorHandler, K8sModelCommon, K8sResourceCommon, MessageHandler, OpenHandler, UtilsConfig, WebSocketFactory, WebSocketOptions, WebSocketState, commonFetch, commonFetchJSON, commonFetchText, getK8sResourceURL, getUtilsConfig, isUtilsConfigSet, k8sCreateResource, k8sDeleteResource, k8sGetResource, k8sListResource, k8sListResourceItems, k8sPatchResource, k8sUpdateResource, setUtilsConfig, useK8sWatchResource };

@@ -5,44 +5,18 @@ /*

@openshift/dynamic-plugin-sdk-utils version 1.0.0-alpha3
March 8, 2022 at 10:18:12 PM GMT+1
commit b1138726d539870ac4eaef5a1d8eb1717473bb53
@openshift/dynamic-plugin-sdk-utils version 1.0.0-alpha4
March 9, 2022 at 3:49:58 PM GMT+1
commit d81643bdebaa9b288c8758554a733891a14fdaf7
*/
import * as _ from 'lodash-es';
import { PluginStoreProvider } from '@openshift/dynamic-plugin-sdk';
import * as React from 'react';
import { useSelector, useDispatch } from 'react-redux';
import { useStore, Provider, useSelector, useDispatch } from 'react-redux';
import { plural } from 'pluralize';
import { Map, fromJS } from 'immutable';
import { action } from 'typesafe-actions';
import 'immutable';
import { createStore, combineReducers, compose, applyMiddleware } from 'redux';
import thunk from 'redux-thunk';
let config;
/**
* Checks if the {@link UtilsConfig} is set.
*/
const isUtilsConfigSet = () => {
return config !== undefined;
};
/**
* Set the {@link UtilsConfig} reference.
*
* This must be done before using any of the Kubernetes utilities.
*/
const setUtilsConfig = (c) => {
if (config !== undefined) {
throw new Error('UtilsConfig reference has already been set');
}
config = Object.freeze({ ...c });
};
/**
* Get the {@link UtilsConfig} reference.
*
* Throws an error if the reference isn't already set.
*/
const getUtilsConfig = () => {
if (config === undefined) {
throw new Error('UtilsConfig reference has not been set');
}
return config;
};
/**
* Base class for custom errors.

@@ -96,2 +70,52 @@ *

let config;
/**
* Checks if the {@link UtilsConfig} is set.
*/
const isUtilsConfigSet = () => {
return config !== undefined;
};
/**
* Set the {@link UtilsConfig} reference.
*
* This must be done before using any of the Kubernetes utilities.
*/
const setUtilsConfig = (c) => {
if (config !== undefined) {
throw new Error('UtilsConfig reference has already been set');
}
config = Object.freeze({ ...c });
};
/**
* Get the {@link UtilsConfig} reference.
*
* Throws an error if the reference isn't already set.
*/
const getUtilsConfig = () => {
if (config === undefined) {
throw new Error('UtilsConfig reference has not been set');
}
return config;
};
let reduxStore;
/**
* Set the {@link Store} reference.
*
* This must be done before using the AppInitSDK React entrypoint
*/
const setReduxStore = (storeData) => {
reduxStore = storeData;
};
/**
* Get the {@link Store} reference.
*
* Throws an error if the reference isn't already set.
*/
const getReduxStore = () => {
if (reduxStore === undefined) {
throw new Error('Redux store reference has not been set');
}
return reduxStore;
};
class TimeoutError extends CustomError {

@@ -599,2 +623,17 @@ constructor(url, ms) {

const getReferenceForModel = (model) => getReference({ group: model.apiGroup, version: model.apiVersion, kind: model.kind });
// TODO Migrate implementation or refactor K8s reducer to avoid usage
let k8sModels;
const allModels = () => {
if (!k8sModels) {
k8sModels = Map();
}
return k8sModels;
};
let namespacedResources;
const getNamespacedResources = () => {
if (!namespacedResources) {
namespacedResources = new Set();
}
return namespacedResources;
};
/**

@@ -656,2 +695,13 @@ * @deprecated - This will become obsolete when we move away from K8sResourceKindReference to K8sGroupVersionKind

const k8sListResourceItems = (options) => k8sListResource(options).then((result) => result.items);
const abbrBlacklist = ['ASS'];
/**
* Provides an abbreviation string for given kind with respect to abbrBlacklist.
* @param kind Kind for which the abbreviation is generated.
* @return Abbreviation string for given kind.
* TODO: Use in resource-icon component once it is being migrated to the SDK.
* * */
const kindToAbbr = (kind) => {
const abbrKind = (kind.replace(/[^A-Z]/g, '') || kind.toUpperCase()).slice(0, 4);
return abbrBlacklist.includes(abbrKind) ? abbrKind.slice(0, -1) : abbrKind;
};

@@ -701,3 +751,3 @@ /**

const WS = {};
const POLLs = {};
const POLLs$1 = {};
const REF_COUNTS = {};

@@ -715,5 +765,5 @@ const paginationLimit = 250;

}
const poller = POLLs[id];
const poller = POLLs$1[id];
window.clearInterval(poller);
delete POLLs[id];
delete POLLs$1[id];
delete REF_COUNTS[id];

@@ -780,3 +830,3 @@ dispatch(stopWatchK8s(id));

const pollAndWatch = async () => {
delete POLLs[id];
delete POLLs$1[id];
try {

@@ -797,4 +847,4 @@ const resourceVersion = await incrementallyLoad();

consoleLogger.warn('Resource does not support watching, falling back to polling.', k8skind);
if (!POLLs[id]) {
POLLs[id] = window.setTimeout(pollAndWatch, 15 * 1000);
if (!POLLs$1[id]) {
POLLs$1[id] = window.setTimeout(pollAndWatch, 15 * 1000);
}

@@ -814,4 +864,4 @@ return;

dispatch(errored(id, e));
if (!POLLs[id]) {
POLLs[id] = window.setTimeout(pollAndWatch, 15 * 1000);
if (!POLLs$1[id]) {
POLLs$1[id] = window.setTimeout(pollAndWatch, 15 * 1000);
}

@@ -838,6 +888,6 @@ return;

delete WS[id];
if (POLLs[id]) {
if (POLLs$1[id]) {
return;
}
POLLs[id] = window.setTimeout(pollAndWatch, 15 * 1000);
POLLs$1[id] = window.setTimeout(pollAndWatch, 15 * 1000);
})

@@ -886,3 +936,3 @@ // eslint-disable-next-line @typescript-eslint/no-explicit-any

};
POLLs[id] = window.setInterval(poller, 30 * 1000);
POLLs$1[id] = window.setInterval(poller, 30 * 1000);
poller();

@@ -898,3 +948,149 @@ if (!_.get(k8sType, 'verbs', ['watch']).includes('watch')) {

};
const receivedResources = (resources) => action(ActionType$1.ReceivedResources, { resources });
const getResourcesInFlight = () => action(ActionType$1.GetResourcesInFlight);
const SDK_API_DISCOVERY_RESOURCES_LOCAL_STORAGE_KEY = 'sdk/api-discovery-resources';
const cacheResources = (resources) => {
try {
localStorage.setItem(SDK_API_DISCOVERY_RESOURCES_LOCAL_STORAGE_KEY, JSON.stringify(resources));
}
catch (e) {
consoleLogger.error('Error caching API resources in localStorage', e);
throw e;
}
};
const getCachedResources = async () => {
const resourcesJSON = localStorage.getItem(SDK_API_DISCOVERY_RESOURCES_LOCAL_STORAGE_KEY);
if (!resourcesJSON) {
throw new Error(`No API resources found in localStorage for key ${SDK_API_DISCOVERY_RESOURCES_LOCAL_STORAGE_KEY}`);
}
// Clear cached resources after load as a safeguard. If there's any errors
// with the content that prevents the console from working, the bad data
// will not be loaded when the user refreshes the console. The cache will
// be refreshed when discovery completes.
localStorage.removeItem(SDK_API_DISCOVERY_RESOURCES_LOCAL_STORAGE_KEY);
const resources = JSON.parse(resourcesJSON);
consoleLogger.info('Loaded cached API resources from localStorage');
return resources;
};
const POLLs = {};
const apiDiscovery = 'apiDiscovery';
const API_DISCOVERY_POLL_INTERVAL = 60000;
const pluralizeKind = (kind) => {
// Use startCase to separate words so the last can be pluralized but remove spaces so as not to humanize
const pluralized = plural(_.startCase(kind)).replace(/\s+/g, '');
// Handle special cases like DB -> DBs (instead of DBS).
if (pluralized === `${kind}S`) {
return `${kind}s`;
}
return pluralized;
};
const defineModels = (list) => {
const { apiGroup, apiVersion } = list;
if (!list.resources || list.resources.length < 1) {
return [];
}
return list.resources
.filter(({ name }) => !name.includes('/'))
.map(({ name, singularName, namespaced, kind, verbs, shortNames }) => ({
...(apiGroup ? { apiGroup } : {}),
apiVersion,
kind,
namespaced,
verbs,
shortNames,
plural: name,
crd: true,
abbr: kindToAbbr(kind),
labelPlural: pluralizeKind(kind),
path: name,
id: singularName,
label: kind,
}));
};
const getResources = async () => {
const apiResourceData = await commonFetchJSON('/apis');
const groupVersionMap = apiResourceData.groups.reduce((acc, { name, versions, preferredVersion: { version } }) => {
acc[name] = {
versions: _.map(versions, 'version'),
preferredVersion: version,
};
return acc;
}, {});
const all = _.flatten(apiResourceData.groups.map((group) => group.versions.map((version) => `/apis/${version.groupVersion}`)))
.concat(['/api/v1'])
.map((p) => commonFetchJSON(`api/kubernetes${p}`).catch((err) => err));
return Promise.all(all).then((data) => {
const resourceSet = new Set();
const namespacedSet = new Set();
data.forEach((d) => d.resources &&
d.resources.forEach(({ namespaced, name }) => {
resourceSet.add(name);
if (namespaced) {
namespacedSet.add(name);
}
}));
const allResources = [...resourceSet].sort();
const safeResources = [];
const adminResources = [];
const models = _.flatten(data.filter((d) => d.resources).map(defineModels));
const coreResources = new Set([
'roles',
'rolebindings',
'clusterroles',
'clusterrolebindings',
'thirdpartyresources',
'nodes',
'secrets',
]);
allResources.forEach((r) => coreResources.has(r.split('/')[0]) ? adminResources.push(r) : safeResources.push(r));
const configResources = _.filter(models, (m) => m.apiGroup === 'config.openshift.io' && m.kind !== 'ClusterOperator');
const clusterOperatorConfigResources = _.filter(models, (m) => m.apiGroup === 'operator.openshift.io');
return {
allResources,
safeResources,
adminResources,
configResources,
clusterOperatorConfigResources,
namespacedSet,
models,
groupVersionMap,
};
});
};
const updateResources = () => (dispatch) => {
dispatch(getResourcesInFlight());
getResources()
.then((resources) => {
// Cache the resources whenever discovery completes to improve console load times.
cacheResources(resources);
dispatch(receivedResources(resources));
return resources;
})
.catch((err) => consoleLogger.error('Fetching resource failed:', err));
};
const startAPIDiscovery = () => (dispatch) => {
consoleLogger.info('API discovery method: Polling');
// Poll API discovery every 30 seconds since we can't watch CRDs
dispatch(updateResources());
if (POLLs[apiDiscovery]) {
clearTimeout(POLLs[apiDiscovery]);
delete POLLs[apiDiscovery];
}
POLLs[apiDiscovery] = window.setTimeout(() => dispatch(startAPIDiscovery()), API_DISCOVERY_POLL_INTERVAL);
};
const initAPIDiscovery = (storeInstance) => {
getCachedResources()
.then((resources) => {
if (resources) {
storeInstance.dispatch(receivedResources(resources));
}
// Still perform discovery to refresh the cache.
storeInstance.dispatch(startAPIDiscovery());
return resources;
})
.catch(() => storeInstance.dispatch(startAPIDiscovery()));
};
var ActionType;

@@ -908,4 +1104,330 @@ (function (ActionType) {

const emptyCoreState = { user: { identities: [], apiVersion: '', kind: '' }, activeCluster: '' };
/**
* Reducer function for the core
* @param state the reducer state
* @param action provided associated action type alongwith payload
* @param action.type type of the action
* @param action.payload associated payload for the action
* @see CoreAction
* @return The the updated state.
* * */
const coreReducer = (state, action) => {
if (!state) {
return emptyCoreState;
}
switch (action.type) {
case ActionType.BeginImpersonate:
return {
...state,
impersonate: {
kind: action.payload.kind,
name: action.payload.name,
subprotocols: action.payload.subprotocols,
},
};
case ActionType.EndImpersonate:
return _.omit(state, 'impersonate');
case ActionType.SetUser:
return {
...state,
user: action.payload.user,
};
case ActionType.SetActiveCluster:
return {
...state,
activeCluster: action.payload.cluster,
};
default:
return state;
}
};
const getReduxIdPayload = (state, reduxId) => state?.k8s?.get(reduxId);
const getK8sDataById = (state, id) => state?.getIn([id, 'data']);
const getQN = (obj) => {
const { name, namespace } = obj.metadata || {};
return (namespace ? `(${namespace})-` : '') + name;
};
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const moreRecent = (a, b) => {
const metaA = a.get('metadata').toJSON();
const metaB = b.get('metadata').toJSON();
if (metaA.uid !== metaB.uid) {
return new Date(metaA.creationTimestamp) > new Date(metaB.creationTimestamp);
}
return parseInt(metaA.resourceVersion, 10) > parseInt(metaB.resourceVersion, 10);
};
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const removeFromList = (list, resource) => {
const qualifiedName = getQN(resource);
consoleLogger.info(`deleting ${qualifiedName}`);
return list.delete(qualifiedName);
};
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const updateList = (list, nextJS) => {
const qualifiedName = getQN(nextJS);
const current = list.get(qualifiedName);
const next = fromJS(nextJS);
if (!current) {
return list.set(qualifiedName, next);
}
if (!moreRecent(next, current)) {
return list;
}
// TODO: (kans) only store the data for things we display ...
// and then only do this comparison for the same stuff!
if (current
.deleteIn(['metadata', 'resourceVersion'])
.equals(next.deleteIn(['metadata', 'resourceVersion']))) {
// If the only thing that differs is resource version, don't fire an update.
return list;
}
return list.set(qualifiedName, next);
};
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const loadList = (oldList, resources) => {
const existingKeys = new Set(oldList.keys());
// eslint-disable-next-line @typescript-eslint/no-explicit-any
return oldList.withMutations((list) => {
(resources || []).forEach((r) => {
const qualifiedName = getQN(r);
existingKeys.delete(qualifiedName);
const next = fromJS(r);
const current = list.get(qualifiedName);
if (!current || moreRecent(next, current)) {
list.set(qualifiedName, next);
}
});
// eslint-disable-next-line @typescript-eslint/no-explicit-any
existingKeys.forEach((k) => {
const r = list.get(k);
const metadata = r.get('metadata').toJSON();
if (!metadata.deletionTimestamp) {
consoleLogger.warn(`${metadata.namespace}-${metadata.name} is gone with no deletion timestamp!`);
}
list.delete(k);
});
});
};
const sdkK8sReducer = (state, action) => {
if (!state) {
return fromJS({
RESOURCES: { inFlight: false, models: Map() },
});
}
let newList;
switch (action.type) {
case ActionType$1.GetResourcesInFlight:
return state.setIn(['RESOURCES', 'inFlight'], true);
case ActionType$1.ReceivedResources:
return (action.payload.resources.models
.filter((model) => !state?.getIn(['RESOURCES', 'models']).has(getReferenceForModel(model)))
.filter((model) => {
const existingModel = state?.getIn(['RESOURCES', 'models', model.kind]);
return (!existingModel || getReferenceForModel(existingModel) !== getReferenceForModel(model));
})
.map((model) => {
if (model.namespaced) {
getNamespacedResources().add(getReferenceForModel(model));
}
else {
getNamespacedResources().delete(getReferenceForModel(model));
}
return model;
})
.reduce((prevState, newModel) => {
// FIXME: Need to use `kind` as model reference for legacy components accessing k8s primitives
const [modelRef, model] = allModels().findEntry((staticModel) => staticModel
? getReferenceForModel(staticModel) === getReferenceForModel(newModel)
: false) || [getReferenceForModel(newModel), newModel];
// Verbs and short names are not part of the static model definitions, so use the values found during discovery.
return prevState.updateIn(['RESOURCES', 'models'], (models) => models.set(modelRef, {
...model,
verbs: newModel.verbs,
shortNames: newModel.shortNames,
}));
}, state)
// TODO: Determine where these are used and implement filtering in that component instead of storing in Redux
.setIn(['RESOURCES', 'allResources'], action.payload.resources.allResources)
.setIn(['RESOURCES', 'safeResources'], action.payload.resources.safeResources)
.setIn(['RESOURCES', 'adminResources'], action.payload.resources.adminResources)
.setIn(['RESOURCES', 'configResources'], action.payload.resources.configResources)
.setIn(['RESOURCES', 'clusterOperatorConfigResources'], action.payload.resources.clusterOperatorConfigResources)
.setIn(['RESOURCES', 'namespacedSet'], action.payload.resources.namespacedSet)
.setIn(['RESOURCES', 'groupToVersionMap'], action.payload.resources.groupVersionMap)
.setIn(['RESOURCES', 'inFlight'], false));
case ActionType$1.StartWatchK8sObject:
return state.set(action.payload.id, Map({
loadError: '',
loaded: false,
data: {},
}));
case ActionType$1.StartWatchK8sList:
if (getK8sDataById(state, action.payload.id)) {
return state;
}
// We mergeDeep instead of overwriting state because it's possible to add filters before load/watching
return state.mergeDeep({
[action.payload.id]: {
loadError: '',
// has the data set been loaded successfully
loaded: false,
// Canonical data
data: Map(),
// client side filters to be applied externally (ie, we keep all data intact)
filters: Map(),
// The name of an element in the list that has been "selected"
selected: null,
},
});
case ActionType$1.ModifyObject: {
const { k8sObjects, id } = action.payload;
let currentJS = getK8sDataById(state, id) || {};
// getIn can return JS object or Immutable object
if (currentJS.toJSON) {
currentJS = currentJS.toJSON();
currentJS.metadata.resourceVersion = k8sObjects?.metadata?.resourceVersion;
if (_.isEqual(currentJS, k8sObjects)) {
// If the only thing that differs is resource version, don't fire an update.
return state;
}
}
return state.mergeIn([id], {
loadError: '',
loaded: true,
data: k8sObjects,
});
}
case ActionType$1.StopWatchK8s:
return state.delete(action.payload.id);
case ActionType$1.Errored:
if (!getK8sDataById(state, action.payload.id)) {
return state;
}
/* Don't overwrite data or loaded state if there was an error. Better to
* keep stale data around than to suddenly have it disappear on a user.
*/
return state.setIn([action.payload.id, 'loadError'], action.payload.k8sObjects);
case ActionType$1.Loaded:
if (!getK8sDataById(state, action.payload.id)) {
return state;
}
consoleLogger.info(`loaded ${action.payload.id}`);
// eslint-disable-next-line no-param-reassign
state = state.mergeDeep({
[action.payload.id]: { loaded: true, loadError: '' },
});
newList = loadList(getK8sDataById(state, action.payload.id), action.payload.k8sObjects);
break;
case ActionType$1.UpdateListFromWS:
newList = getK8sDataById(state, action.payload.id);
// k8sObjects is an array of k8s WS Events
// eslint-disable-next-line no-restricted-syntax
for (const { type, object } of action.payload.k8sObjects) {
switch (type) {
case 'DELETED':
newList = removeFromList(newList, object);
break;
case 'ADDED':
case 'MODIFIED':
newList = updateList(newList, object);
break;
default:
// possible `ERROR` type or other
consoleLogger.warn(`unknown websocket action: ${type}`);
}
}
break;
case ActionType$1.BulkAddToList:
if (!getK8sDataById(state, action.payload.id)) {
return state;
}
newList = getK8sDataById(state, action.payload.id);
newList = newList.merge(action.payload.k8sObjects.reduce((map, obj) => map.set(getQN(obj), fromJS(obj)), Map()));
break;
case ActionType$1.FilterList:
return state.setIn([action.payload.id, 'filters', action.payload.name], action.payload.value);
default:
return state;
}
return state.setIn([action.payload.id, 'data'], newList);
};
/**
* Dynamic Plugin SDK Redux store reducers
*
* If the app uses Redux, these can be spread into the root of your store to provide an integrated SDK.
* If the app does not use Redux, these will be provided via the SDK Redux Store.
*/
const SDKReducers = Object.freeze({
sdkCore: coreReducer,
k8s: sdkK8sReducer,
});
/**
* `useReduxStore` will provide the store instance if present or else create one along with info if the context was present.
*
* @example
* ```ts
* function Component () {
* const {store, storeContextPresent} = useReduxStore()
* return ...
* }
* ```
*/
const useReduxStore = () => {
const storeContext = useStore();
const [storeContextPresent, setStoreContextPresent] = React.useState(false);
const store = React.useMemo(() => {
if (storeContext) {
setStoreContextPresent(true);
setReduxStore(storeContext);
}
else {
consoleLogger.info('Creating the SDK redux store');
setStoreContextPresent(false);
const storeInstance = createStore(combineReducers(SDKReducers), {}, compose(applyMiddleware(thunk)));
setReduxStore(storeInstance);
}
return getReduxStore();
}, [storeContext]);
return { store, storeContextPresent };
};
/**
* Initializes the host application to work with Kubernetes and related SDK utilities.
* Add this at app-level to make use of app's redux store and pass configurations prop needed to initialize the app, preferred to have it under Provider.
* It checks for store instance if present or not.
* If the store is there then the reference is persisted to be used in SDK else it creates a new store and passes it to the children with the provider
* @component AppInitSDK
* @example
* ```tsx
* return (
* <Provider store={store}>
* <AppInitSDK configurations={{ appFetch, pluginStore, wsAppSettings }}>
* <App />
* </AppInitSDK>
* </Provider>
* )
* ```
*/
const AppInitSDK = ({ children, configurations }) => {
const { store, storeContextPresent } = useReduxStore();
const { appFetch, pluginStore, wsAppSettings, apiDiscovery = initAPIDiscovery } = configurations;
React.useEffect(() => {
try {
if (isUtilsConfigSet()) {
setUtilsConfig({ appFetch, wsAppSettings });
}
apiDiscovery(store);
}
catch (e) {
consoleLogger.warn('Error while initializing AppInitSDK', e);
}
}, [apiDiscovery, appFetch, store, wsAppSettings]);
return (React.createElement(PluginStoreProvider, { store: pluginStore }, !storeContextPresent ? React.createElement(Provider, { store: store }, children) : children));
};
class NoModelError extends CustomError {

@@ -1082,2 +1604,2 @@ constructor() {

export { WebSocketFactory, WebSocketState, commonFetch, commonFetchJSON, commonFetchText, getK8sResourceURL, getUtilsConfig, isUtilsConfigSet, k8sCreateResource, k8sDeleteResource, k8sGetResource, k8sListResource, k8sListResourceItems, k8sPatchResource, k8sUpdateResource, setUtilsConfig, useK8sWatchResource };
export { AppInitSDK, WebSocketFactory, WebSocketState, commonFetch, commonFetchJSON, commonFetchText, getK8sResourceURL, getUtilsConfig, isUtilsConfigSet, k8sCreateResource, k8sDeleteResource, k8sGetResource, k8sListResource, k8sListResourceItems, k8sPatchResource, k8sUpdateResource, setUtilsConfig, useK8sWatchResource };

2

package.json
{
"name": "@openshift/dynamic-plugin-sdk-utils",
"version": "1.0.0-alpha3",
"version": "1.0.0-alpha4",
"description": "Provides Kubernetes and React utilities",

@@ -5,0 +5,0 @@ "license": "Apache-2.0",

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc