import * as q from '../../../backend/src/Model' import { AppState } from '../reducers' import { autoExpandLimitSet } from '../components/SettingsDrawer/Settings' import { batchActions } from 'redux-batched-actions' import { default as persistentStorage, StorageIdentifier } from '../utils/PersistentStorage' import { Dispatch } from 'redux' import { showError } from './Global' import { showTree } from './Tree' import { TopicViewModel } from '../model/TopicViewModel' import { ActionTypes, SettingsState, TopicOrder } from '../reducers/Settings' import { Base64Message } from '../../../backend/src/Model/Base64Message' import { globalActions } from '.' const settingsIdentifier: StorageIdentifier> = { id: 'Settings', } export const loadSettings = () => async (dispatch: Dispatch, getState: () => AppState) => { try { const settings = (await persistentStorage.load(settingsIdentifier)) || {} dispatch({ settings: getState().settings.merge(settings), type: ActionTypes.SETTINGS_DID_LOAD_SETTINGS, }) } catch (error) { dispatch(showError(error)) } dispatch(globalActions.didLaunch()) } export const storeSettings = () => async (dispatch: Dispatch, getState: () => AppState) => { const settings = { ...getState().settings.toJS(), autoExpandLimit: undefined, topicFilter: undefined, visible: undefined, } try { await persistentStorage.store(settingsIdentifier, settings) } catch (error) { dispatch(showError(error)) } } export const setAutoExpandLimit = (autoExpandLimit: number = 0) => (dispatch: Dispatch) => { dispatch({ autoExpandLimit, type: ActionTypes.SETTINGS_SET_AUTO_EXPAND_LIMIT, }) } export const setTimeLocale = (timeLocale: string) => (dispatch: Dispatch) => { dispatch({ timeLocale, type: ActionTypes.SETTINGS_SET_TIME_LOCALE, }) dispatch(storeSettings()) } export const selectTopicWithMouseOver = (doSelect: boolean) => (dispatch: Dispatch) => { dispatch({ selectTopicWithMouseOver: doSelect, type: ActionTypes.SETTINGS_SET_SELECT_TOPIC_WITH_MOUSE_OVER, }) dispatch(storeSettings()) } export const setValueDisplayMode = (valueRendererDisplayMode: 'diff' | 'raw') => (dispatch: Dispatch) => { dispatch({ valueRendererDisplayMode, type: ActionTypes.SETTINGS_SET_VALUE_RENDERER_DISPLAY_MODE, }) dispatch(storeSettings()) } export const toggleHighlightTopicUpdates = () => (dispatch: Dispatch) => { dispatch({ type: ActionTypes.SETTINGS_TOGGLE_HIGHLIGHT_ACTIVITY, }) dispatch(storeSettings()) } export const setTopicOrder = (topicOrder: TopicOrder = TopicOrder.none) => (dispatch: Dispatch) => { dispatch({ topicOrder, type: ActionTypes.SETTINGS_SET_TOPIC_ORDER, }) dispatch(storeSettings()) } export const filterTopics = (filterStr: string) => (dispatch: Dispatch, getState: () => AppState) => { const { tree } = getState().connection dispatch({ topicFilter: filterStr, type: ActionTypes.SETTINGS_FILTER_TOPICS, }) if (!filterStr || !tree) { dispatch(batchActions([setAutoExpandLimit(0), showTree(tree) as any])) return } const topicFilter = filterStr.toLowerCase() const nodeFilter = (node: q.TreeNode): boolean => { const topicMatches = node .path() .toLowerCase() .indexOf(topicFilter) !== -1 if (topicMatches) { return true } const messageMatches = node.message && node.message.value && Base64Message.toUnicodeString(node.message.value) .toLowerCase() .indexOf(filterStr) !== -1 return Boolean(messageMatches) } const resultTree = tree .childTopics() .filter(nodeFilter) .map((node: q.TreeNode) => { const clone = node.unconnectedClone() q.TreeNodeFactory.insertNodeAtPosition(node.path().split('/'), clone) return clone.firstNode() }) .reduce((a: q.TreeNode, b: q.TreeNode) => { a.updateWithNode(b) return a }, new q.Tree()) const nextTree: q.Tree = resultTree as q.Tree if (tree.updateSource && tree.connectionId) { nextTree.updateWithConnection(tree.updateSource, tree.connectionId, nodeFilter) } dispatch(batchActions([setAutoExpandLimit(autoExpandLimitForTree(nextTree)), showTree(nextTree) as any])) } function autoExpandLimitForTree(tree: q.Tree) { if (!tree) { return 0 } function closestExistingLimit(i: number): number { const sorted = autoExpandLimitSet.sort((a, b) => Math.abs(a.limit - i) - Math.abs(b.limit - i)) return sorted[0]!.limit } const count = tree.childTopicCount() const calculatedLimit = Math.max(7 - Math.log(count), 0) * 2 return closestExistingLimit(calculatedLimit) } export const toggleTheme = () => (dispatch: Dispatch, getState: () => AppState) => { dispatch({ type: getState().settings.get('theme') === 'light' ? ActionTypes.SETTINGS_SET_THEME_DARK : ActionTypes.SETTINGS_SET_THEME_LIGHT, }) dispatch(storeSettings()) }