| /* |
| * 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; |
| } |
| }; |