@craftercms/studio-ui
Version:
Services, components, models & utils to build CrafterCMS authoring extensions.
244 lines (242 loc) • 9.75 kB
JavaScript
/*
* Copyright (C) 2007-2022 Crafter Software Corporation. All Rights Reserved.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 3 as published by
* the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/*
* Copyright (C) 2007-2022 Crafter Software Corporation. All Rights Reserved.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3 as published by
* the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { createReducer } from '@reduxjs/toolkit';
import {
clearClipboard,
completeDetailedItem,
fetchDetailedItem,
fetchDetailedItemComplete,
fetchDetailedItems,
fetchDetailedItemsComplete,
fetchQuickCreateList,
fetchQuickCreateListComplete,
fetchQuickCreateListFailed,
fetchSandboxItem,
fetchSandboxItemComplete,
fetchSandboxItems,
fetchSandboxItemsComplete,
reloadDetailedItem,
restoreClipboard,
setClipboard,
updateItemsByPath
} from '../actions/content';
import {
pathNavigatorConditionallySetPathComplete,
pathNavigatorFetchParentItemsComplete,
pathNavigatorFetchPathComplete
} from '../actions/pathNavigator';
import { parseSandBoxItemToDetailedItem } from '../../utils/content';
import { createLookupTable, reversePluckProps } from '../../utils/object';
import { changeSite } from '../actions/sites';
import {
pathNavigatorTreeFetchPathChildrenComplete,
pathNavigatorTreeFetchPathPageComplete,
pathNavigatorTreeRestoreComplete
} from '../actions/pathNavigatorTree';
import { STATE_LOCKED_MASK } from '../../utils/constants';
import { deleteContentEvent, lockContentEvent, moveContentEvent } from '../actions/system';
const initialState = {
quickCreate: {
error: null,
isFetching: false,
items: null
},
itemsByPath: {},
clipboard: null,
itemsBeingFetchedByPath: {}
};
const updateItemLockState = (state, { path, username, locked }) => {
if (
!state.itemsByPath[path] ||
(locked && state.itemsByPath[path].stateMap.locked) ||
(!locked && !state.itemsByPath[path].stateMap.locked)
) {
return state;
}
return Object.assign(Object.assign({}, state), {
itemsByPath: Object.assign(Object.assign({}, state.itemsByPath), {
[path]: Object.assign(Object.assign({}, state.itemsByPath[path]), {
lockOwner: locked ? username : null,
state: locked
? state.itemsByPath[path].state + STATE_LOCKED_MASK
: state.itemsByPath[path].state - STATE_LOCKED_MASK,
stateMap: Object.assign(Object.assign({}, state.itemsByPath[path].stateMap), { locked })
})
})
});
};
const updateItemByPath = (state, { payload: { parent, children } }) => {
const nextByPath = Object.assign(
Object.assign({}, state.itemsByPath),
createLookupTable(parseSandBoxItemToDetailedItem(children, state.itemsByPath), 'path')
);
if (children.levelDescriptor) {
nextByPath[children.levelDescriptor.path] = parseSandBoxItemToDetailedItem(
children.levelDescriptor,
state.itemsByPath[children.levelDescriptor.path]
);
}
if (parent) {
nextByPath[parent.path] = parent;
}
return Object.assign(Object.assign({}, state), { itemsByPath: nextByPath });
};
const updateItemsBeingFetchedByPath = (state, { payload: { path } }) => {
state.itemsBeingFetchedByPath[path] = true;
};
const updateItemsBeingFetchedByPaths = (state, { payload: { paths } }) => {
paths.forEach((path) => {
state.itemsBeingFetchedByPath[path] = true;
});
};
const reducer = createReducer(initialState, {
[fetchQuickCreateList.type]: (state) =>
Object.assign(Object.assign({}, state), {
quickCreate: Object.assign(Object.assign({}, state.quickCreate), { isFetching: true })
}),
[fetchQuickCreateListComplete.type]: (state, { payload }) =>
Object.assign(Object.assign({}, state), {
quickCreate: Object.assign(Object.assign({}, state.quickCreate), { items: payload, isFetching: false })
}),
[fetchQuickCreateListFailed.type]: (state, error) =>
Object.assign(Object.assign({}, state), {
quickCreate: Object.assign(Object.assign({}, state.quickCreate), {
isFetching: false,
error: error.payload.response
})
}),
[fetchDetailedItem.type]: updateItemsBeingFetchedByPath,
[reloadDetailedItem.type]: updateItemsBeingFetchedByPath,
[completeDetailedItem.type]: updateItemsBeingFetchedByPath,
[fetchSandboxItem.type]: updateItemsBeingFetchedByPath,
[fetchSandboxItems.type]: updateItemsBeingFetchedByPaths,
[fetchSandboxItemsComplete.type]: (state, { payload: { items } }) => {
items.forEach((item) => {
const path = item.path;
state.itemsByPath[path] = parseSandBoxItemToDetailedItem(item, state.itemsByPath[item.path]);
delete state.itemsBeingFetchedByPath[path];
});
},
[fetchDetailedItemComplete.type]: (state, { payload }) =>
Object.assign(Object.assign({}, state), {
itemsByPath: Object.assign(Object.assign({}, state.itemsByPath), { [payload.path]: payload }),
itemsBeingFetchedByPath: Object.assign({}, reversePluckProps(state.itemsBeingFetchedByPath, payload.path))
}),
[fetchDetailedItems.type]: updateItemsBeingFetchedByPaths,
[fetchDetailedItemsComplete.type]: (state, { payload: { items } }) => {
items.forEach((item) => {
const path = item.path;
state.itemsByPath[path] = item;
delete state.itemsBeingFetchedByPath[path];
});
},
[fetchSandboxItemComplete.type]: (state, { payload: { item } }) => {
const path = item.path;
state.itemsByPath[path] = parseSandBoxItemToDetailedItem(item, state.itemsByPath[item.path]);
state.itemsBeingFetchedByPath[path] = false;
},
[restoreClipboard.type]: (state, { payload }) => Object.assign(Object.assign({}, state), { clipboard: payload }),
[setClipboard.type]: (state, { payload }) => Object.assign(Object.assign({}, state), { clipboard: payload }),
[clearClipboard.type]: (state) => Object.assign(Object.assign({}, state), { clipboard: null }),
[pathNavigatorConditionallySetPathComplete.type]: updateItemByPath,
[pathNavigatorFetchPathComplete.type]: updateItemByPath,
[pathNavigatorFetchParentItemsComplete.type]: (state, { payload: { items, children } }) => {
return Object.assign(Object.assign({}, state), {
itemsByPath: Object.assign(
Object.assign(
Object.assign(
Object.assign({}, state.itemsByPath),
createLookupTable(parseSandBoxItemToDetailedItem(children, state.itemsByPath), 'path')
),
children.levelDescriptor && {
[children.levelDescriptor.path]: parseSandBoxItemToDetailedItem(
children.levelDescriptor,
state.itemsByPath[children.levelDescriptor.path]
)
}
),
createLookupTable(
items.reduce((items, item) => {
var _a;
if ((_a = state.itemsByPath[item.path]) === null || _a === void 0 ? void 0 : _a.live) {
item.live = state.itemsByPath[item.path].live;
item.staging = state.itemsByPath[item.path].staging;
}
return items;
}, items),
'path'
)
)
});
},
[pathNavigatorTreeFetchPathChildrenComplete.type]: updateItemByPath,
[pathNavigatorTreeFetchPathPageComplete.type]: updateItemByPath,
[pathNavigatorTreeRestoreComplete.type]: (state, action) => {
const {
payload: { children, items }
} = action;
let nextByPath = {};
Object.values(children).forEach((children) => {
Object.assign(nextByPath, createLookupTable(parseSandBoxItemToDetailedItem(children, state.itemsByPath), 'path'));
if (children.levelDescriptor) {
nextByPath[children.levelDescriptor.path] = parseSandBoxItemToDetailedItem(
children.levelDescriptor,
state.itemsByPath[children.levelDescriptor.path]
);
}
});
items.forEach((item) => {
nextByPath[item.path] = item;
});
return Object.assign(Object.assign({}, state), {
itemsByPath: Object.assign(Object.assign({}, state.itemsByPath), nextByPath)
});
},
[updateItemsByPath.type]: (state, { payload }) => {
return updateItemByPath(state, { payload: { parent: null, children: payload.items } });
},
[changeSite.type]: () => initialState,
[lockContentEvent.type]: (state, { payload }) =>
updateItemLockState(state, {
path: payload.targetPath,
username: payload.user.username,
locked: payload.locked
}),
[deleteContentEvent.type]: (state, { payload: { targetPath } }) => {
delete state.itemsByPath[targetPath];
delete state.itemsBeingFetchedByPath[targetPath];
},
[moveContentEvent.type]: (state, { payload: { sourcePath } }) => {
delete state.itemsByPath[sourcePath];
delete state.itemsBeingFetchedByPath[sourcePath];
}
});
export default reducer;