diff --git a/packages/xod-client/src/core/styles/components/Button.scss b/packages/xod-client/src/core/styles/components/Button.scss
index af4fc70b..75597c9a 100644
--- a/packages/xod-client/src/core/styles/components/Button.scss
+++ b/packages/xod-client/src/core/styles/components/Button.scss
@@ -52,4 +52,10 @@
box-sizing: border-box;
padding: 6px 10px;
}
+
+ &--inline {
+ height: 22px;
+ line-height: 0;
+ padding: 0.2rem 0.5rem;
+ }
}
diff --git a/packages/xod-client/src/core/styles/components/ReactDatasheet.scss b/packages/xod-client/src/core/styles/components/ReactDatasheet.scss
index 2dd3c632..aa9321d9 100644
--- a/packages/xod-client/src/core/styles/components/ReactDatasheet.scss
+++ b/packages/xod-client/src/core/styles/components/ReactDatasheet.scss
@@ -34,7 +34,6 @@ span.data-grid-container, span.data-grid-container:focus {
}
.data-grid-container .data-grid .cell.read-only {
- background: whitesmoke;
color: #999;
text-align: center;
}
@@ -92,7 +91,7 @@ span.data-grid-container, span.data-grid-container:focus {
display: block;
}
-.data-grid-container tr:first-child .cell {
+.data-grid.with-header tr:first-child .cell {
font-weight: bold;
text-align: right;
background-color: $grey;
diff --git a/packages/xod-client/src/core/styles/components/TableLog.scss b/packages/xod-client/src/core/styles/components/TableLog.scss
new file mode 100644
index 00000000..89229b59
--- /dev/null
+++ b/packages/xod-client/src/core/styles/components/TableLog.scss
@@ -0,0 +1,93 @@
+@mixin header-vertical-centered {
+ height: 22px;
+ padding: 8px 0;
+}
+
+.TableLog {
+ position: relative;
+ width: 100%;
+ height: 100%;
+
+ flex: 1;
+ flex-grow: 1;
+ flex-flow: column;
+
+ &-header {
+ height: 40px;
+ overflow: hidden;
+ padding: 1px 3px 1px 8px;
+
+ .sourceSelector {
+ @include header-vertical-centered;
+ float: left;
+ margin-right: 1rem;
+
+ label {
+ color: $chalk;
+ margin-right: .5rem;
+ }
+
+ select {
+ width: 300px;
+ text-overflow: ellipsis;
+ }
+ }
+ .sheets {
+ @include header-vertical-centered;
+ float: left;
+ margin-left: 1rem;
+
+ .currentSheet {
+ display: inline-block;
+ margin: 0 .5rem;
+ color: $chalk;
+ }
+
+ button {
+ height: 22px;
+ }
+ }
+ .actions {
+ @include header-vertical-centered;
+ float: right;
+ margin-left: 1rem;
+
+ button {
+ margin-left: 2px;
+
+ .fa {
+ margin-right: .5em;
+ }
+ }
+ }
+ }
+
+ &-content {
+ position: absolute;
+ top: 40px;
+ bottom: 0;
+ left: 0;
+ right: 0;
+ overflow: scroll;
+
+ background: $grey;
+
+ .no-data {
+ position: absolute;
+ top: 50%;
+ margin-top: -.5em;
+
+ width: 100%;
+ text-align: center;
+
+ color: $chalk;
+ font-size: $font-size-l;
+ }
+
+ .data-grid {
+ margin-top: -2px; // compensate border-spacing
+ }
+
+ @include styled-scrollbar();
+ }
+}
diff --git a/packages/xod-client/src/core/styles/main.scss b/packages/xod-client/src/core/styles/main.scss
index 0154c9bd..cf2fd638 100644
--- a/packages/xod-client/src/core/styles/main.scss
+++ b/packages/xod-client/src/core/styles/main.scss
@@ -58,6 +58,7 @@
'components/SnappingPreviewLayer',
'components/SplitPane',
'components/Suggester',
+ 'components/TableLog',
'components/Tabs',
'components/TabsContainer',
'components/TabsItem',
diff --git a/packages/xod-client/src/debugger/actions.js b/packages/xod-client/src/debugger/actions.js
index b6ec1f24..9f602d0f 100644
--- a/packages/xod-client/src/debugger/actions.js
+++ b/packages/xod-client/src/debugger/actions.js
@@ -36,7 +36,7 @@ export const startDebuggerSession = (
nodePinKeysMap,
tableLogNodeIds,
pinsAffectedByErrorRaisers,
- currentPatchPath,
+ patchPath,
globals,
tetheringInetNodeId
) => ({
@@ -47,7 +47,7 @@ export const startDebuggerSession = (
nodePinKeysMap,
tableLogNodeIds,
pinsAffectedByErrorRaisers,
- patchPath: currentPatchPath,
+ patchPath,
globals,
tetheringInetNodeId,
},
diff --git a/packages/xod-client/src/debugger/constants.js b/packages/xod-client/src/debugger/constants.js
index 062f9289..b9631ba8 100644
--- a/packages/xod-client/src/debugger/constants.js
+++ b/packages/xod-client/src/debugger/constants.js
@@ -24,3 +24,5 @@ export const SESSION_TYPE = {
SERIAL: 'serial',
SIMULATON: 'simulation',
};
+
+export const NEW_SHEET = String.fromCharCode(0xc);
diff --git a/packages/xod-client/src/debugger/reducer.js b/packages/xod-client/src/debugger/reducer.js
index 30f8a571..726fd73e 100644
--- a/packages/xod-client/src/debugger/reducer.js
+++ b/packages/xod-client/src/debugger/reducer.js
@@ -33,7 +33,7 @@ import {
import * as EAT from '../editor/actionTypes';
-import { UPLOAD_MSG_TYPE, LOG_TAB_TYPE, SESSION_TYPE } from './constants';
+import { UPLOAD_MSG_TYPE, LOG_TAB_TYPE, SESSION_TYPE, NEW_SHEET } from './constants';
import * as MSG from './messages';
import { STATUS } from '../utils/constants';
import { isXodErrorMessage } from './debugProtocol';
@@ -157,7 +157,6 @@ const updateInteractiveNodeValues = R.curry((messageList, state) => {
)(watchNodeMessages);
// Prepare data for table logs
- const NEW_SHEET = String.fromCharCode(0xc); // TODO: Move somewhere
const newTableLogData = R.map(
R.compose(
R.reduce(
diff --git a/packages/xod-client/src/debugger/selectors.js b/packages/xod-client/src/debugger/selectors.js
index a0c408ed..a903d392 100644
--- a/packages/xod-client/src/debugger/selectors.js
+++ b/packages/xod-client/src/debugger/selectors.js
@@ -296,3 +296,20 @@ export const tetheringInetTransmitter = R.compose(
R.path(['tetheringInet', 'transmitter']),
getDebuggerState
);
+
+// =============================================================================
+//
+// Table log
+//
+// =============================================================================
+
+export const getTableLogValues = R.compose(
+ R.prop('tableLogValues'),
+ getDebuggerState
+);
+
+export const getTableLogSources = R.compose(R.keys, getTableLogValues);
+
+export const getTableLogsByNodeId = R.curry((nodeId, state) =>
+ R.compose(R.pathOr([], ['tableLogValues', nodeId]), getDebuggerState)(state)
+);
diff --git a/packages/xod-client/src/editor/actionTypes.js b/packages/xod-client/src/editor/actionTypes.js
index 47513d3b..5da06c1b 100644
--- a/packages/xod-client/src/editor/actionTypes.js
+++ b/packages/xod-client/src/editor/actionTypes.js
@@ -69,3 +69,6 @@ export const NODE_PROPERTY_UPDATING = 'NODE_PROPERTY_UPDATING';
export const SHOW_COLORPICKER_WIDGET = 'SHOW_COLORPICKER_WIDGET';
export const HIDE_COLORPICKER_WIDGET = 'HIDE_COLORPICKER_WIDGET';
+
+export const OPEN_TABLE_LOG_TAB = 'OPEN_TABLE_LOG_TAB';
+export const CHANGE_TABLE_LOG_SHEET = 'CHANGE_TABLE_LOG_SHEET';
diff --git a/packages/xod-client/src/editor/actions.js b/packages/xod-client/src/editor/actions.js
index 7b541ca1..dd7a3509 100644
--- a/packages/xod-client/src/editor/actions.js
+++ b/packages/xod-client/src/editor/actions.js
@@ -940,3 +940,39 @@ export const tweakNodeProperty = (nodeId, kind, key, value) => (
})
);
};
+
+export const openTableLogTab = nodeId => (dispatch, getState) => {
+ const sheets = DebuggerSelectors.getTableLogsByNodeId(nodeId, getState());
+ return dispatch({
+ type: ActionType.OPEN_TABLE_LOG_TAB,
+ payload: {
+ nodeId,
+ activeSheetIndex: sheets.length > 0 ? sheets.length - 1 : 0,
+ },
+ });
+};
+
+export const changeActiveSheet = R.curry((tabId, nodeId, newSheetIndex) => ({
+ type: ActionType.CHANGE_TABLE_LOG_SHEET,
+ payload: {
+ tabId,
+ nodeId,
+ newSheetIndex,
+ },
+}));
+
+export const changeTableLogSource = (tabId, nodeId) => (dispatch, getState) => {
+ const newSourceSheets = DebuggerSelectors.getTableLogsByNodeId(
+ nodeId,
+ getState()
+ );
+ const newSheetIndex = R.max(0, newSourceSheets.length - 1);
+ dispatch({
+ type: ActionType.CHANGE_TABLE_LOG_SHEET,
+ payload: {
+ tabId,
+ nodeId,
+ newSheetIndex,
+ },
+ });
+};
diff --git a/packages/xod-client/src/editor/components/TabtestEditor.jsx b/packages/xod-client/src/editor/components/TabtestEditor.jsx
index f079ee43..6208fea1 100644
--- a/packages/xod-client/src/editor/components/TabtestEditor.jsx
+++ b/packages/xod-client/src/editor/components/TabtestEditor.jsx
@@ -99,6 +99,7 @@ const TabtestEditor = ({
,
tab => {
+ // Render
component only for PATCH or DEBUGGER
+ // tab types
+ if (tab.type !== TAB_TYPES.PATCH && tab.type !== TAB_TYPES.DEBUGGER)
+ return null;
+
// Do not render
component if opened tab
// is in EditingCppImplementation mode.
if (tab.editedAttachment) return null;
@@ -139,12 +145,37 @@ class Editor extends React.Component {
);
}
+ renderTableLogTab() {
+ const { currentTab } = this.props;
+
+ return foldMaybe(
+ null,
+ tab => {
+ // Render only for TABLE_LOG tab type
+ if (tab.type !== TAB_TYPES.TABLE_LOG) return null;
+
+ return (
+
+ );
+ },
+ currentTab
+ );
+ }
+
renderOpenedAttachmentEditorTabs() {
return foldMaybe(
null,
currentTab => {
const tabs = this.props.attachmentEditorTabs.map(
({ id, type, patchPath, editedAttachment }) => {
+ // Render only for PATCH or DEBUGGER tab types
+ if (type !== TAB_TYPES.PATCH && type !== TAB_TYPES.DEBUGGER)
+ return null;
+
const patch = XP.getPatchByPathUnsafe(
patchPath,
this.props.project
@@ -156,11 +187,6 @@ class Editor extends React.Component {
R.propOr('', editedAttachment, XP.MANAGED_ATTACHMENT_TEMPLATES)
);
- const currentPatchPath = explodeMaybe(
- 'No currentPatchPath, but currentTab exists',
- this.props.currentPatchPath
- );
-
switch (editedAttachment) {
case XP.TABTEST_MARKER_PATH:
return (
@@ -177,11 +203,9 @@ class Editor extends React.Component {
}
isInDebuggerTab={type === TAB_TYPES.DEBUGGER}
isRunning={this.props.isTabtestRunning}
- onRunClick={() =>
- this.props.actions.runTabtest(currentPatchPath)
- }
+ onRunClick={() => this.props.actions.runTabtest(patchPath)}
onClose={this.props.actions.closeAttachmentEditor}
- patchPath={currentPatchPath}
+ patchPath={patchPath}
/>
);
@@ -200,7 +224,7 @@ class Editor extends React.Component {
}
isInDebuggerTab={type === TAB_TYPES.DEBUGGER}
onClose={this.props.actions.closeAttachmentEditor}
- patchPath={currentPatchPath}
+ patchPath={patchPath}
/>
);
@@ -282,6 +306,7 @@ class Editor extends React.Component {
>
{this.renderOpenedPatchTab()}
{this.renderOpenedAttachmentEditorTabs()}
+ {this.renderTableLogTab()}
diff --git a/packages/xod-client/src/editor/containers/Patch/index.jsx b/packages/xod-client/src/editor/containers/Patch/index.jsx
index 802aca5e..56119441 100644
--- a/packages/xod-client/src/editor/containers/Patch/index.jsx
+++ b/packages/xod-client/src/editor/containers/Patch/index.jsx
@@ -382,6 +382,7 @@ const mapDispatchToProps = dispatch => ({
addInteractiveNode: ProjectActions.addInteractiveNode,
focusBoundValue: EditorActions.focusBoundValue,
focusLabel: EditorActions.focusLabel,
+ openTableLogTab: EditorActions.openTableLogTab,
},
dispatch
),
diff --git a/packages/xod-client/src/editor/containers/Patch/modes/debugging.jsx b/packages/xod-client/src/editor/containers/Patch/modes/debugging.jsx
index 164b8e01..137d3a3f 100644
--- a/packages/xod-client/src/editor/containers/Patch/modes/debugging.jsx
+++ b/packages/xod-client/src/editor/containers/Patch/modes/debugging.jsx
@@ -16,6 +16,8 @@ const debuggingMode = R.merge(selectingMode, {
onNodeDoubleClick(api, nodeId, patchPath) {
if (R.contains(patchPath, R.keys(XP.MANAGED_ATTACHMENT_FILENAMES))) {
api.props.actions.openAttachmentEditor(patchPath);
+ } else if (XP.isTableLogPatchPath(patchPath)) {
+ api.props.actions.openTableLogTab(nodeId);
} else if (
XP.isConstantNodeType(patchPath) ||
XP.isTweakPath(patchPath) ||
diff --git a/packages/xod-client/src/editor/containers/Patch/modes/selecting.jsx b/packages/xod-client/src/editor/containers/Patch/modes/selecting.jsx
index 550e5faa..1aadc555 100644
--- a/packages/xod-client/src/editor/containers/Patch/modes/selecting.jsx
+++ b/packages/xod-client/src/editor/containers/Patch/modes/selecting.jsx
@@ -231,6 +231,8 @@ const selectingMode = {
onNodeDoubleClick(api, nodeId, patchPath) {
if (R.contains(patchPath, R.keys(XP.MANAGED_ATTACHMENT_FILENAMES))) {
api.props.actions.openAttachmentEditor(patchPath);
+ } else if (XP.isTableLogPatchPath(patchPath)) {
+ api.props.actions.openTableLogTab(nodeId);
} else if (
XP.isConstantNodeType(patchPath) ||
XP.isTweakPath(patchPath) ||
diff --git a/packages/xod-client/src/editor/containers/TableLog.jsx b/packages/xod-client/src/editor/containers/TableLog.jsx
new file mode 100644
index 00000000..c66904f7
--- /dev/null
+++ b/packages/xod-client/src/editor/containers/TableLog.jsx
@@ -0,0 +1,229 @@
+import * as R from 'ramda';
+import React from 'react';
+import PropTypes from 'prop-types';
+import { connect } from 'react-redux';
+import { bindActionCreators } from 'redux';
+
+import ReactDataSheet from 'react-datasheet';
+import { Icon } from 'react-fa';
+
+import * as Actions from '../actions';
+import * as DebuggerSelectors from '../../debugger/selectors';
+
+import { addConfirmation } from '../../messages/actions';
+import {
+ LOG_COPIED,
+ LOG_COPY_NOT_SUPPORTED,
+ logCopyError,
+ logSaveError,
+} from '../../debugger/messages';
+
+// :: [[String]] -> [[{ value, readOnly }]]
+const tableLogToDataSheet = R.map(
+ R.map(
+ R.applySpec({
+ value: R.identity,
+ readOnly: R.T,
+ })
+ )
+);
+
+const gridToTsv = R.compose(R.join('\n'), R.map(R.join('\t')));
+
+class TableLog extends React.Component {
+ constructor(props) {
+ super(props);
+
+ this.getSheet = this.getSheet.bind(this);
+
+ this.onPrevSheetClick = this.onPrevSheetClick.bind(this);
+ this.onNextSheetClick = this.onNextSheetClick.bind(this);
+ this.onCopyLogClicked = this.onCopyLogClicked.bind(this);
+ this.onSaveLogClicked = this.onSaveLogClicked.bind(this);
+ this.onChangeSource = this.onChangeSource.bind(this);
+ }
+
+ onPrevSheetClick() {
+ const prevSheetIndex = R.max(0, this.props.sheetIndex - 1);
+ this.props.actions.changeActiveSheet(
+ this.props.tabId, // TODO: what's about debugger?
+ this.props.nodeId,
+ prevSheetIndex
+ );
+ }
+
+ onNextSheetClick() {
+ const nextSheetIndex = R.unless(R.equals(this.getSheetsAmount()), R.add(1))(
+ this.props.sheetIndex
+ );
+ this.props.actions.changeActiveSheet(
+ this.props.tabId,
+ this.props.nodeId,
+ nextSheetIndex
+ );
+ }
+
+ onCopyLogClicked() {
+ const copy = R.path(['navigator', 'clipboard', 'writeText'], window);
+ if (!copy) {
+ this.props.actions.addError(LOG_COPY_NOT_SUPPORTED);
+ return;
+ }
+
+ const tsv = gridToTsv(this.getSheet());
+ window.navigator.clipboard.writeText(tsv).then(
+ () => {
+ this.props.actions.addConfirmation(LOG_COPIED);
+ },
+ err => {
+ this.props.actions.addError(logCopyError(err));
+ }
+ );
+ }
+
+ onSaveLogClicked() {
+ const tsv = gridToTsv(this.getSheet());
+ const defaultFilename = `log-${this.props.nodeId}-${
+ this.props.sheetIndex
+ }.txt`;
+
+ try {
+ const data = new window.Blob([tsv], { type: 'text/plain' });
+ const file = window.URL.createObjectURL(data);
+
+ const link = document.createElement('a');
+ link.download = defaultFilename;
+ link.href = file;
+ link.click();
+
+ // We need to manually revoke the object URL to avoid memory leaks.
+ window.URL.revokeObjectURL(file);
+ } catch (err) {
+ this.props.actions.addError(logSaveError(err));
+ }
+ }
+
+ onChangeSource(event) {
+ const sourceNodeId = event.target.value;
+ this.props.actions.changeSource(this.props.tabId, sourceNodeId);
+ }
+
+ getSheet() {
+ return R.propOr([], this.props.sheetIndex, this.props.document);
+ }
+
+ getSheetsAmount() {
+ return this.props.document.length;
+ }
+
+ isEmptySheet() {
+ return this.getSheet().length === 0;
+ }
+
+ render() {
+ const hasNoSources = this.props.sources.length === 0;
+ const sheetAmount =
+ this.getSheetsAmount() === 0 ? 1 : this.getSheetsAmount();
+
+ return (
+
+
+
+
+
+
+
+
+ {this.props.sheetIndex + 1} / {sheetAmount}
+
+
+
+
+
+
+
+
+
+ {this.isEmptySheet() ? (
+ No data stored
+ ) : (
+ cell.value}
+ overflow={'nowrap'}
+ />
+ )}
+
+
+ );
+ }
+}
+
+TableLog.propTypes = {
+ // from parent
+ tabId: PropTypes.string.isRequired,
+ // connect
+ sources: PropTypes.arrayOf(PropTypes.string).isRequired,
+ document: PropTypes.array.isRequired,
+ nodeId: PropTypes.string.isRequired,
+ sheetIndex: PropTypes.number.isRequired,
+ actions: PropTypes.objectOf(PropTypes.func),
+};
+
+const mapStateToProps = (state, { nodeId }) =>
+ R.applySpec({
+ sources: DebuggerSelectors.getTableLogSources,
+ document: DebuggerSelectors.getTableLogsByNodeId(nodeId),
+ })(state);
+
+const mapDispatchToProps = dispatch => ({
+ actions: bindActionCreators(
+ {
+ changeActiveSheet: Actions.changeActiveSheet,
+ changeSource: Actions.changeTableLogSource,
+ addConfirmation,
+ },
+ dispatch
+ ),
+});
+
+export default connect(mapStateToProps, mapDispatchToProps)(TableLog);
diff --git a/packages/xod-client/src/editor/reducer.js b/packages/xod-client/src/editor/reducer.js
index 40c5edb5..e9f6dd31 100644
--- a/packages/xod-client/src/editor/reducer.js
+++ b/packages/xod-client/src/editor/reducer.js
@@ -11,6 +11,7 @@ import { DEFAULT_PANNING_OFFSET } from '../project/nodeLayout';
import { MAIN_PATCH_PATH } from '../project/constants';
import {
DEBUGGER_TAB_ID,
+ TABLE_LOG_TAB_ID,
FOCUS_AREAS,
SELECTION_ENTITY_TYPE,
TAB_TYPES,
@@ -130,34 +131,52 @@ const setPropsToTab = R.curry((id, props, state) =>
)(state)
);
-const addTabWithProps = R.curry((id, type, patchPath, state) => {
+const getTabNewIndex = state => {
const tabs = R.prop('tabs')(state);
const lastIndex = R.reduce(
(acc, tab) => R.pipe(R.prop('index'), R.max(acc))(tab),
-1,
R.values(tabs)
);
- const newIndex = R.inc(lastIndex);
+ return R.inc(lastIndex);
+};
- return setPropsToTab(
+const addTabWithProps = R.curry((id, type, patchPath, state) =>
+ setPropsToTab(
id,
{
id,
patchPath,
- index: newIndex,
+ index: getTabNewIndex(state),
type,
offset: DEFAULT_PANNING_OFFSET,
editedAttachment: null,
},
state
- );
-});
+ )
+);
const addPatchTab = R.curry((newId, patchPath, state) => {
if (!patchPath) return state;
return addTabWithProps(newId, TAB_TYPES.PATCH, patchPath, state);
});
+const openTableLogTab = R.curry((nodeId, activeSheetIndex, state) =>
+ setPropsToTab(
+ TABLE_LOG_TAB_ID,
+ R.unless(
+ () => isTabOpened(TABLE_LOG_TAB_ID, state),
+ R.merge(R.__, { index: getTabNewIndex(state) })
+ )({
+ id: TABLE_LOG_TAB_ID,
+ type: TAB_TYPES.TABLE_LOG,
+ nodeId,
+ activeSheetIndex,
+ }),
+ state
+ )
+);
+
const applyTabSort = (tab, payload) => {
if (R.not(R.has(tab.id, payload))) {
return tab;
@@ -711,6 +730,20 @@ const editorReducer = (state = initialState, action) => {
R.lensProp('pointingPopups'),
R.assoc('colorPickerWidget', null)
)(state);
+ case EAT.OPEN_TABLE_LOG_TAB:
+ return R.compose(
+ R.assoc('currentTabId', TABLE_LOG_TAB_ID),
+ openTableLogTab(action.payload.nodeId, action.payload.activeSheetIndex)
+ )(state);
+ case EAT.CHANGE_TABLE_LOG_SHEET:
+ return setPropsToTab(
+ action.payload.tabId,
+ {
+ nodeId: action.payload.nodeId,
+ activeSheetIndex: action.payload.newSheetIndex,
+ },
+ state
+ );
default:
return state;
diff --git a/packages/xod-client/src/editor/selectors.js b/packages/xod-client/src/editor/selectors.js
index 3a6d7cf3..6934981f 100644
--- a/packages/xod-client/src/editor/selectors.js
+++ b/packages/xod-client/src/editor/selectors.js
@@ -1,7 +1,7 @@
import * as R from 'ramda';
import { Maybe } from 'ramda-fantasy';
import { createSelector } from 'reselect';
-import { mapIndexed, foldMaybe } from 'xod-func-tools';
+import { mapIndexed, foldMaybe, maybeProp } from 'xod-func-tools';
import * as XP from 'xod-project';
import {
@@ -32,37 +32,49 @@ export const getCurrentTabId = R.pipe(getEditor, R.prop('currentTabId'), Maybe);
export const getCurrentTab = createSelector(
[getCurrentTabId, getTabs],
- (maybeTabId, tabs) => maybeTabId.chain(R.compose(Maybe, R.prop(R.__, tabs)))
+ (maybeTabId, tabs) => R.chain(maybeProp(R.__, tabs))(maybeTabId)
);
export const getCurrentPatchPath = createSelector(
getCurrentTab,
- R.map(R.prop('patchPath'))
+ R.chain(maybeProp('patchPath'))
);
export const getCurrentPatchOffset = createSelector(
getCurrentTab,
- foldMaybe(DEFAULT_PANNING_OFFSET, R.prop('offset'))
+ foldMaybe(DEFAULT_PANNING_OFFSET, R.propOr(DEFAULT_PANNING_OFFSET, 'offset'))
);
+const isTabTypeEq = R.curry((expected, tab) => tab.type === expected);
+
+const setTabLabel = R.assoc('label');
+
// :: State -> EditorTabs
export const getPreparedTabs = createSelector(
[getCurrentTabId, getTabs],
(maybeCurrentTabId, tabs) => {
const currentTabId = foldMaybe(null, R.identity, maybeCurrentTabId);
- return R.map(tab => {
- const patchPath = tab.patchPath;
-
- const label =
- tab.type === TAB_TYPES.DEBUGGER
- ? 'Debugger'
- : XP.getBaseName(patchPath);
-
- return R.merge(tab, {
- label,
- isActive: currentTabId === tab.id,
- });
- }, tabs);
+ return R.map(
+ R.compose(
+ tab => R.assoc('isActive', currentTabId === tab.id, tab),
+ R.cond([
+ [isTabTypeEq(TAB_TYPES.TABLE_LOG), setTabLabel('Table Logs')],
+ [isTabTypeEq(TAB_TYPES.DEBUGGER), setTabLabel('Debugger')],
+ [
+ isTabTypeEq(TAB_TYPES.PATCH),
+ tab =>
+ R.compose(
+ setTabLabel(R.__, tab),
+ XP.getBaseName,
+ R.prop('patchPath')
+ )(tab),
+ ],
+ // It should not be possible:
+ [R.T, setTabLabel('Unknown Tab Type')],
+ ])
+ ),
+ tabs
+ );
}
);