model-navigator-standalone
Version:
Standalone MDF graph model visualizer
165 lines (156 loc) • 6.72 kB
JavaScript
import "core-js/modules/es.array.sort.js";
import "core-js/modules/es.regexp.exec.js";
import "core-js/modules/es.string.search.js";
import { createSlice, createSelector } from '@reduxjs/toolkit';
import { compareTwoStrings } from 'string-similarity';
import { getSearchSummary, calcMatchedStrings, storeSearchHistoryItem, retrieveSearchHistoryItems, clearSearchHistoryItems } from '../../components/ModelNavigator/DataDictionary/Search/DictionarySearcher/searchHelper';
// matchedResult - getSearchResultItem
const initialState = {
acCloseIconHidden: true,
searchHistoryItems: retrieveSearchHistoryItems(),
currentSearchKeyword: '',
searchString: '',
lastSearchError: '',
searchData: null,
searchResult: null,
overlayPropertyHidden: true,
matchedNodeIDs: [],
matchedNodeIDsInNameAndDescription: [],
matchedNodeIDsInProperties: [],
suggestionList: [],
clickedSuggestionItem: null,
clickedHistoryItem: null,
isSearchMode: false,
isSearching: false
};
// searchMode is set when SEARCH_RESULT_UPDATED - setSearchResult - mapped to onSearchResultUpdated
// searchMode is cleared when SEARCH_RESULT_CLEARED - clearSearchResult - mapped to onSearchResultCleared
const searchSlice = createSlice({
name: 'search',
initialState,
reducers: {
changedVisAcCloseIcon(state, action) {
const vis = action.payload;
state.acCloseIconHidden = vis === 'hide' ? true : false;
},
searchDataPrepared(state, action) {
const searchData = action.payload;
state.searchData = searchData;
},
searchResultCleared(state, action) {
state.isSearchMode = false;
state.searchResult = null;
},
searchStarted(state, action) {
const searchString = action.payload;
state.searchString = searchString;
state.isSearching = true;
},
searchCompleted(state, action) {
const {
result,
errorMsg,
save
} = action.payload;
state.isSearching = false;
state.currentSearchKeyword = state.searchString;
state.searchString = "";
if (!result || result.length === 0) {
state.searchResult = null;
state.lastSearchError = errorMsg || 'error';
state.suggestionList = [];
} else {
const summary = getSearchSummary(result);
state.searchResult = {
matchedNodes: result,
summary
};
state.lastSearchError = '';
if (save) {
state.searchHistoryItems = storeSearchHistoryItem({
keywordStr: state.currentSearchKeyword,
matchedCount: summary.generalMatchedNodeIDs.length
});
}
state.matchedNodeIDs = summary.generalMatchedNodeIDs;
state.matchedNodeIDsInNameAndDescription = summary.matchedNodeIDsInNameAndDescription;
state.matchedNodeIDsInProperties = summary.matchedNodeIDsInProperties;
const matchedStrings = calcMatchedStrings(result);
state.suggestionList = Object.keys(matchedStrings).sort((str1, str2) => compareTwoStrings(str2, state.searchString) - compareTwoStrings(str1, state.searchString)).map(s => ({
fullString: s,
matchedPieceIndices: matchedStrings[s].matchedPieceIndices
}));
state.isSearchMode = true;
}
},
suggestionItemClicked(state, action) {
const suggestionItem = action.payload;
state.clickedSuggestionItem = suggestionItem;
},
suggestionItemReset(state, action) {
state.clickedSuggestionItem = null;
},
suggestionsCleared(state, action) {
state.clickedSuggestionItem = null;
state.suggestionList = [];
},
historyItemClicked(state, action) {
const historyItem = action.payload;
state.clickedHistoryItem = historyItem;
},
clearedHistory(state, action) {
state.searchHistoryItems = clearSearchHistoryItems();
},
historyItemReset(state, action) {
state.clickedHistoryItem = null;
}
}
});
export const {
// reducer/actions
changedVisAcCloseIcon,
searchDataPrepared,
searchResultCleared,
searchStarted,
searchCompleted,
suggestionItemClicked,
suggestionItemReset,
suggestionsCleared,
historyItemClicked,
historyItemReset,
clearedHistory
} = searchSlice.actions;
export default searchSlice.reducer;
// export Selectors
export const selectAcCloseIconHidden = state => state.search.acCloseIconHidden;
export const selectSearchData = state => state.search.searchData;
export const selectIsSearchMode = state => state.search.isSearchMode;
export const selectIsSearching = state => state.search.isSearching;
export const selectLastSearchError = state => state.search.lastSearchError;
export const selectOverlayPropertyHidden = state => state.search.overlayPropertyHidden;
export const selectCurrentSearchKeyword = state => state.search.currentSearchKeyword;
export const selectSearchResult = state => state.search.searchResult;
export const selectSearchHistoryItems = state => state.search.searchHistoryItems;
export const selectClickedSuggestionItem = state => state.search.clickedSuggestionItem;
export const selectClickedHistoryItem = state => state.search.clickedHistoryItem;
export const selectSuggestionList = state => state.search.suggestionList;
export const selectMatchedNodeIDs = state => state.search.matchedNodeIDs;
export const selectMatchedNodeIDsInProperties = state => state.search.matchedNodeIDsInProperties;
export const selectMatchedNodeIDsInNameAndDescription = state => state.search.matchedNodeIDsInNameAndDescription;
export const selectSearchIsFinished = state => !state.search.isSearching && !!state.search.searchResult;
// note - to use the following, must get highlightingMatchedNodeID from graphSlice,
// then useSelector( (state) => selectMatchedResult(state, highlightingMatchedNodeID) )
export const selectMatchedResult = createSelector([selectSearchResult, (state, matchedNodeID) => matchedNodeID], (searchResult, matchedNodeID) => {
return searchResult && searchResult.matchedNodes.find(item => item.id === matchedNodeID);
});
// useSelector( (state) => selectSearchResultOfHighlighted(state, matchedNodeID) )
// export const selectSearchResultOfHighlighted = createSelector(
// [selectSearchResult, (state, matchedNodeID) => matchedNodeID],
// (searchResult, matchedNodeID) => {
// return searchResult.find( item => item.id == matchedNodeID );
// });
export const selectMatchedNodes = createSelector([selectMatchedNodeIDs, selectMatchedNodeIDsInProperties, selectMatchedNodeIDsInNameAndDescription], (matchedNodeIDs, matchedNodeIDsInProperties, matchedNodeIDsInNameAndDescription) => ({
matchedNodeIDs,
matchedNodeIDsInNameAndDescription,
matchedNodeIDsInProperties
}));