[MM-36431] Logic to support multiple configurable tabs per server (#1655)
* Updated config, added types and classes for messaging tab * Working app with tabs and servers * Remainder of logic * Make base tab abstract class * Account for new app case * Merge'd * PR feedback
This commit is contained in:
@@ -8,7 +8,9 @@ import {DropResult} from 'react-beautiful-dnd';
|
||||
import DotsVerticalIcon from 'mdi-react/DotsVerticalIcon';
|
||||
import {IpcRendererEvent} from 'electron/renderer';
|
||||
|
||||
import {Team} from 'types/config';
|
||||
import {TeamWithTabs} from 'types/config';
|
||||
|
||||
import {getTabViewName} from 'common/tabs/TabView';
|
||||
|
||||
import {
|
||||
FOCUS_BROWSERVIEW,
|
||||
@@ -18,8 +20,6 @@ import {
|
||||
LOAD_RETRY,
|
||||
LOAD_SUCCESS,
|
||||
LOAD_FAILED,
|
||||
SHOW_NEW_SERVER_MODAL,
|
||||
SWITCH_SERVER,
|
||||
WINDOW_CLOSE,
|
||||
WINDOW_MINIMIZE,
|
||||
WINDOW_RESTORE,
|
||||
@@ -28,16 +28,14 @@ import {
|
||||
PLAY_SOUND,
|
||||
MODAL_OPEN,
|
||||
MODAL_CLOSE,
|
||||
SET_SERVER_KEY,
|
||||
SET_ACTIVE_VIEW,
|
||||
UPDATE_MENTIONS,
|
||||
TOGGLE_BACK_BUTTON,
|
||||
SELECT_NEXT_TAB,
|
||||
SELECT_PREVIOUS_TAB,
|
||||
ADD_SERVER,
|
||||
FOCUS_THREE_DOT_MENU,
|
||||
GET_FULL_SCREEN_STATUS,
|
||||
CLOSE_TEAMS_DROPDOWN,
|
||||
OPEN_TEAMS_DROPDOWN,
|
||||
SWITCH_TAB,
|
||||
} from 'common/communication';
|
||||
|
||||
import restoreButton from '../../assets/titlebar/chrome-restore.svg';
|
||||
@@ -61,22 +59,21 @@ enum Status {
|
||||
}
|
||||
|
||||
type Props = {
|
||||
teams: Team[];
|
||||
showAddServerButton: boolean;
|
||||
moveTabs: (originalOrder: number, newOrder: number) => number | undefined;
|
||||
teams: TeamWithTabs[];
|
||||
moveTabs: (teamName: string, originalOrder: number, newOrder: number) => number | undefined;
|
||||
openMenu: () => void;
|
||||
darkMode: boolean;
|
||||
appName: string;
|
||||
};
|
||||
|
||||
type State = {
|
||||
key: number;
|
||||
activeServerName?: string;
|
||||
activeTabName?: string;
|
||||
sessionsExpired: Record<string, boolean>;
|
||||
unreadCounts: Record<string, number>;
|
||||
mentionCounts: Record<string, number>;
|
||||
targetURL: string;
|
||||
maximized: boolean;
|
||||
tabStatus: Map<string, TabStatus>;
|
||||
tabViewStatus: Map<string, TabViewStatus>;
|
||||
darkMode: boolean;
|
||||
modalOpen?: boolean;
|
||||
fullScreen?: boolean;
|
||||
@@ -84,7 +81,7 @@ type State = {
|
||||
isMenuOpen: boolean;
|
||||
};
|
||||
|
||||
type TabStatus = {
|
||||
type TabViewStatus = {
|
||||
status: Status;
|
||||
extra?: {
|
||||
url: string;
|
||||
@@ -102,40 +99,39 @@ export default class MainPage extends React.PureComponent<Props, State> {
|
||||
this.topBar = React.createRef();
|
||||
this.threeDotMenu = React.createRef();
|
||||
|
||||
const firstServer = this.props.teams.find((team) => team.order === 0);
|
||||
const firstTab = firstServer?.tabs.find((tab) => tab.order === (firstServer.lastActiveTab || 0)) || firstServer?.tabs[0];
|
||||
|
||||
this.state = {
|
||||
key: this.props.teams.length ? this.props.teams.findIndex((team) => team.order === 0) : 0,
|
||||
activeServerName: firstServer?.name,
|
||||
activeTabName: firstTab?.name,
|
||||
sessionsExpired: {},
|
||||
unreadCounts: {},
|
||||
mentionCounts: {},
|
||||
targetURL: '',
|
||||
maximized: false,
|
||||
tabStatus: new Map(this.props.teams.map((server) => [server.name, {status: Status.LOADING}])),
|
||||
tabViewStatus: new Map(this.props.teams.map((team) => team.tabs.map((tab) => getTabViewName(team.name, tab.name))).flat().map((tabViewName) => [tabViewName, {status: Status.LOADING}])),
|
||||
darkMode: this.props.darkMode,
|
||||
isMenuOpen: false,
|
||||
};
|
||||
}
|
||||
|
||||
getTabStatus() {
|
||||
if (this.props.teams.length) {
|
||||
const tab = this.props.teams[this.state.key];
|
||||
if (tab) {
|
||||
const tabname = tab.name;
|
||||
return this.state.tabStatus.get(tabname);
|
||||
}
|
||||
getTabViewStatus() {
|
||||
if (!this.state.activeServerName || !this.state.activeTabName) {
|
||||
return undefined;
|
||||
}
|
||||
return {status: Status.NOSERVERS};
|
||||
return this.state.tabViewStatus.get(getTabViewName(this.state.activeServerName, this.state.activeTabName)) ?? {status: Status.NOSERVERS};
|
||||
}
|
||||
|
||||
updateTabStatus(server: string, newStatusValue: TabStatus) {
|
||||
const status = new Map(this.state.tabStatus);
|
||||
status.set(server, newStatusValue);
|
||||
this.setState({tabStatus: status});
|
||||
updateTabStatus(tabViewName: string, newStatusValue: TabViewStatus) {
|
||||
const status = new Map(this.state.tabViewStatus);
|
||||
status.set(tabViewName, newStatusValue);
|
||||
this.setState({tabViewStatus: status});
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
// set page on retry
|
||||
window.ipcRenderer.on(LOAD_RETRY, (_, server, retry, err, loadUrl) => {
|
||||
console.log(`${server}: failed to load ${err}, but retrying`);
|
||||
window.ipcRenderer.on(LOAD_RETRY, (_, viewName, retry, err, loadUrl) => {
|
||||
console.log(`${viewName}: failed to load ${err}, but retrying`);
|
||||
const statusValue = {
|
||||
status: Status.RETRY,
|
||||
extra: {
|
||||
@@ -144,15 +140,15 @@ export default class MainPage extends React.PureComponent<Props, State> {
|
||||
url: loadUrl,
|
||||
},
|
||||
};
|
||||
this.updateTabStatus(server, statusValue);
|
||||
this.updateTabStatus(viewName, statusValue);
|
||||
});
|
||||
|
||||
window.ipcRenderer.on(LOAD_SUCCESS, (_, server) => {
|
||||
this.updateTabStatus(server, {status: Status.DONE});
|
||||
window.ipcRenderer.on(LOAD_SUCCESS, (_, viewName) => {
|
||||
this.updateTabStatus(viewName, {status: Status.DONE});
|
||||
});
|
||||
|
||||
window.ipcRenderer.on(LOAD_FAILED, (_, server, err, loadUrl) => {
|
||||
console.log(`${server}: failed to load ${err}`);
|
||||
window.ipcRenderer.on(LOAD_FAILED, (_, viewName, err, loadUrl) => {
|
||||
console.log(`${viewName}: failed to load ${err}`);
|
||||
const statusValue = {
|
||||
status: Status.FAILED,
|
||||
extra: {
|
||||
@@ -160,7 +156,7 @@ export default class MainPage extends React.PureComponent<Props, State> {
|
||||
url: loadUrl,
|
||||
},
|
||||
};
|
||||
this.updateTabStatus(server, statusValue);
|
||||
this.updateTabStatus(viewName, statusValue);
|
||||
});
|
||||
|
||||
window.ipcRenderer.on(DARK_MODE_CHANGE, (_, darkMode) => {
|
||||
@@ -168,26 +164,8 @@ export default class MainPage extends React.PureComponent<Props, State> {
|
||||
});
|
||||
|
||||
// can't switch tabs sequentially for some reason...
|
||||
window.ipcRenderer.on(SET_SERVER_KEY, (event, key) => {
|
||||
const nextIndex = this.props.teams.findIndex((team) => team.order === key);
|
||||
this.handleSetServerKey(nextIndex);
|
||||
});
|
||||
window.ipcRenderer.on(SELECT_NEXT_TAB, () => {
|
||||
const currentOrder = this.props.teams[this.state.key].order;
|
||||
const nextOrder = ((currentOrder + 1) % this.props.teams.length);
|
||||
const nextIndex = this.props.teams.findIndex((team) => team.order === nextOrder);
|
||||
const team = this.props.teams[nextIndex];
|
||||
this.handleSelect(team.name, nextIndex);
|
||||
});
|
||||
|
||||
window.ipcRenderer.on(SELECT_PREVIOUS_TAB, () => {
|
||||
const currentOrder = this.props.teams[this.state.key].order;
|
||||
|
||||
// js modulo operator returns a negative number if result is negative, so we have to ensure it's positive
|
||||
const nextOrder = ((this.props.teams.length + (currentOrder - 1)) % this.props.teams.length);
|
||||
const nextIndex = this.props.teams.findIndex((team) => team.order === nextOrder);
|
||||
const team = this.props.teams[nextIndex];
|
||||
this.handleSelect(team.name, nextIndex);
|
||||
window.ipcRenderer.on(SET_ACTIVE_VIEW, (event, serverName, tabName) => {
|
||||
this.setState({activeServerName: serverName, activeTabName: tabName});
|
||||
});
|
||||
|
||||
window.ipcRenderer.on(MAXIMIZE_CHANGE, this.handleMaximizeState);
|
||||
@@ -197,10 +175,6 @@ export default class MainPage extends React.PureComponent<Props, State> {
|
||||
|
||||
window.ipcRenderer.invoke(GET_FULL_SCREEN_STATUS).then((fullScreenStatus) => this.handleFullScreenState(fullScreenStatus));
|
||||
|
||||
window.ipcRenderer.on(ADD_SERVER, () => {
|
||||
this.addServer();
|
||||
});
|
||||
|
||||
window.ipcRenderer.on(PLAY_SOUND, (_event, soundName) => {
|
||||
playSound(soundName);
|
||||
});
|
||||
@@ -217,18 +191,17 @@ export default class MainPage extends React.PureComponent<Props, State> {
|
||||
this.setState({showExtraBar});
|
||||
});
|
||||
|
||||
window.ipcRenderer.on(UPDATE_MENTIONS, (_event, team, mentions, unreads, isExpired) => {
|
||||
const key = this.props.teams.findIndex((server) => server.name === team);
|
||||
window.ipcRenderer.on(UPDATE_MENTIONS, (_event, view, mentions, unreads, isExpired) => {
|
||||
const {unreadCounts, mentionCounts, sessionsExpired} = this.state;
|
||||
|
||||
const newMentionCounts = {...mentionCounts};
|
||||
newMentionCounts[key] = mentions || 0;
|
||||
newMentionCounts[view] = mentions || 0;
|
||||
|
||||
const newUnreads = {...unreadCounts};
|
||||
newUnreads[key] = unreads || false;
|
||||
newUnreads[view] = unreads || false;
|
||||
|
||||
const expired = {...sessionsExpired};
|
||||
expired[key] = isExpired || false;
|
||||
expired[view] = isExpired || false;
|
||||
|
||||
this.setState({unreadCounts: newUnreads, mentionCounts: newMentionCounts, sessionsExpired: expired});
|
||||
});
|
||||
@@ -258,14 +231,8 @@ export default class MainPage extends React.PureComponent<Props, State> {
|
||||
this.setState({fullScreen: isFullScreen});
|
||||
}
|
||||
|
||||
handleSetServerKey = (key: number) => {
|
||||
const newKey = ((this.props.teams.length + key) % this.props.teams.length) || 0;
|
||||
this.setState({key: newKey});
|
||||
}
|
||||
|
||||
handleSelect = (name: string, key: number) => {
|
||||
window.ipcRenderer.send(SWITCH_SERVER, name);
|
||||
this.handleSetServerKey(key);
|
||||
handleSelectTab = (name: string) => {
|
||||
window.ipcRenderer.send(SWITCH_TAB, this.state.activeServerName, name);
|
||||
}
|
||||
|
||||
handleDragAndDrop = async (dropResult: DropResult) => {
|
||||
@@ -274,12 +241,20 @@ export default class MainPage extends React.PureComponent<Props, State> {
|
||||
if (addedIndex === undefined || removedIndex === addedIndex) {
|
||||
return;
|
||||
}
|
||||
const teamIndex = this.props.moveTabs(removedIndex, addedIndex < this.props.teams.length ? addedIndex : this.props.teams.length - 1);
|
||||
if (!this.state.activeServerName) {
|
||||
return;
|
||||
}
|
||||
const currentTabs = this.props.teams.find((team) => team.name === this.state.activeServerName)?.tabs;
|
||||
if (!currentTabs) {
|
||||
// TODO: figure out something here
|
||||
return;
|
||||
}
|
||||
const teamIndex = this.props.moveTabs(this.state.activeServerName, removedIndex, addedIndex < currentTabs.length ? addedIndex : currentTabs.length - 1);
|
||||
if (!teamIndex) {
|
||||
return;
|
||||
}
|
||||
const name = this.props.teams[teamIndex].name;
|
||||
this.handleSelect(name, teamIndex);
|
||||
const name = currentTabs[teamIndex].name;
|
||||
this.handleSelectTab(name);
|
||||
}
|
||||
|
||||
handleClose = (e: React.MouseEvent<HTMLDivElement>) => {
|
||||
@@ -312,17 +287,18 @@ export default class MainPage extends React.PureComponent<Props, State> {
|
||||
window.ipcRenderer.send(DOUBLE_CLICK_ON_WINDOW);
|
||||
}
|
||||
|
||||
addServer = () => {
|
||||
window.ipcRenderer.send(SHOW_NEW_SERVER_MODAL);
|
||||
}
|
||||
|
||||
focusOnWebView = () => {
|
||||
window.ipcRenderer.send(FOCUS_BROWSERVIEW);
|
||||
window.ipcRenderer.send(CLOSE_TEAMS_DROPDOWN);
|
||||
}
|
||||
|
||||
render() {
|
||||
if (!this.props.teams.length) {
|
||||
if (!this.state.activeServerName || !this.state.activeTabName) {
|
||||
return null;
|
||||
}
|
||||
const currentTabs = this.props.teams.find((team) => team.name === this.state.activeServerName)?.tabs;
|
||||
if (!currentTabs) {
|
||||
// TODO: figure out something here
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -330,14 +306,13 @@ export default class MainPage extends React.PureComponent<Props, State> {
|
||||
<TabBar
|
||||
id='tabBar'
|
||||
isDarkMode={this.state.darkMode}
|
||||
teams={this.props.teams}
|
||||
tabs={currentTabs}
|
||||
sessionsExpired={this.state.sessionsExpired}
|
||||
unreadCounts={this.state.unreadCounts}
|
||||
mentionCounts={this.state.mentionCounts}
|
||||
activeKey={this.state.key}
|
||||
onSelect={this.handleSelect}
|
||||
onAddServer={this.addServer}
|
||||
showAddServerButton={this.props.showAddServerButton}
|
||||
activeServerName={this.state.activeServerName}
|
||||
activeTabName={this.state.activeTabName}
|
||||
onSelect={this.handleSelectTab}
|
||||
onDrop={this.handleDragAndDrop}
|
||||
tabsDisabled={this.state.modalOpen}
|
||||
/>
|
||||
@@ -424,7 +399,7 @@ export default class MainPage extends React.PureComponent<Props, State> {
|
||||
<DotsVerticalIcon/>
|
||||
</button>
|
||||
<TeamDropdownButton
|
||||
activeServerName={this.props.teams[this.state.key].name}
|
||||
activeServerName={this.state.activeServerName}
|
||||
totalMentionCount={totalMentionCount}
|
||||
hasUnreads={totalUnreadCount > 0}
|
||||
isMenuOpen={this.state.isMenuOpen}
|
||||
@@ -439,11 +414,10 @@ export default class MainPage extends React.PureComponent<Props, State> {
|
||||
|
||||
const views = () => {
|
||||
let component;
|
||||
const tabStatus = this.getTabStatus();
|
||||
const tabStatus = this.getTabViewStatus();
|
||||
if (!tabStatus) {
|
||||
const tab = this.props.teams[this.state.key];
|
||||
if (tab) {
|
||||
console.error(`Not tabStatus for ${this.props.teams[this.state.key].name}`);
|
||||
if (this.state.activeTabName) {
|
||||
console.error(`Not tabStatus for ${this.state.activeTabName}`);
|
||||
} else {
|
||||
console.error('No tab status, tab doesn\'t exist anymore');
|
||||
}
|
||||
@@ -463,7 +437,7 @@ export default class MainPage extends React.PureComponent<Props, State> {
|
||||
case Status.FAILED:
|
||||
component = (
|
||||
<ErrorView
|
||||
id={this.state.key + '-fail'}
|
||||
id={this.state.activeTabName + '-fail'}
|
||||
errorInfo={tabStatus.extra?.error}
|
||||
url={tabStatus.extra ? tabStatus.extra.url : ''}
|
||||
active={true}
|
||||
|
@@ -15,6 +15,7 @@ import {CombinedConfig, LocalConfiguration, Team} from 'types/config';
|
||||
import {DeepPartial} from 'types/utils';
|
||||
|
||||
import {GET_LOCAL_CONFIGURATION, UPDATE_CONFIGURATION, DOUBLE_CLICK_ON_WINDOW, GET_DOWNLOAD_LOCATION, SWITCH_SERVER, ADD_SERVER, RELOAD_CONFIGURATION} from 'common/communication';
|
||||
import {getDefaultTeamWithTabsFromTeam} from 'common/tabs/TabView';
|
||||
|
||||
import TeamList from './TeamList';
|
||||
import AutoSaveIndicator, {SavingState} from './AutoSaveIndicator';
|
||||
@@ -337,7 +338,7 @@ export default class SettingsPage extends React.PureComponent<Record<string, nev
|
||||
|
||||
addServer = (team: Team) => {
|
||||
const teams = this.state.teams || [];
|
||||
teams.push(team);
|
||||
teams.push(getDefaultTeamWithTabsFromTeam(team));
|
||||
window.timers.setImmediate(this.saveSetting, CONFIG_TYPE_SERVERS, {key: 'teams', data: teams});
|
||||
this.setState({
|
||||
teams,
|
||||
|
@@ -5,32 +5,26 @@
|
||||
import React from 'react';
|
||||
import {Nav, NavItem, NavLink} from 'react-bootstrap';
|
||||
import {DragDropContext, Draggable, DraggingStyle, Droppable, DropResult, NotDraggingStyle} from 'react-beautiful-dnd';
|
||||
import PlusIcon from 'mdi-react/PlusIcon';
|
||||
import classNames from 'classnames';
|
||||
|
||||
import {Team} from 'types/config';
|
||||
import {Tab} from 'types/config';
|
||||
|
||||
import {GET_CONFIGURATION} from 'common/communication';
|
||||
import {getTabViewName} from 'common/tabs/TabView';
|
||||
|
||||
type Props = {
|
||||
activeKey: number;
|
||||
activeTabName: string;
|
||||
activeServerName: string;
|
||||
id: string;
|
||||
isDarkMode: boolean;
|
||||
onSelect: (name: string, index: number) => void;
|
||||
teams: Team[];
|
||||
tabs: Tab[];
|
||||
sessionsExpired: Record<string, boolean>;
|
||||
unreadCounts: Record<string, number>;
|
||||
mentionCounts: Record<string, number>;
|
||||
showAddServerButton: boolean;
|
||||
onAddServer: () => void;
|
||||
onDrop: (result: DropResult) => void;
|
||||
tabsDisabled?: boolean;
|
||||
};
|
||||
|
||||
type State = {
|
||||
hasGPOTeams: boolean;
|
||||
};
|
||||
|
||||
function getStyle(style?: DraggingStyle | NotDraggingStyle) {
|
||||
if (style?.transform) {
|
||||
const axisLockX = `${style.transform.slice(0, style.transform.indexOf(','))}, 0px)`;
|
||||
@@ -42,31 +36,19 @@ function getStyle(style?: DraggingStyle | NotDraggingStyle) {
|
||||
return style;
|
||||
}
|
||||
|
||||
export default class TabBar extends React.PureComponent<Props, State> { // need "this"
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
hasGPOTeams: false,
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
window.ipcRenderer.invoke(GET_CONFIGURATION).then((config) => {
|
||||
this.setState({hasGPOTeams: config.registryTeams && config.registryTeams.length > 0});
|
||||
});
|
||||
}
|
||||
|
||||
export default class TabBar extends React.PureComponent<Props> {
|
||||
render() {
|
||||
const orderedTabs = this.props.teams.concat().sort((a, b) => a.order - b.order);
|
||||
const tabs = orderedTabs.map((team, orderedIndex) => {
|
||||
const index = this.props.teams.indexOf(team);
|
||||
const orderedTabs = this.props.tabs.concat().sort((a, b) => a.order - b.order);
|
||||
const tabs = orderedTabs.map((tab, orderedIndex) => {
|
||||
const index = this.props.tabs.indexOf(tab);
|
||||
const tabName = getTabViewName(this.props.activeServerName, tab.name);
|
||||
|
||||
const sessionExpired = this.props.sessionsExpired[index];
|
||||
const hasUnreads = this.props.unreadCounts[index];
|
||||
const sessionExpired = this.props.sessionsExpired[tabName];
|
||||
const hasUnreads = this.props.unreadCounts[tabName];
|
||||
|
||||
let mentionCount = 0;
|
||||
if (this.props.mentionCounts[index] > 0) {
|
||||
mentionCount = this.props.mentionCounts[index];
|
||||
if (this.props.mentionCounts[tabName] > 0) {
|
||||
mentionCount = this.props.mentionCounts[tabName];
|
||||
}
|
||||
|
||||
let badgeDiv: React.ReactNode;
|
||||
@@ -98,9 +80,9 @@ export default class TabBar extends React.PureComponent<Props, State> { // need
|
||||
as='li'
|
||||
id={`teamTabItem${index}`}
|
||||
draggable={false}
|
||||
title={team.name}
|
||||
title={tab.name}
|
||||
className={classNames('teamTabItem', {
|
||||
active: this.props.activeKey === index,
|
||||
active: this.props.activeTabName === tab.name,
|
||||
dragging: snapshot.isDragging,
|
||||
})}
|
||||
{...provided.draggableProps}
|
||||
@@ -110,15 +92,15 @@ export default class TabBar extends React.PureComponent<Props, State> { // need
|
||||
<NavLink
|
||||
eventKey={index}
|
||||
draggable={false}
|
||||
active={this.props.activeKey === index}
|
||||
active={this.props.activeTabName === tab.name}
|
||||
disabled={this.props.tabsDisabled}
|
||||
onSelect={() => {
|
||||
this.props.onSelect(team.name, index);
|
||||
this.props.onSelect(tab.name, index);
|
||||
}}
|
||||
>
|
||||
<div className='TabBar-tabSeperator'>
|
||||
<span>
|
||||
{team.name}
|
||||
{tab.name}
|
||||
</span>
|
||||
{ badgeDiv }
|
||||
</div>
|
||||
@@ -128,49 +110,11 @@ export default class TabBar extends React.PureComponent<Props, State> { // need
|
||||
</Draggable>
|
||||
);
|
||||
});
|
||||
if (this.props.showAddServerButton === true) {
|
||||
tabs.push(
|
||||
<Draggable
|
||||
draggableId={'TabBar-addServerButton'}
|
||||
index={this.props.teams.length}
|
||||
isDragDisabled={true}
|
||||
>
|
||||
{(provided) => (
|
||||
<NavItem
|
||||
ref={provided.innerRef}
|
||||
as='li'
|
||||
className='TabBar-addServerButton'
|
||||
key='addServerButton'
|
||||
id='addServerButton'
|
||||
draggable={false}
|
||||
title='Add new server'
|
||||
{...provided.draggableProps}
|
||||
{...provided.dragHandleProps}
|
||||
>
|
||||
<NavLink
|
||||
eventKey='addServerButton'
|
||||
draggable={false}
|
||||
disabled={this.props.tabsDisabled}
|
||||
onSelect={() => {
|
||||
this.props.onAddServer();
|
||||
}}
|
||||
>
|
||||
<div className='TabBar-tabSeperator'>
|
||||
<PlusIcon size={20}/>
|
||||
</div>
|
||||
</NavLink>
|
||||
</NavItem>
|
||||
)}
|
||||
</Draggable>,
|
||||
);
|
||||
}
|
||||
|
||||
// TODO: Replace with products
|
||||
tabs.length = 0;
|
||||
return (
|
||||
<DragDropContext onDragEnd={this.props.onDrop}>
|
||||
<Droppable
|
||||
isDropDisabled={this.state.hasGPOTeams || this.props.tabsDisabled}
|
||||
isDropDisabled={this.props.tabsDisabled}
|
||||
droppableId='tabBar'
|
||||
direction='horizontal'
|
||||
>
|
||||
|
Reference in New Issue
Block a user