PromucFlow_constructor/app/client/src/widgets/TabsWidget.tsx
Nikhil Nandagopal 0b22fc67b3
Updated sentry sdk (#461)
Integrated react router for better performance reporting
Added Sentry Profiler for editor, appviewer and widgets

Co-authored-by: Nikhil Nandagopal <nikhil@appsmith.com>
2020-08-28 22:53:07 +05:30

222 lines
6.4 KiB
TypeScript

import React from "react";
import TabsComponent from "components/designSystems/appsmith/TabsComponent";
import { WidgetType, WidgetTypes } from "constants/WidgetConstants";
import BaseWidget, { WidgetProps, WidgetState } from "./BaseWidget";
import WidgetFactory, { TriggerPropertiesMap } from "utils/WidgetFactory";
import { generateReactKey } from "utils/generators";
import { WidgetPropertyValidationType } from "utils/ValidationFactory";
import { VALIDATION_TYPES } from "constants/WidgetValidation";
import _ from "lodash";
import { EventType } from "constants/ActionConstants";
import { WidgetOperations } from "widgets/BaseWidget";
import * as Sentry from "@sentry/react";
class TabsWidget extends BaseWidget<
TabsWidgetProps<TabContainerWidgetProps>,
WidgetState
> {
static getPropertyValidationMap(): WidgetPropertyValidationType {
return {
tabs: VALIDATION_TYPES.TABS_DATA,
defaultTab: VALIDATION_TYPES.SELECTED_TAB,
};
}
onTabChange = (tabId: string) => {
this.updateWidgetMetaProperty("selectedTabId", tabId);
if (this.props.onTabSelected) {
super.executeAction({
dynamicString: this.props.onTabSelected,
event: {
type: EventType.ON_TAB_CHANGE,
},
});
}
};
static getDerivedPropertiesMap() {
return {
selectedTab: `{{_.find(this.tabs, { id: this.selectedTabId }).label}}`,
};
}
static getDefaultPropertiesMap(): Record<string, string> {
return {
selectedTab: "defaultTab",
};
}
static getTriggerPropertyMap(): TriggerPropertiesMap {
return {
onTabSelected: true,
};
}
getPageView() {
return (
<TabsComponent {...this.props} onTabChange={this.onTabChange}>
{this.renderComponent()}
</TabsComponent>
);
}
renderComponent = () => {
const selectedTabId = this.props.selectedTabId;
const childWidgetData: TabContainerWidgetProps = this.props.children.filter(
item => {
return selectedTabId === item.tabId;
},
)[0];
if (!childWidgetData) {
return null;
}
childWidgetData.shouldScrollContents = false;
childWidgetData.canExtend = this.props.shouldScrollContents;
const { componentWidth, componentHeight } = this.getComponentDimensions();
childWidgetData.rightColumn = componentWidth;
childWidgetData.isVisible = this.props.isVisible;
childWidgetData.bottomRow = this.props.shouldScrollContents
? childWidgetData.bottomRow
: componentHeight - 1;
childWidgetData.parentId = this.props.widgetId;
childWidgetData.minHeight = componentHeight;
return WidgetFactory.createWidget(childWidgetData, this.props.renderMode);
};
getWidgetType(): WidgetType {
return "TABS_WIDGET";
}
addTabContainer = () => {
let tabId = "";
const childrenTabIds: string[] = this.props.children.map(children => {
return children.tabId;
});
for (let index = 0; index < this.props.tabs.length; index++) {
const tab = this.props.tabs[index];
if (!childrenTabIds.includes(tab.id)) {
tabId = tab.id;
}
}
const columns =
(this.props.rightColumn - this.props.leftColumn) *
this.props.parentColumnSpace;
const rows =
(this.props.bottomRow - this.props.topRow - 1) *
this.props.parentRowSpace;
const config = {
type: WidgetTypes.CANVAS_WIDGET,
columns: columns,
rows: rows,
parentRowSpace: 1,
parentColumnSpace: 1,
leftColumn: 0,
topRow: 1,
newWidgetId: generateReactKey(),
widgetId: this.props.widgetId,
props: {
tabId: tabId,
containerStyle: "none",
canExtend: false,
detachFromLayout: true,
children: [],
},
};
this.updateWidget(WidgetOperations.ADD_CHILD, this.props.widgetId, config);
};
removeTabContainer = () => {
let removedContainerWidgetId = "";
let removedTabId = "";
const tabIds: string[] = this.props.tabs.map(tab => {
return tab.id;
});
for (let index = 0; index < this.props.children.length; index++) {
const children = this.props.children[index];
if (!tabIds.includes(children.tabId)) {
removedContainerWidgetId = children.widgetId;
removedTabId = children.tabId;
}
}
/* Selecting first tab as default tab when no tab is selected */
if (
this.props.tabs.length > 1 &&
removedTabId === this.props.selectedTabId
) {
setTimeout(() => {
this.updateWidgetProperty(
"defaultTab",
this.props.tabs.filter(tab => tab.id !== removedTabId)[0].label,
);
}, 0);
}
this.updateWidget(WidgetOperations.DELETE, removedContainerWidgetId, {
parentId: this.props.widgetId,
});
};
componentDidUpdate(prevProps: TabsWidgetProps<TabContainerWidgetProps>) {
super.componentDidUpdate(prevProps);
if (this.props.tabs) {
if (
this.props.tabs.length !== prevProps.tabs.length &&
this.props.children.length !== this.props.tabs.length
) {
//adding container widget for the new tab
if (this.props.tabs.length > this.props.children.length) {
this.addTabContainer();
}
//removing container widget for the removed tab
else {
this.removeTabContainer();
}
}
}
if (this.props.defaultTab) {
if (this.props.defaultTab !== prevProps.defaultTab) {
const selectedTab = _.find(this.props.tabs, {
label: this.props.defaultTab,
});
const selectedTabId = selectedTab ? selectedTab.id : undefined;
this.updateWidgetMetaProperty("selectedTabId", selectedTabId);
}
}
}
componentDidMount() {
if (this.props.defaultTab) {
const selectedTab = _.find(this.props.tabs, {
label: this.props.defaultTab,
});
const selectedTabId = selectedTab ? selectedTab.id : undefined;
this.updateWidgetMetaProperty("selectedTabId", selectedTabId);
}
}
}
export interface TabContainerWidgetProps extends WidgetProps {
tabId: string;
}
export interface TabsWidgetProps<T extends TabContainerWidgetProps>
extends WidgetProps {
isVisible?: boolean;
shouldScrollContents: boolean;
tabs: Array<{
id: string;
label: string;
}>;
shouldShowTabs: boolean;
children: T[];
snapColumns?: number;
onTabSelected?: string;
snapRows?: number;
defaultTab: string;
selectedTabId: string;
}
export default TabsWidget;
export const ProfiledTabsWidget = Sentry.withProfiler(TabsWidget);