blob: 10374a93239fb3b95cda5dd1b07d659036adddb3 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import difference from 'lodash/difference';
import capitalize from 'lodash/capitalize';
import {REMOVE_CLUSTER_ITEMS_CONFIRMED} from './actionTypes';
export const LOAD_LIST = Symbol('LOAD_LIST');
export const ADD_CLUSTER = Symbol('ADD_CLUSTER');
export const ADD_CLUSTERS = Symbol('ADD_CLUSTERS');
export const REMOVE_CLUSTERS = Symbol('REMOVE_CLUSTERS');
export const UPDATE_CLUSTER = Symbol('UPDATE_CLUSTER');
export const UPSERT_CLUSTERS = Symbol('UPSERT_CLUSTERS');
export const ADD_CACHE = Symbol('ADD_CACHE');
export const UPDATE_CACHE = Symbol('UPDATE_CACHE');
export const UPSERT_CACHES = Symbol('UPSERT_CACHES');
export const REMOVE_CACHE = Symbol('REMOVE_CACHE');
const defaults = {clusters: new Map(), caches: new Map(), spaces: new Map()};
const mapByID = (items) => {
return Array.isArray(items) ? new Map(items.map((item) => [item._id, item])) : new Map(items);
};
export const reducer = (state = defaults, action) => {
switch (action.type) {
case LOAD_LIST: {
return {
clusters: mapByID(action.list.clusters),
domains: mapByID(action.list.domains),
caches: mapByID(action.list.caches),
spaces: mapByID(action.list.spaces),
plugins: mapByID(action.list.plugins)
};
}
case ADD_CLUSTER: {
return Object.assign({}, state, {
clusters: new Map([...state.clusters.entries(), [action.cluster._id, action.cluster]])
});
}
case ADD_CLUSTERS: {
return Object.assign({}, state, {
clusters: new Map([...state.clusters.entries(), ...action.clusters.map((c) => [c._id, c])])
});
}
case REMOVE_CLUSTERS: {
return Object.assign({}, state, {
clusters: new Map([...state.clusters.entries()].filter(([id, value]) => !action.clusterIDs.includes(id)))
});
}
case UPDATE_CLUSTER: {
const id = action._id || action.cluster._id;
return Object.assign({}, state, {
// clusters: new Map(state.clusters).set(id, Object.assign({}, state.clusters.get(id), action.cluster))
clusters: new Map(Array.from(state.clusters.entries()).map(([_id, cluster]) => {
return _id === id
? [action.cluster._id || _id, Object.assign({}, cluster, action.cluster)]
: [_id, cluster];
}))
});
}
case UPSERT_CLUSTERS: {
return action.clusters.reduce((state, cluster) => reducer(state, {
type: state.clusters.has(cluster._id) ? UPDATE_CLUSTER : ADD_CLUSTER,
cluster
}), state);
}
case ADD_CACHE: {
return Object.assign({}, state, {
caches: new Map([...state.caches.entries(), [action.cache._id, action.cache]])
});
}
case UPDATE_CACHE: {
const id = action.cache._id;
return Object.assign({}, state, {
caches: new Map(state.caches).set(id, Object.assign({}, state.caches.get(id), action.cache))
});
}
case UPSERT_CACHES: {
return action.caches.reduce((state, cache) => reducer(state, {
type: state.caches.has(cache._id) ? UPDATE_CACHE : ADD_CACHE,
cache
}), state);
}
case REMOVE_CACHE:
return state;
default:
return state;
}
};
export const RECEIVE_CLUSTER_EDIT = Symbol('RECEIVE_CLUSTER_EDIT');
export const RECEIVE_CACHE_EDIT = Symbol('RECEIVE_CACHE_EDIT');
export const RECEIVE_IGFSS_EDIT = Symbol('RECEIVE_IGFSS_EDIT');
export const RECEIVE_IGFS_EDIT = Symbol('RECEIVE_IGFS_EDIT');
export const RECEIVE_MODELS_EDIT = Symbol('RECEIVE_MODELS_EDIT');
export const RECEIVE_MODEL_EDIT = Symbol('RECEIVE_MODEL_EDIT');
export const editReducer = (state = {originalCluster: null}, action) => {
switch (action.type) {
case RECEIVE_CLUSTER_EDIT:
return {
...state,
originalCluster: action.cluster
};
case RECEIVE_CACHE_EDIT: {
return {
...state,
originalCache: action.cache
};
}
case RECEIVE_IGFSS_EDIT:
return {
...state,
originalIGFSs: action.igfss
};
case RECEIVE_IGFS_EDIT: {
return {
...state,
originalIGFS: action.igfs
};
}
case RECEIVE_MODELS_EDIT:
return {
...state,
originalModels: action.models
};
case RECEIVE_MODEL_EDIT: {
return {
...state,
originalModel: action.model
};
}
default:
return state;
}
};
export const SHOW_CONFIG_LOADING = Symbol('SHOW_CONFIG_LOADING');
export const HIDE_CONFIG_LOADING = Symbol('HIDE_CONFIG_LOADING');
const loadingDefaults = {isLoading: false, loadingText: 'Loading...'};
export const loadingReducer = (state = loadingDefaults, action) => {
switch (action.type) {
case SHOW_CONFIG_LOADING:
return {...state, isLoading: true, loadingText: action.loadingText};
case HIDE_CONFIG_LOADING:
return {...state, isLoading: false};
default:
return state;
}
};
export const setStoreReducerFactory = (actionTypes) => (state = new Set(), action = {}) => {
switch (action.type) {
case actionTypes.SET:
return new Set(action.items.map((i) => i._id));
case actionTypes.RESET:
return new Set();
case actionTypes.UPSERT:
return action.items.reduce((acc, item) => {acc.add(item._id); return acc;}, new Set(state));
case actionTypes.REMOVE:
return action.items.reduce((acc, item) => {acc.delete(item); return acc;}, new Set(state));
default:
return state;
}
};
export const mapStoreReducerFactory = (actionTypes) => (state = new Map(), action = {}) => {
switch (action.type) {
case actionTypes.SET:
return new Map(action.items.map((i) => [i._id, i]));
case actionTypes.RESET:
return new Map();
case actionTypes.UPSERT:
if (!action.items.length)
return state;
return action.items.reduce((acc, item) => {acc.set(item._id, item); return acc;}, new Map(state));
case actionTypes.REMOVE:
if (!action.ids.length)
return state;
return action.ids.reduce((acc, id) => {acc.delete(id); return acc;}, new Map(state));
default:
return state;
}
};
export const mapCacheReducerFactory = (actionTypes) => {
const mapStoreReducer = mapStoreReducerFactory(actionTypes);
return (state = {value: mapStoreReducer(), pristine: true}, action) => {
switch (action.type) {
case actionTypes.SET:
case actionTypes.REMOVE:
case actionTypes.UPSERT:
return {
value: mapStoreReducer(state.value, action),
pristine: false
};
case actionTypes.RESET:
return {
value: mapStoreReducer(state.value, action),
pristine: true
};
default:
return state;
}
};
};
export const basicCachesActionTypes = {
SET: 'SET_BASIC_CACHES',
RESET: 'RESET_BASIC_CACHES',
LOAD: 'LOAD_BASIC_CACHES',
UPSERT: 'UPSERT_BASIC_CACHES',
REMOVE: 'REMOVE_BASIC_CACHES'
};
export const mapStoreActionTypesFactory = (NAME) => ({
SET: `SET_${NAME}`,
RESET: `RESET_${NAME}`,
UPSERT: `UPSERT_${NAME}`,
REMOVE: `REMOVE_${NAME}`
});
export const clustersActionTypes = mapStoreActionTypesFactory('CLUSTERS');
export const shortClustersActionTypes = mapStoreActionTypesFactory('SHORT_CLUSTERS');
export const cachesActionTypes = mapStoreActionTypesFactory('CACHES');
export const shortCachesActionTypes = mapStoreActionTypesFactory('SHORT_CACHES');
export const modelsActionTypes = mapStoreActionTypesFactory('MODELS');
export const shortModelsActionTypes = mapStoreActionTypesFactory('SHORT_MODELS');
export const igfssActionTypes = mapStoreActionTypesFactory('IGFSS');
export const shortIGFSsActionTypes = mapStoreActionTypesFactory('SHORT_IGFSS');
export const itemsEditReducerFactory = (actionTypes) => {
const setStoreReducer = setStoreReducerFactory(actionTypes);
const mapStoreReducer = mapStoreReducerFactory(actionTypes);
return (state = {ids: setStoreReducer(), changedItems: mapStoreReducer()}, action) => {
switch (action.type) {
case actionTypes.SET:
return action.state;
case actionTypes.LOAD:
return {
...state,
ids: setStoreReducer(state.ids, {...action, type: actionTypes.UPSERT})
};
case actionTypes.RESET:
case actionTypes.UPSERT:
return {
ids: setStoreReducer(state.ids, action),
changedItems: mapStoreReducer(state.changedItems, action)
};
case actionTypes.REMOVE:
return {
ids: setStoreReducer(state.ids, {type: action.type, items: action.ids}),
changedItems: mapStoreReducer(state.changedItems, action)
};
default:
return state;
}
};
};
export const editReducer2 = (state = editReducer2.getDefaults(), action) => {
switch (action.type) {
case 'SET_EDIT':
return action.state;
case 'EDIT_CLUSTER': {
return {
...state,
changes: {
...['caches', 'models', 'igfss'].reduce((a, t) => ({
...a,
[t]: {
ids: action.cluster ? action.cluster[t] || [] : [],
changedItems: []
}
}), state.changes),
cluster: action.cluster
}
};
}
case 'RESET_EDIT_CHANGES': {
return {
...state,
changes: {
...['caches', 'models', 'igfss'].reduce((a, t) => ({
...a,
[t]: {
ids: state.changes.cluster ? state.changes.cluster[t] || [] : [],
changedItems: []
}
}), state.changes),
cluster: {...state.changes.cluster}
}
};
}
case 'UPSERT_CLUSTER': {
return {
...state,
changes: {
...state.changes,
cluster: action.cluster
}
};
}
case 'UPSERT_CLUSTER_ITEM': {
const {itemType, item} = action;
return {
...state,
changes: {
...state.changes,
[itemType]: {
ids: state.changes[itemType].ids.filter((_id) => _id !== item._id).concat(item._id),
changedItems: state.changes[itemType].changedItems.filter(({_id}) => _id !== item._id).concat(item)
}
}
};
}
case REMOVE_CLUSTER_ITEMS_CONFIRMED: {
const {itemType, itemIDs} = action;
return {
...state,
changes: {
...state.changes,
[itemType]: {
ids: state.changes[itemType].ids.filter((_id) => !itemIDs.includes(_id)),
changedItems: state.changes[itemType].changedItems.filter(({_id}) => !itemIDs.includes(_id))
}
}
};
}
default: return state;
}
};
editReducer2.getDefaults = () => ({
changes: ['caches', 'models', 'igfss'].reduce((a, t) => ({...a, [t]: {ids: [], changedItems: []}}), {cluster: null})
});
export const refsReducer = (refs) => (state, action) => {
switch (action.type) {
case 'ADVANCED_SAVE_COMPLETE_CONFIGURATION': {
const newCluster = action.changedItems.cluster;
const oldCluster = state.clusters.get(newCluster._id) || {};
const val = Object.keys(refs).reduce((state, ref) => {
if (!state || !state[refs[ref].store].size)
return state;
const addedSources = new Set(difference(newCluster[ref], oldCluster[ref] || []));
const removedSources = new Set(difference(oldCluster[ref] || [], newCluster[ref]));
const changedSources = new Map(action.changedItems[ref].map((m) => [m._id, m]));
const targets = new Map();
const maybeTarget = (id) => {
if (!targets.has(id))
targets.set(id, {[refs[ref].at]: {add: new Set(), remove: new Set()}});
return targets.get(id);
};
[...state[refs[ref].store].values()].forEach((target) => {
target[refs[ref].at]
.filter((sourceID) => removedSources.has(sourceID))
.forEach((sourceID) => maybeTarget(target._id)[refs[ref].at].remove.add(sourceID));
});
[...addedSources.values()].forEach((sourceID) => {
(changedSources.get(sourceID)[refs[ref].store] || []).forEach((targetID) => {
maybeTarget(targetID)[refs[ref].at].add.add(sourceID);
});
});
action.changedItems[ref].filter((s) => !addedSources.has(s._id)).forEach((source) => {
const newSource = source;
const oldSource = state[ref].get(source._id);
const addedTargets = difference(newSource[refs[ref].store], oldSource[refs[ref].store]);
const removedCaches = difference(oldSource[refs[ref].store], newSource[refs[ref].store]);
addedTargets.forEach((targetID) => {
maybeTarget(targetID)[refs[ref].at].add.add(source._id);
});
removedCaches.forEach((targetID) => {
maybeTarget(targetID)[refs[ref].at].remove.add(source._id);
});
});
const result = [...targets.entries()]
.filter(([targetID]) => state[refs[ref].store].has(targetID))
.map(([targetID, changes]) => {
const target = state[refs[ref].store].get(targetID);
return [
targetID,
{
...target,
[refs[ref].at]: target[refs[ref].at]
.filter((sourceID) => !changes[refs[ref].at].remove.has(sourceID))
.concat([...changes[refs[ref].at].add.values()])
}
];
});
return result.length
? {
...state,
[refs[ref].store]: new Map([...state[refs[ref].store].entries()].concat(result))
}
: state;
}, state);
return val;
}
default:
return state;
}
};
export const shortObjectsReducer = (state, action) => {
switch (action.type) {
case REMOVE_CLUSTER_ITEMS_CONFIRMED: {
const {itemType, itemIDs} = action;
const target = 'short' + capitalize(itemType);
const oldItems = state[target];
const newItems = {
value: itemIDs.reduce((acc, id) => {acc.delete(id); return acc;}, oldItems.value),
pristine: oldItems.pristine
};
return {
...state,
[target]: newItems
};
}
default:
return state;
}
};