diff --git a/app/client/packages/design-system/theming/src/color/src/LightModeTheme.ts b/app/client/packages/design-system/theming/src/color/src/LightModeTheme.ts index 35cb8ff5e6d..0d2f336b6c0 100644 --- a/app/client/packages/design-system/theming/src/color/src/LightModeTheme.ts +++ b/app/client/packages/design-system/theming/src/color/src/LightModeTheme.ts @@ -67,7 +67,7 @@ export class LightModeTheme implements ColorModeTheme { bgNegative: this.bgNegative.to("sRGB").toString(), bgNegativeHover: this.bgNegativeHover.to("sRGB").toString(), bgNegativeActive: this.bgNegativeActive.to("sRGB").toString(), - bgNegativeSubtle: this.bgNegativeActive.to("sRGB").toString(), + bgNegativeSubtle: this.bgNegativeSubtle.to("sRGB").toString(), bgNegativeSubtleHover: this.bgNegativeSubtleHover.to("sRGB").toString(), bgNegativeSubtleActive: this.bgNegativeSubtleActive.to("sRGB").toString(), bgWarning: this.bgWarning.to("sRGB").toString(), diff --git a/app/client/packages/design-system/theming/src/color/tests/LightModeTheme.test.ts b/app/client/packages/design-system/theming/src/color/tests/LightModeTheme.test.ts index 565cb6f6e70..1d8c702cabc 100644 --- a/app/client/packages/design-system/theming/src/color/tests/LightModeTheme.test.ts +++ b/app/client/packages/design-system/theming/src/color/tests/LightModeTheme.test.ts @@ -476,7 +476,7 @@ describe("bgNegativeSubtle color", () => { const { bgNegativeSubtle } = new LightModeTheme( "oklch(0.55 0.22 27)", ).getColors(); - expect(bgNegativeSubtle).toEqual("rgb(80.074% 0% 19.209%)"); + expect(bgNegativeSubtle).toEqual("rgb(100% 89.936% 89.52%)"); }); }); diff --git a/app/client/packages/design-system/widgets/src/components/Link/index.ts b/app/client/packages/design-system/widgets/src/components/Link/index.ts new file mode 100644 index 00000000000..3bd16e178a0 --- /dev/null +++ b/app/client/packages/design-system/widgets/src/components/Link/index.ts @@ -0,0 +1 @@ +export * from "./src"; diff --git a/app/client/packages/design-system/widgets/src/components/Link/src/Link.tsx b/app/client/packages/design-system/widgets/src/components/Link/src/Link.tsx new file mode 100644 index 00000000000..88e6e128b5f --- /dev/null +++ b/app/client/packages/design-system/widgets/src/components/Link/src/Link.tsx @@ -0,0 +1,17 @@ +import React from "react"; + +import { Text } from "../../Text"; +import type { LinkProps } from "./types"; +import styles from "./styles.module.css"; + +export function Link(props: LinkProps) { + const { children, href, rel, target, ...rest } = props; + + return ( + + + {children} + + + ); +} diff --git a/app/client/packages/design-system/widgets/src/components/Link/src/index.ts b/app/client/packages/design-system/widgets/src/components/Link/src/index.ts new file mode 100644 index 00000000000..3b40a46d8b6 --- /dev/null +++ b/app/client/packages/design-system/widgets/src/components/Link/src/index.ts @@ -0,0 +1 @@ +export * from "./Link"; diff --git a/app/client/packages/design-system/widgets/src/components/Link/src/styles.module.css b/app/client/packages/design-system/widgets/src/components/Link/src/styles.module.css new file mode 100644 index 00000000000..8ca5a569c23 --- /dev/null +++ b/app/client/packages/design-system/widgets/src/components/Link/src/styles.module.css @@ -0,0 +1,10 @@ +.link { + text-decoration: underline; + text-decoration-color: currentColor; + text-underline-offset: 2px; + + &:hover { + color: currentColor; + text-decoration-color: currentColor; + } +} diff --git a/app/client/packages/design-system/widgets/src/components/Link/src/types.ts b/app/client/packages/design-system/widgets/src/components/Link/src/types.ts new file mode 100644 index 00000000000..8da1bbd6bb4 --- /dev/null +++ b/app/client/packages/design-system/widgets/src/components/Link/src/types.ts @@ -0,0 +1,9 @@ +import type { ComponentProps } from "react"; + +import type { TextProps } from "../../Text"; + +export interface LinkProps extends TextProps { + href?: string; + target?: ComponentProps<"a">["target"]; + rel?: string; +} diff --git a/app/client/packages/design-system/widgets/src/components/Text/src/Text.tsx b/app/client/packages/design-system/widgets/src/components/Text/src/Text.tsx index c549bd73bb5..1ed09327a17 100644 --- a/app/client/packages/design-system/widgets/src/components/Text/src/Text.tsx +++ b/app/client/packages/design-system/widgets/src/components/Text/src/Text.tsx @@ -19,7 +19,7 @@ const _Text = (props: TextProps, ref: Ref) => { isItalic = false, lineClamp, style, - textAlign = "left", + textAlign = "start", title, variant = "body", ...rest diff --git a/app/client/packages/design-system/widgets/src/components/Text/src/index.ts b/app/client/packages/design-system/widgets/src/components/Text/src/index.ts index 7afe56f372c..041a2819179 100644 --- a/app/client/packages/design-system/widgets/src/components/Text/src/index.ts +++ b/app/client/packages/design-system/widgets/src/components/Text/src/index.ts @@ -1 +1,2 @@ export { Text } from "./Text"; +export type { TextProps } from "./types"; diff --git a/app/client/packages/design-system/widgets/src/components/Text/src/types.ts b/app/client/packages/design-system/widgets/src/components/Text/src/types.ts index 5bc70beeecb..125109197b5 100644 --- a/app/client/packages/design-system/widgets/src/components/Text/src/types.ts +++ b/app/client/packages/design-system/widgets/src/components/Text/src/types.ts @@ -29,7 +29,7 @@ export interface TextProps { /** Sets the horizontal alignment of the inline-level content inside a block element or table-cell box. See [MDN](https://developer.mozilla.org/en-US/docs/Web/CSS/text-align). * @default left */ - textAlign?: "left" | "center" | "right"; + textAlign?: "start" | "center" | "end" | "left" | "right"; /** Allows limiting of the contents of a block to the specified number of lines. See [MDN](https://developer.mozilla.org/en-US/docs/Web/CSS/-webkit-line-clamp). */ lineClamp?: number; /** Sets the CSS [className](https://developer.mozilla.org/en-US/docs/Web/API/Element/className) for the element. Only use as a **last resort**. Use style props instead. */ diff --git a/app/client/packages/design-system/widgets/src/index.ts b/app/client/packages/design-system/widgets/src/index.ts index 1ccdb1ad112..a314a5a513b 100644 --- a/app/client/packages/design-system/widgets/src/index.ts +++ b/app/client/packages/design-system/widgets/src/index.ts @@ -21,6 +21,7 @@ export * from "./components/ActionGroup"; export * from "./components/ButtonGroup"; export * from "./components/Select"; export * from "./components/ContextualHelp"; +export * from "./components/Link"; export * from "./utils"; export * from "./styles"; diff --git a/app/client/src/components/propertyControls/PrimaryColumnsControlV2.tsx b/app/client/src/components/propertyControls/PrimaryColumnsControlV2.tsx index bb618d1948a..aeff49f06d9 100644 --- a/app/client/src/components/propertyControls/PrimaryColumnsControlV2.tsx +++ b/app/client/src/components/propertyControls/PrimaryColumnsControlV2.tsx @@ -201,22 +201,24 @@ class PrimaryColumnsControlV2 extends BaseControl { const isFocused = !_.isNull(this.state.focusedIndex) && _.includes(this.state.duplicateColumnIds, column?.id); + return ( <>
{Object.values(reorderedColumns).length} columns
- {this.isEditableColumnPresent() && ( - - Editable - - - )} + {this.props.widgetProperties.type !== "WDS_TABLE_WIDGET" && + this.isEditableColumnPresent() && ( + + Editable + + + )}
@@ -233,26 +235,34 @@ class PrimaryColumnsControlV2 extends BaseControl { renderComponent={(props: any) => DraggableListCard({ ...props, - showCheckbox: true, + showCheckbox: + this.props.widgetProperties.type !== "WDS_TABLE_WIDGET" && + true, placeholder: "Column title", }) } toggleCheckbox={this.toggleCheckbox} - toggleVisibility={this.toggleVisibility} + toggleVisibility={ + this.props.widgetProperties.type !== "WDS_TABLE_WIDGET" + ? this.toggleVisibility + : undefined + } updateFocus={this.updateFocus} updateItems={this.updateItems} updateOption={this.updateOption} /> - + {this.props.widgetProperties.type !== "WDS_TABLE_WIDGET" && ( + + )}
); diff --git a/app/client/src/widgets/wds/WDSTableWidget/component/Constants.ts b/app/client/src/widgets/wds/WDSTableWidget/component/Constants.ts index 703c84edbee..bd8b38ad970 100644 --- a/app/client/src/widgets/wds/WDSTableWidget/component/Constants.ts +++ b/app/client/src/widgets/wds/WDSTableWidget/component/Constants.ts @@ -17,6 +17,8 @@ import type { import type { ColumnTypes } from "../constants"; import type { TimePrecision } from "widgets/DatePickerWidget2/constants"; import { generateReactKey } from "widgets/WidgetUtils"; +import type { PlainTextCellProps } from "./cellComponents/PlainTextCell"; +import type { ButtonCellProps } from "./cellComponents/ButtonCell"; export interface TableSizes { COLUMN_HEADER_HEIGHT: number; @@ -112,8 +114,8 @@ export interface TableStyles { export type CompactMode = keyof typeof CompactModeTypes; export type Condition = keyof typeof ConditionFunctions | ""; export type Operator = keyof typeof OperatorTypes; -export type CellAlignment = keyof typeof CellAlignmentTypes; -export type VerticalAlignment = keyof typeof VerticalAlignmentTypes; +export type CellAlignment = "start" | "center" | "end"; +export type VerticalAlignment = "start" | "center" | "end"; export type ImageSize = keyof typeof ImageSizes; export interface ReactTableFilter { @@ -153,7 +155,7 @@ export interface CellWrappingProperties { } export interface ButtonCellProperties { - buttonVariant: ButtonVariant; + buttonVariant: ButtonCellProps["buttonVariant"]; buttonColor?: string; buttonLabel?: string; isCompact?: boolean; @@ -212,24 +214,17 @@ export interface BaseCellProperties { cellBackground?: string; isVisible?: boolean; isDisabled?: boolean; - borderRadius: string; - boxShadow: string; isCellVisible: boolean; isCellDisabled?: boolean; } export interface CellLayoutProperties - extends EditActionCellProperties, - InlineEditingCellProperties, - CellWrappingProperties, + extends CellWrappingProperties, ButtonCellProperties, URLCellProperties, - MenuButtonCellProperties, - SelectCellProperties, - ImageCellProperties, - DateCellProperties, - CurrencyCellProperties, - BaseCellProperties {} + BaseCellProperties { + cellColor?: "default" | PlainTextCellProps["cellColor"]; +} export interface TableColumnMetaProps { isHidden: boolean; @@ -280,7 +275,6 @@ export interface ColumnBaseProperties { enableFilter?: boolean; enableSort?: boolean; isDerived: boolean; - computedValue: string; isCellVisible?: boolean; isAscOrder?: boolean; alias: string; @@ -353,38 +347,26 @@ export interface CurrencyColumnProperties { export interface ColumnProperties extends ColumnBaseProperties, ColumnStyleProperties, - DateColumnProperties, - ColumnEditabilityProperties, - CurrencyColumnProperties, - EditActionColumnProperties { + ColumnEditabilityProperties { allowSameOptionsInNewRow?: boolean; newRowSelectOptions?: DropdownOption[]; buttonLabel?: string; - menuButtonLabel?: string; buttonColor?: string; onClick?: string; dropdownOptions?: string; onOptionChange?: string; displayText?: string; buttonVariant?: ButtonVariant; - isCompact?: boolean; - menuItems?: MenuItems; - menuVariant?: ButtonVariant; - menuColor?: string; - borderRadius?: ButtonBorderRadius; - boxShadow?: string; - boxShadowColor?: string; iconName?: IconName; - menuButtoniconName?: IconName; iconAlign?: Alignment; onItemClicked?: (onClick: string | undefined) => void; iconButtonStyle?: ButtonStyleType; imageSize?: ImageSize; sticky?: StickyType; getVisibleItems?: () => Array; - menuItemsSource?: MenuItemsSource; configureMenuItems?: ConfigureMenuItems; sourceData?: Array>; + cellColor?: PlainTextCellProps["cellColor"]; } export const ConditionFunctions: { @@ -494,7 +476,6 @@ export enum IMAGE_VERTICAL_ALIGN { } export interface BaseCellComponentProps { - compactMode: string; isHidden: boolean; allowCellWrapping?: boolean; horizontalAlignment?: CellAlignment; @@ -502,8 +483,6 @@ export interface BaseCellComponentProps { cellBackground?: string; isCellVisible: boolean; fontStyle?: string; - textColor?: string; - textSize?: string; isCellDisabled?: boolean; } @@ -513,29 +492,6 @@ export enum CheckboxState { PARTIAL = 2, } -export const scrollbarOnHoverCSS = ` - .track-horizontal { - height: 6px; - bottom: 1px; - width: 100%; - opacity: 0; - transition: opacity 0.15s ease-in; - &:active { - opacity: 1; - } - } - &:hover { - .track-horizontal { - opacity: 1; - } - } - .thumb-horizontal { - &:hover, &:active { - height: 6px !important; - } - } -`; - export const MULTISELECT_CHECKBOX_WIDTH = 40; export enum AddNewRowActions { @@ -543,20 +499,6 @@ export enum AddNewRowActions { DISCARD = "DISCARD", } -export const EDITABLE_CELL_PADDING_OFFSET = 8; - -export const TABLE_SCROLLBAR_WIDTH = 10; -export const TABLE_SCROLLBAR_HEIGHT = 8; - -export const POPOVER_ITEMS_TEXT_MAP = { - SORT_ASC: "Sort column ascending", - SORT_DSC: "Sort column descending", - FREEZE_LEFT: "Freeze column left", - FREEZE_RIGHT: "Freeze column right", -}; - -export const HEADER_MENU_PORTAL_CLASS = ".header-menu-portal"; -export const MENU_CONTENT_CLASS = ".menu-content"; export const DEFAULT_FILTER = { id: generateReactKey(), column: "", diff --git a/app/client/src/widgets/wds/WDSTableWidget/component/StaticTable.tsx b/app/client/src/widgets/wds/WDSTableWidget/component/StaticTable.tsx index 3fb405f0f27..9a933814e35 100644 --- a/app/client/src/widgets/wds/WDSTableWidget/component/StaticTable.tsx +++ b/app/client/src/widgets/wds/WDSTableWidget/component/StaticTable.tsx @@ -7,7 +7,7 @@ import type { import type { ReactElementType } from "react-window"; import "simplebar-react/dist/simplebar.min.css"; import type { ReactTableColumnProps, TableSizes } from "./Constants"; -import { MULTISELECT_CHECKBOX_WIDTH, TABLE_SCROLLBAR_WIDTH } from "./Constants"; +import { MULTISELECT_CHECKBOX_WIDTH } from "./Constants"; import type { TableColumnHeaderProps } from "./TableHeader/TableColumnHeader"; import TableColumnHeader from "./TableHeader/TableColumnHeader"; import { TableBody } from "./TableBody"; @@ -86,7 +86,7 @@ const StaticTable = (props: StaticTableProps) => { selectedRowIndex={props.selectedRowIndex} selectedRowIndices={props.selectedRowIndices} useVirtual={props.useVirtual} - width={props.width - TABLE_SCROLLBAR_WIDTH / 2} + width={props.width} /> ); diff --git a/app/client/src/widgets/wds/WDSTableWidget/component/Table.tsx b/app/client/src/widgets/wds/WDSTableWidget/component/Table.tsx index fe2a414ab48..9f682223049 100644 --- a/app/client/src/widgets/wds/WDSTableWidget/component/Table.tsx +++ b/app/client/src/widgets/wds/WDSTableWidget/component/Table.tsx @@ -9,7 +9,6 @@ import { useRowSelect, } from "react-table"; import { useSticky } from "react-table-sticky"; -import { TableWrapper } from "./TableStyledWrappers"; import { TableHeader } from "./TableHeader"; import { Classes } from "@blueprintjs/core"; import type { @@ -20,7 +19,6 @@ import type { StickyType, } from "./Constants"; import { TABLE_SIZES, CompactModeTypes } from "./Constants"; -import { Colors } from "constants/Colors"; import type { EventType } from "constants/AppsmithActionConstants/ActionConstants"; import type { EditableCell, TableVariant } from "../constants"; import "simplebar-react/dist/simplebar.min.css"; @@ -73,7 +71,6 @@ export interface TableProps { triggerRowSelection: boolean; onSearch: (searchKey: any) => void; filters?: ReactTableFilter[]; - applyFilter: (filters: ReactTableFilter[]) => void; compactMode?: CompactMode; isVisibleDownload?: boolean; isVisibleFilters?: boolean; @@ -117,8 +114,6 @@ export interface HeaderComponentProps { ) => void; handleReorderColumn: (columnOrder: string[]) => void; columnOrder?: string[]; - accentColor: string; - borderRadius: string; headerGroups: any; canFreezeColumn?: boolean; editMode: boolean; @@ -182,7 +177,6 @@ export function Table(props: TableProps) { getTableProps, headerGroups, page, - pageOptions, prepareRow, state, totalColumnsWidth, @@ -283,60 +277,29 @@ export function Table(props: TableProps) { onConnectData={props.onConnectData} /> )} - {isHeaderVisible && ( )}
-
+ ); } diff --git a/app/client/src/widgets/wds/WDSTableWidget/component/TableBody/Row.tsx b/app/client/src/widgets/wds/WDSTableWidget/component/TableBody/Row.tsx index 804b98ae01c..992dba4a707 100644 --- a/app/client/src/widgets/wds/WDSTableWidget/component/TableBody/Row.tsx +++ b/app/client/src/widgets/wds/WDSTableWidget/component/TableBody/Row.tsx @@ -2,7 +2,7 @@ import type { CSSProperties, Key } from "react"; import React, { useContext } from "react"; import type { Row as ReactTableRowType } from "react-table"; import type { ListChildComponentProps } from "react-window"; -import { BodyContext } from "."; +import { TableBodyContext } from "./context"; import { renderEmptyRows } from "../cellComponents/EmptyCell"; import { renderBodyCheckBoxCell } from "../cellComponents/SelectionCheckboxCell"; import { MULTISELECT_CHECKBOX_WIDTH, StickyType } from "../Constants"; @@ -16,8 +16,6 @@ interface RowType { export function Row(props: RowType) { const { - accentColor, - borderRadius, columns, isAddRowInProgress, multiRowSelection, @@ -26,7 +24,7 @@ export function Row(props: RowType) { selectedRowIndex, selectedRowIndices, selectTableRow, - } = useContext(BodyContext); + } = useContext(TableBodyContext); prepareRow?.(props.row); const rowProps = { @@ -62,18 +60,22 @@ export function Row(props: RowType) { key={key} onClick={onClickRow} > - {multiRowSelection && - renderBodyCheckBoxCell(isRowSelected, accentColor, borderRadius)} + {multiRowSelection && renderBodyCheckBoxCell(isRowSelected)} {props.row.cells.map((cell, cellIndex) => { const cellProperties = cell.getCellProps(); cellProperties["style"] = { ...cellProperties.style, + display: "flex", + alignItems: columns[cellIndex].columnProperties.verticalAlignment, + justifyContent: + columns[cellIndex].columnProperties.horizontalAlignment, left: columns[cellIndex].sticky === StickyType.LEFT && multiRowSelection ? cell.column.totalLeft + MULTISELECT_CHECKBOX_WIDTH : cellProperties?.style?.left, }; + return (
@@ -113,7 +117,7 @@ export const EmptyRows = (props: { prepareRow, rows, width, - } = useContext(BodyContext); + } = useContext(TableBodyContext); return ( <> @@ -141,7 +145,7 @@ export const EmptyRow = (props: { style?: CSSProperties }) => { prepareRow, rows, width, - } = useContext(BodyContext); + } = useContext(TableBodyContext); return renderEmptyRows( 1, diff --git a/app/client/src/widgets/wds/WDSTableWidget/component/TableBody/StaticTableBody.tsx b/app/client/src/widgets/wds/WDSTableWidget/component/TableBody/StaticTableBody.tsx index 3030999e505..e7edf832aa5 100644 --- a/app/client/src/widgets/wds/WDSTableWidget/component/TableBody/StaticTableBody.tsx +++ b/app/client/src/widgets/wds/WDSTableWidget/component/TableBody/StaticTableBody.tsx @@ -1,6 +1,19 @@ import React from "react"; import { EmptyRows, Row } from "./Row"; -import type { StaticTableProps } from "./types"; +import type { + TableBodyProps, + TableBodyPropGetter, + Row as ReactTableRowType, +} from "react-table"; + +export interface StaticTableProps { + getTableBodyProps( + propGetter?: TableBodyPropGetter> | undefined, + ): TableBodyProps; + pageSize: number; + rows: ReactTableRowType>[]; + height: number; +} export const StaticTableBody = (props: StaticTableProps) => { return ( diff --git a/app/client/src/widgets/wds/WDSTableWidget/component/TableBody/VirtualTableBody.tsx b/app/client/src/widgets/wds/WDSTableWidget/component/TableBody/VirtualTableBody.tsx index 4aae1d28920..1137ed82891 100644 --- a/app/client/src/widgets/wds/WDSTableWidget/component/TableBody/VirtualTableBody.tsx +++ b/app/client/src/widgets/wds/WDSTableWidget/component/TableBody/VirtualTableBody.tsx @@ -1,11 +1,16 @@ import React, { useCallback } from "react"; import { useLayoutEffect, useRef } from "react"; -import type { VirtualTableBodyProps } from "./types"; - +import type { ReactElementType } from "react-window"; +import { useResizeObserver } from "@react-aria/utils"; import { FixedSizeList, areEqual } from "react-window"; import type { ListChildComponentProps } from "react-window"; + import { Row, EmptyRow } from "./Row"; -import { useResizeObserver } from "@react-aria/utils"; +import type { StaticTableProps } from "./StaticTableBody"; + +export interface VirtualTableBodyProps extends StaticTableProps { + innerElementType?: ReactElementType; +} export const VirtualTableBody = (props: VirtualTableBodyProps) => { const ref = useRef(null); diff --git a/app/client/src/widgets/wds/WDSTableWidget/component/TableBody/context.ts b/app/client/src/widgets/wds/WDSTableWidget/component/TableBody/context.ts new file mode 100644 index 00000000000..bcccab3287f --- /dev/null +++ b/app/client/src/widgets/wds/WDSTableWidget/component/TableBody/context.ts @@ -0,0 +1,45 @@ +import type { + Row as ReactTableRowType, + TableBodyPropGetter, + TableBodyProps, +} from "react-table"; +import React from "react"; + +import type { HeaderComponentProps } from "../Table"; +import type { ReactTableColumnProps } from "../Constants"; + +export type TableBodyContextType = { + accentColor: string; + borderRadius: string; + multiRowSelection: boolean; + prepareRow?(row: ReactTableRowType>): void; + selectTableRow?: (row: { + original: Record; + index: number; + }) => void; + selectedRowIndex: number; + selectedRowIndices: number[]; + columns: ReactTableColumnProps[]; + width: number; + rows: ReactTableRowType>[]; + primaryColumnId?: string; + isAddRowInProgress: boolean; + getTableBodyProps?( + propGetter?: TableBodyPropGetter> | undefined, + ): TableBodyProps; + totalColumnsWidth?: number; +} & Partial; + +export const TableBodyContext = React.createContext({ + accentColor: "", + borderRadius: "", + multiRowSelection: false, + selectedRowIndex: -1, + selectedRowIndices: [], + columns: [], + width: 0, + rows: [], + primaryColumnId: "", + isAddRowInProgress: false, + totalColumnsWidth: 0, +}); diff --git a/app/client/src/widgets/wds/WDSTableWidget/component/TableBody/index.tsx b/app/client/src/widgets/wds/WDSTableWidget/component/TableBody/index.tsx index ee33c93a8ff..b68e0d62d55 100644 --- a/app/client/src/widgets/wds/WDSTableWidget/component/TableBody/index.tsx +++ b/app/client/src/widgets/wds/WDSTableWidget/component/TableBody/index.tsx @@ -1,53 +1,13 @@ import React from "react"; -import type { - Row as ReactTableRowType, - TableBodyPropGetter, - TableBodyProps, -} from "react-table"; -import type { ReactTableColumnProps } from "../Constants"; -import type { HeaderComponentProps } from "../Table"; + +import { TableBodyContext } from "./context"; import { StaticTableBody } from "./StaticTableBody"; +import type { TableBodyContextType } from "./context"; +import type { VirtualTableBodyProps } from "./VirtualTableBody"; import { VirtualTableBody } from "./VirtualTableBody"; -import type { VirtualTableBodyProps } from "./types"; - -export type BodyContextType = { - accentColor: string; - borderRadius: string; - multiRowSelection: boolean; - prepareRow?(row: ReactTableRowType>): void; - selectTableRow?: (row: { - original: Record; - index: number; - }) => void; - selectedRowIndex: number; - selectedRowIndices: number[]; - columns: ReactTableColumnProps[]; - width: number; - rows: ReactTableRowType>[]; - primaryColumnId?: string; - isAddRowInProgress: boolean; - getTableBodyProps?( - propGetter?: TableBodyPropGetter> | undefined, - ): TableBodyProps; - totalColumnsWidth?: number; -} & Partial; - -export const BodyContext = React.createContext({ - accentColor: "", - borderRadius: "", - multiRowSelection: false, - selectedRowIndex: -1, - selectedRowIndices: [], - columns: [], - width: 0, - rows: [], - primaryColumnId: "", - isAddRowInProgress: false, - totalColumnsWidth: 0, -}); export const TableBody = ( - props: VirtualTableBodyProps & BodyContextType & { useVirtual: boolean }, + props: VirtualTableBodyProps & TableBodyContextType & { useVirtual: boolean }, ) => { const { accentColor, @@ -81,7 +41,7 @@ export const TableBody = ( } = props; return ( - {useVirtual ? ( - + ) : ( )} - + ); }; + +export { TableBodyContext }; diff --git a/app/client/src/widgets/wds/WDSTableWidget/component/TableBody/types.ts b/app/client/src/widgets/wds/WDSTableWidget/component/TableBody/types.ts deleted file mode 100644 index e1698391936..00000000000 --- a/app/client/src/widgets/wds/WDSTableWidget/component/TableBody/types.ts +++ /dev/null @@ -1,20 +0,0 @@ -import type { - TableBodyProps, - TableBodyPropGetter, - Row as ReactTableRowType, -} from "react-table"; -import type { ReactElementType } from "react-window"; - -export interface StaticTableProps { - getTableBodyProps( - propGetter?: TableBodyPropGetter> | undefined, - ): TableBodyProps; - pageSize: number; - rows: ReactTableRowType>[]; - height: number; - width?: number; -} - -export interface VirtualTableBodyProps extends StaticTableProps { - innerElementType?: ReactElementType; -} diff --git a/app/client/src/widgets/wds/WDSTableWidget/component/TableHeader/Actions.tsx b/app/client/src/widgets/wds/WDSTableWidget/component/TableHeader/Actions.tsx deleted file mode 100644 index ef3817d122d..00000000000 --- a/app/client/src/widgets/wds/WDSTableWidget/component/TableHeader/Actions.tsx +++ /dev/null @@ -1,155 +0,0 @@ -import { ActionGroup, Item } from "@design-system/widgets"; -import type { Key } from "react"; -import React, { useCallback } from "react"; -import type { - ReactTableColumnProps, - TableSizes, - ReactTableFilter, -} from "../Constants"; -import type { EventType } from "constants/AppsmithActionConstants/ActionConstants"; -import { - downloadDataAsCSV, - transformTableDataIntoCsv, - transformTableDataIntoExcel, -} from "../utilities"; -import zipcelx from "zipcelx"; -import { useDispatch } from "react-redux"; -import { ReduxActionTypes } from "@appsmith/constants/ReduxActionConstants"; - -export interface ActionsPropsType { - updatePageNo: (pageNo: number, event?: EventType) => void; - nextPageClick: () => void; - prevPageClick: () => void; - pageNo: number; - totalRecordsCount?: number; - tableData: Array>; - tableColumns: ReactTableColumnProps[]; - pageCount: number; - currentPageIndex: number; - pageOptions: number[]; - columns: ReactTableColumnProps[]; - hiddenColumns?: string[]; - widgetName: string; - widgetId: string; - serverSidePaginationEnabled: boolean; - filters?: ReactTableFilter[]; - applyFilter: (filters: ReactTableFilter[]) => void; - tableSizes: TableSizes; - isVisibleDownload?: boolean; - isVisibleFilters?: boolean; - isVisiblePagination?: boolean; - delimiter: string; - allowAddNewRow: boolean; - onAddNewRow: () => void; - disableAddNewRow: boolean; - width: number; -} - -export const Actions = (props: ActionsPropsType) => { - const dispatch = useDispatch(); - const { allowAddNewRow, isVisibleDownload, isVisibleFilters, widgetId } = - props; - - const toggleFilterPane = useCallback( - (selected: boolean) => { - if (selected) { - dispatch({ - type: ReduxActionTypes.SHOW_TABLE_FILTER_PANE, - payload: { widgetId, force: true }, - }); - } else { - dispatch({ - type: ReduxActionTypes.HIDE_TABLE_FILTER_PANE, - payload: { widgetId }, - }); - } - }, - [widgetId], - ); - - // if no columns are present, return - if (!props.columns.length) return null; - - // if none of the actions are visible, return - if (!(isVisibleFilters || isVisibleDownload || allowAddNewRow)) return null; - - const onAction = (key: Key) => { - switch (key) { - case "filter": - toggleFilterPane(true); - break; - case "add-row": - props.onAddNewRow(); - break; - case "download-csv": - const csvData = transformTableDataIntoCsv({ - columns: props.columns, - data: props.tableData, - }); - - downloadDataAsCSV({ - csvData: csvData, - delimiter: props.delimiter, - fileName: `${props.widgetName}.csv`, - }); - break; - case "download-excel": - const tableData = transformTableDataIntoExcel({ - columns: props.columns, - data: props.tableData, - }); - - zipcelx({ - filename: props.widgetName, - sheet: { - data: tableData, - }, - }); - break; - default: - break; - } - }; - - const actionItems = (() => { - const items = []; - - if (isVisibleFilters) - items.push( - - Filters - , - ); - if (isVisibleDownload) { - items.push( - - CSV - , - ); - items.push( - - Excel - , - ); - } - if (allowAddNewRow) - items.push( - - Add Row - , - ); - - return items; - })(); - - return ( - - {actionItems} - - ); -}; diff --git a/app/client/src/widgets/wds/WDSTableWidget/component/TableHeader/AddNewRowBanner.tsx b/app/client/src/widgets/wds/WDSTableWidget/component/TableHeader/AddNewRowBanner.tsx deleted file mode 100644 index feb95b29bf8..00000000000 --- a/app/client/src/widgets/wds/WDSTableWidget/component/TableHeader/AddNewRowBanner.tsx +++ /dev/null @@ -1,56 +0,0 @@ -import React, { useState } from "react"; -import { Text, Button, Flex } from "@design-system/widgets"; - -import { AddNewRowActions } from "../Constants"; - -export interface AddNewRowBannerProps { - onAddNewRowAction: ( - type: AddNewRowActions, - onActionComplete: () => void, - ) => void; - disabledAddNewRowSave: boolean; -} - -function AddNewRowBanner(props: AddNewRowBannerProps) { - const [isDiscardLoading, setIsDiscardLoading] = useState(false); - const [isSaveLoading, setIsSaveLoading] = useState(false); - - return ( - - Add New Row - - - - - - ); -} - -const MemoizedAddNewRowBanner = React.memo(AddNewRowBanner); - -export { MemoizedAddNewRowBanner as AddNewRowBanner }; diff --git a/app/client/src/widgets/wds/WDSTableWidget/component/TableHeader/CascadeFields.tsx b/app/client/src/widgets/wds/WDSTableWidget/component/TableHeader/CascadeFields.tsx deleted file mode 100644 index e86e93a5b15..00000000000 --- a/app/client/src/widgets/wds/WDSTableWidget/component/TableHeader/CascadeFields.tsx +++ /dev/null @@ -1,641 +0,0 @@ -import React, { useState, useEffect, useCallback } from "react"; -import styled from "styled-components"; -import { InputGroup } from "@blueprintjs/core"; -import { debounce, isNaN } from "lodash"; - -import CustomizedDropdown from "pages/common/CustomizedDropdown"; -import { Directions } from "utils/helpers"; -import { Colors } from "constants/Colors"; -import { Skin } from "constants/DefaultTheme"; -import AutoToolTipComponent from "../cellComponents/AutoToolTipComponent"; -import type { Condition, Operator, ReactTableFilter } from "../Constants"; -import { OperatorTypes } from "../Constants"; -import { RenderOptionWrapper } from "../TableStyledWrappers"; - -//TODO(abhinav): Fix this cross import between widgets -import DatePickerComponent from "widgets/DatePickerWidget2/component"; -import { TimePrecision } from "widgets/DatePickerWidget2/constants"; -import { ColumnTypes, ReadOnlyColumnTypes } from "../../constants"; -import { importRemixIcon } from "design-system-old"; -import type { DropdownOption } from "./FilterPaneContent"; - -const CloseIcon = importRemixIcon( - async () => import("remixicon-react/CloseCircleFillIcon"), -); -const ArrowDownIcon = importRemixIcon( - async () => import("remixicon-react/ArrowDownSLineIcon"), -); - -const LabelWrapper = styled.div` - width: 95px; - margin-left: 10px; - color: var(--wds-color-text-light); - font-size: 14px; - font-weight: 500; -`; - -const FieldWrapper = styled.div` - display: flex; - align-items: center; - justify-content: flex-start; - margin-top: 14px; -`; - -const DropdownWrapper = styled.div<{ width: number }>` - width: ${(props) => props.width}px; - margin-left: 10px; -`; - -const StyledInputGroup = styled(InputGroup)<{ - borderRadius?: string; -}>` - background: var(--wds-color-bg); - border: 1px solid var(--wds-color-border); - box-sizing: border-box; - border-radius: ${(props) => props.borderRadius || "0"}; - color: var(--wds-color-text); - height: 32px; - width: 120px; - margin-left: 10px; - overflow: hidden; - - input { - box-shadow: none; - } - - input:focus { - box-shadow: none; - } - &:hover { - border-color: var(--wds-color-border-hover); - } -`; - -const DatePickerWrapper = styled.div` - margin-left: 10px; - width: 150px; -`; - -const DropdownTrigger = styled.div<{ - borderRadius?: string; -}>` - display: flex; - align-items: center; - justify-content: space-between; - width: 100%; - height: 32px; - background: var(--wds-color-bg); - border: 1px solid var(--wds-color-border); - box-sizing: border-box; - border-radius: ${(props) => props.borderRadius || "0"}; - font-size: 14px; - padding: 5px 12px 7px; - color: var(--wds-color-text); - cursor: pointer; - - &:hover { - border-color: var(--wds-color-border-hover); - } - &&& span { - margin-right: 0; - } -`; - -const AutoToolTipComponentWrapper = styled(AutoToolTipComponent)` - width: 100%; - color: ${Colors.OXFORD_BLUE}; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; - margin-right: 5px; -`; - -const typeOperatorsMap: Record = { - [ColumnTypes.TEXT]: [ - { label: "contains", value: "contains", type: "input" }, - { label: "does not contain", value: "doesNotContain", type: "input" }, - { label: "starts with", value: "startsWith", type: "input" }, - { label: "ends with", value: "endsWith", type: "input" }, - { label: "is exactly", value: "isExactly", type: "input" }, - { label: "empty", value: "empty", type: "" }, - { label: "not empty", value: "notEmpty", type: "" }, - ], - [ColumnTypes.URL]: [ - { label: "contains", value: "contains", type: "input" }, - { label: "does not contain", value: "doesNotContain", type: "input" }, - { label: "starts with", value: "startsWith", type: "input" }, - { label: "ends with", value: "endsWith", type: "input" }, - { label: "is exactly", value: "isExactly", type: "input" }, - { label: "empty", value: "empty", type: "" }, - { label: "not empty", value: "notEmpty", type: "" }, - ], - [ColumnTypes.DATE]: [ - { label: "is", value: "is", type: "date" }, - { label: "is before", value: "isBefore", type: "date" }, - { label: "is after", value: "isAfter", type: "date" }, - { label: "is not", value: "isNot", type: "date" }, - { label: "empty", value: "empty", type: "" }, - { label: "not empty", value: "notEmpty", type: "" }, - ], - [ColumnTypes.IMAGE]: [ - { label: "empty", value: "empty", type: "" }, - { label: "not empty", value: "notEmpty", type: "" }, - ], - [ColumnTypes.VIDEO]: [ - { label: "empty", value: "empty", type: "" }, - { label: "not empty", value: "notEmpty", type: "" }, - ], - [ColumnTypes.NUMBER]: [ - { label: "is equal to", value: "isEqualTo", type: "input" }, - { label: "not equal to", value: "notEqualTo", type: "input" }, - { label: "greater than", value: "greaterThan", type: "input" }, - { - label: "greater than or equal to", - value: "greaterThanEqualTo", - type: "input", - }, - { label: "less than", value: "lessThan", type: "input" }, - { - label: "less than or equal to", - value: "lessThanEqualTo", - type: "input", - }, - { label: "empty", value: "empty", type: "" }, - { label: "not empty", value: "notEmpty", type: "" }, - ], - [ColumnTypes.CHECKBOX]: [ - { label: "is checked", value: "isChecked", type: "" }, - { label: "is unchecked", value: "isUnChecked", type: "" }, - ], - [ColumnTypes.SWITCH]: [ - { label: "is checked", value: "isChecked", type: "" }, - { label: "is unchecked", value: "isUnChecked", type: "" }, - ], - [ColumnTypes.SELECT]: [ - { label: "contains", value: "contains", type: "input" }, - { label: "does not contain", value: "doesNotContain", type: "input" }, - { label: "starts with", value: "startsWith", type: "input" }, - { label: "ends with", value: "endsWith", type: "input" }, - { label: "is exactly", value: "isExactly", type: "input" }, - { label: "empty", value: "empty", type: "" }, - { label: "not empty", value: "notEmpty", type: "" }, - ], -}; - -const operatorOptions: DropdownOption[] = [ - { label: "OR", value: OperatorTypes.OR, type: "" }, - { label: "AND", value: OperatorTypes.AND, type: "" }, -]; - -const columnTypeNameMap: Record = { - [ReadOnlyColumnTypes.TEXT]: "Text", - [ReadOnlyColumnTypes.VIDEO]: "Video", - [ReadOnlyColumnTypes.IMAGE]: "Image", - [ReadOnlyColumnTypes.NUMBER]: "Num", - [ReadOnlyColumnTypes.DATE]: "Date", - [ReadOnlyColumnTypes.URL]: "Url", - [ReadOnlyColumnTypes.CHECKBOX]: "Check", - [ReadOnlyColumnTypes.SWITCH]: "Check", - [ReadOnlyColumnTypes.SELECT]: "Text", -}; - -function RenderOption(props: { type: string; title: string; active: boolean }) { - return ( - -
{props.title}
-
- {columnTypeNameMap[props.type as ReadOnlyColumnTypes]} -
-
- ); -} - -function RenderOptions(props: { - columns: DropdownOption[]; - selectItem: (column: DropdownOption) => void; - placeholder: string; - value?: string | Condition; - showType?: boolean; - className?: string; - borderRadius?: string; -}) { - const [selectedValue, selectValue] = useState(props.placeholder); - const configs = { - sections: [ - { - options: props.columns.map((column: DropdownOption) => { - const isActive = column.value === props.value; - return { - content: props.showType ? ( - - ) : ( - column.label - ), - value: column.value, - active: isActive, - onSelect: () => { - selectValue(column.label); - props.selectItem(column); - }, - }; - }), - }, - ], - openDirection: Directions.DOWN, - trigger: { - content: ( - - - {selectedValue} - - - - ), - }, - skin: Skin.LIGHT, - borderRadius: props.borderRadius, - customizedDropdownId: "cascade-dropdown", - }; - useEffect(() => { - if (props.value && props.columns) { - const selectedOptions = props.columns.filter( - (i) => i.value === props.value, - ); - if (selectedOptions && selectedOptions.length) { - selectValue(selectedOptions[0].label); - } else { - selectValue(props.placeholder); - } - } else { - selectValue(props.placeholder); - } - }, [props.value, props.placeholder, props.columns]); - return ; -} - -function RenderInput(props: { - value: string; - onChange: (value: string) => void; - className?: string; - borderRadius?: string; -}) { - const debouncedOnChange = useCallback(debounce(props.onChange, 400), []); - const [value, setValue] = useState(props.value); - const onChange = (event: React.ChangeEvent) => { - const value = event.target.value; - setValue(value); - debouncedOnChange(value); - }; - useEffect(() => { - setValue(props.value); - }, [props.value]); - return ( - - ); -} - -interface CascadeFieldProps { - columns: DropdownOption[]; - column: string; - condition: Condition; - value: any; - operator: Operator; - id: string; - index: number; - hasAnyFilters: boolean; - applyFilter: ( - filter: ReactTableFilter, - index: number, - isOperatorChange: boolean, - ) => void; - removeFilter: (index: number) => void; -} - -interface CascadeFieldState { - column: string; - condition: Condition; - value: any; - operator: Operator; - conditions: DropdownOption[]; - showConditions: boolean; - showInput: boolean; - showDateInput: boolean; - isDeleted: boolean; - isUpdate: boolean; - isOperatorChange: boolean; -} - -const getConditions = (props: CascadeFieldProps) => { - const columnValue = props.column || ""; - const filteredColumn = props.columns.filter((column: DropdownOption) => { - return columnValue === column.value; - }); - if (filteredColumn.length) { - const type: ReadOnlyColumnTypes = filteredColumn[0] - .type as ReadOnlyColumnTypes; - return typeOperatorsMap[type]; - } else { - return new Array(0); - } -}; - -const showConditionsField = (props: CascadeFieldProps) => { - const columnValue = props.column || ""; - const filteredColumn = props.columns.filter((column: DropdownOption) => { - return columnValue === column.value; - }); - return !!filteredColumn.length; -}; - -const showInputField = ( - props: CascadeFieldProps, - conditions: DropdownOption[], -) => { - const conditionValue = props.condition || ""; - const filteredConditions = - conditions && - conditions.filter((condition: DropdownOption) => { - return condition.value === conditionValue; - }); - return !!filteredConditions.length && filteredConditions[0].type === "input"; -}; - -const showDateInputField = ( - props: CascadeFieldProps, - conditions: DropdownOption[], -) => { - const conditionValue = props.condition || ""; - const filteredConditions = - conditions && - conditions.filter((condition: DropdownOption) => { - return condition.value === conditionValue; - }); - return !!filteredConditions.length && filteredConditions[0].type === "date"; -}; - -function calculateInitialState(props: CascadeFieldProps) { - const showConditions = showConditionsField(props); - const conditions = getConditions(props); - const showInput = showInputField(props, conditions); - const showDateInput = showDateInputField(props, conditions); - return { - operator: props.operator, - column: props.column, - condition: props.condition, - value: props.value, - conditions: conditions, - showConditions: showConditions, - showInput: showInput, - showDateInput: showDateInput, - isDeleted: false, - isUpdate: false, - isOperatorChange: false, - }; -} - -export enum CascadeFieldActionTypes { - SELECT_COLUMN = "SELECT_COLUMN", - SELECT_CONDITION = "SELECT_CONDITION", - CHANGE_VALUE = "CHANGE_VALUE", - SELECT_OPERATOR = "SELECT_OPERATOR", - UPDATE_FILTER = "UPDATE_FILTER", - DELETE_FILTER = "DELETE_FILTER", -} - -type CascadeFieldAction = keyof typeof CascadeFieldActionTypes; - -function CaseCaseFieldReducer( - state: CascadeFieldState, - action: { - type: CascadeFieldAction; - payload?: any; - }, -) { - switch (action.type) { - case CascadeFieldActionTypes.SELECT_COLUMN: - const type: ReadOnlyColumnTypes = action.payload.type; - return { - ...state, - column: action.payload.value, - condition: "", - conditions: typeOperatorsMap[type], - showConditions: true, - isUpdate: true, - }; - case CascadeFieldActionTypes.SELECT_CONDITION: - return { - ...state, - condition: action.payload.value, - showInput: action.payload.type === "input", - showDateInput: action.payload.type === "date", - value: action.payload.type === "" ? "" : state.value, - isUpdate: true, - }; - case CascadeFieldActionTypes.CHANGE_VALUE: - return { - ...state, - value: action.payload, - isUpdate: true, - }; - case CascadeFieldActionTypes.SELECT_OPERATOR: - return { - ...state, - operator: action.payload, - isUpdate: true, - isOperatorChange: true, - }; - case CascadeFieldActionTypes.UPDATE_FILTER: - const calculatedState = calculateInitialState(action.payload); - return { - ...calculatedState, - isUpdate: false, - }; - case CascadeFieldActionTypes.DELETE_FILTER: - return { - ...state, - isDeleted: true, - }; - default: - throw new Error(); - } -} - -function CascadeField(props: CascadeFieldProps) { - const memoizedState = React.useMemo( - () => calculateInitialState(props), - [props], - ); - return ; -} - -function Fields(props: CascadeFieldProps & { state: CascadeFieldState }) { - const { applyFilter, hasAnyFilters, id, index, removeFilter } = props; - const [state, dispatch] = React.useReducer(CaseCaseFieldReducer, props.state); - const handleRemoveFilter = () => { - dispatch({ type: CascadeFieldActionTypes.DELETE_FILTER }); - }; - const selectColumn = (column: DropdownOption) => { - dispatch({ - type: CascadeFieldActionTypes.SELECT_COLUMN, - payload: column, - }); - }; - const selectCondition = (condition: DropdownOption) => { - dispatch({ - type: CascadeFieldActionTypes.SELECT_CONDITION, - payload: condition, - }); - }; - const onValueChange = (value: string) => { - const parsedValue = value && !isNaN(Number(value)) ? Number(value) : value; - dispatch({ - type: CascadeFieldActionTypes.CHANGE_VALUE, - payload: parsedValue, - }); - }; - const onDateSelected = (date: string) => { - dispatch({ - type: CascadeFieldActionTypes.CHANGE_VALUE, - payload: date, - }); - }; - const selectOperator = (option: DropdownOption) => { - dispatch({ - type: CascadeFieldActionTypes.SELECT_OPERATOR, - payload: OperatorTypes[option.value as Operator], - }); - }; - - const { - column, - condition, - conditions, - isDeleted, - isOperatorChange, - isUpdate, - operator, - showConditions, - showDateInput, - showInput, - value, - } = state; - useEffect(() => { - if (!isDeleted && isUpdate) { - applyFilter( - { id, operator, column, condition, value }, - index, - isOperatorChange, - ); - } else if (isDeleted) { - removeFilter(index); - } - }, [ - operator, - column, - condition, - value, - isDeleted, - isOperatorChange, - isUpdate, - index, - applyFilter, - removeFilter, - ]); - - useEffect(() => { - dispatch({ - type: CascadeFieldActionTypes.UPDATE_FILTER, - payload: props, - }); - }, [props]); - return ( - - - {index === 1 ? ( - - - - ) : ( - - {index === 0 ? "Where" : OperatorTypes[props.operator]} - - )} - - - - {showConditions ? ( - - - - ) : null} - {showInput ? ( - - ) : null} - {showDateInput ? ( - - {/*@ts-expect-error: types mismatch because we don't use settings styles through props anymore. Remove this after creating WDS datepicker. */} - - - ) : null} - - ); -} - -export default CascadeField; diff --git a/app/client/src/widgets/wds/WDSTableWidget/component/TableHeader/FilterPane.tsx b/app/client/src/widgets/wds/WDSTableWidget/component/TableHeader/FilterPane.tsx deleted file mode 100644 index 6c6fa8a29dd..00000000000 --- a/app/client/src/widgets/wds/WDSTableWidget/component/TableHeader/FilterPane.tsx +++ /dev/null @@ -1,159 +0,0 @@ -import React, { Component } from "react"; -import { connect } from "react-redux"; -import { get } from "lodash"; -import * as log from "loglevel"; -import type { AppState } from "@appsmith/reducers"; -import styled from "styled-components"; - -import { Colors } from "constants/Colors"; -import type { ReactTableColumnProps, ReactTableFilter } from "../Constants"; -import TableFilterPaneContent from "./FilterPaneContent"; -import { getCurrentThemeMode, ThemeMode } from "selectors/themeSelectors"; -import { Layers } from "constants/Layers"; -import Popper from "pages/Editor/Popper"; -import { getTableFilterState } from "selectors/tableFilterSelectors"; -import { getWidgetMetaProps } from "sagas/selectors"; -import { ReduxActionTypes } from "@appsmith/constants/ReduxActionConstants"; -import type { WidgetProps } from "widgets/BaseWidget"; -import { selectWidgetInitAction } from "actions/widgetSelectionActions"; -import { SelectionRequestType } from "sagas/WidgetSelectUtils"; -import { importSvg } from "design-system-old"; -import { CANVAS_ART_BOARD } from "constants/componentClassNameConstants"; - -const DragHandleIcon = importSvg( - async () => import("assets/icons/ads/app-icons/draghandler.svg"), -); - -const DragBlock = styled.div` - height: 40px; - width: 83px; - background: var(--wds-color-bg-light); - box-sizing: border-box; - font-size: 12px; - color: ${Colors.GREY_11}; - letter-spacing: 0.04em; - font-weight: 500; - display: flex; - align-items: center; - justify-content: center; - cursor: pointer; - - span { - padding-left: 8px; - color: var(--wds-color-text-light); - } -`; - -export interface TableFilterPaneProps { - widgetId: string; - columns: ReactTableColumnProps[]; - filters?: ReactTableFilter[]; - applyFilter: (filters: ReactTableFilter[]) => void; - targetNode?: Element; -} - -interface PositionPropsInt { - top: number; - left: number; -} - -type Props = ReturnType & - ReturnType & - TableFilterPaneProps; - -class TableFilterPane extends Component { - getPopperTheme() { - return ThemeMode.LIGHT; - } - - handlePositionUpdate = (position: any) => { - this.props.setPanePosition( - this.props.tableFilterPane.widgetId as string, - position, - ); - }; - - render() { - if ( - this.props.tableFilterPane.isVisible && - this.props.tableFilterPane.widgetId === this.props.widgetId - ) { - log.debug("tablefilter pane rendered"); - - /* - Prevent the FilterPane from overflowing the canvas when the - table widget is on the very top of the canvas. - */ - const boundaryParent = document.querySelector("#root"); - - return ( - - - Move - - } - renderDragBlockPositions={{ - left: "0px", - }} - targetNode={this.props.targetNode} - themeMode={this.getPopperTheme()} - zIndex={Layers.tableFilterPane} - > - - - ); - } else { - return null; - } - } -} - -const mapStateToProps = (state: AppState, ownProps: TableFilterPaneProps) => { - const widgetLikeProps = { - widgetId: ownProps.widgetId, - } as WidgetProps; - - return { - tableFilterPane: getTableFilterState(state), - themeMode: getCurrentThemeMode(state), - metaProps: getWidgetMetaProps(state, widgetLikeProps), - }; -}; - -const mapDispatchToProps = (dispatch: any) => { - return { - setPanePosition: (widgetId: string, position: any) => { - dispatch({ - type: ReduxActionTypes.TABLE_PANE_MOVED, - payload: { - widgetId, - position, - }, - }); - dispatch(selectWidgetInitAction(SelectionRequestType.One, [widgetId])); - }, - hideFilterPane: (widgetId: string) => { - dispatch({ - type: ReduxActionTypes.HIDE_TABLE_FILTER_PANE, - payload: { widgetId }, - }); - dispatch(selectWidgetInitAction(SelectionRequestType.One, [widgetId])); - }, - }; -}; -export default connect(mapStateToProps, mapDispatchToProps)(TableFilterPane); diff --git a/app/client/src/widgets/wds/WDSTableWidget/component/TableHeader/FilterPaneContent.tsx b/app/client/src/widgets/wds/WDSTableWidget/component/TableHeader/FilterPaneContent.tsx deleted file mode 100644 index d5a360b27cd..00000000000 --- a/app/client/src/widgets/wds/WDSTableWidget/component/TableHeader/FilterPaneContent.tsx +++ /dev/null @@ -1,291 +0,0 @@ -import React, { useEffect, useCallback } from "react"; -import styled from "styled-components"; -import { Classes } from "@blueprintjs/core"; -import { Colors } from "constants/Colors"; -import type { - ReactTableColumnProps, - ReactTableFilter, - Operator, -} from "../Constants"; -import { OperatorTypes, DEFAULT_FILTER } from "../Constants"; -import CascadeFields from "./CascadeFields"; -import { - createMessage, - TABLE_FILTER_COLUMN_TYPE_CALLOUT, -} from "@appsmith/constants/messages"; -import { Icon, IconSize } from "@design-system/widgets-old"; -import { StyledButton as Button } from "widgets/ButtonWidget/component"; -import { ButtonVariantTypes } from "components/constants"; - -import { cloneDeep } from "lodash"; -import { - ColumnTypes, - FilterableColumnTypes, -} from "widgets/wds/WDSTableWidget/constants"; -import { generateReactKey } from "utils/generators"; -import { importRemixIcon } from "design-system-old"; - -export interface DropdownOption { - label: string; - value: string; - type: string; -} - -const AddIcon = importRemixIcon( - async () => import("remixicon-react/AddLineIcon"), -); - -const TableFilterOuterWrapper = styled.div<{ - borderRadius?: string; -}>` - display: flex; - flex-direction: column; - width: 100%; - background: ${Colors.WHITE}; - box-shadow: 0 6px 20px 0px rgba(0, 0, 0, 0.15); - border-radius: ${(props) => props.borderRadius || "0"}; -`; - -const TableFilerWrapper = styled.div` - display: flex; - flex-direction: column; - width: 100%; - padding: 2px 16px 14px; -`; - -const ButtonWrapper = styled.div` - display: flex; - width: 100%; - justify-content: space-between; - align-items: center; - background: ${Colors.WHITE}; - margin-top: 14px; - &&& button:hover { - background: transparent; - } - .${Classes.BUTTON_TEXT} { - font-weight: 600 !important; - } -`; - -const ButtonActionsWrapper = styled.div` - display: flex; - align-items: center; - &&& button { - margin-left: 14px; - } -`; - -// margin-left is same as move block width in TableFilterPane.tsx -const ColumnTypeBindingMessage = styled.div` - height: 40px; - line-height: 40px; - background: var(--wds-color-bg-light); - box-sizing: border-box; - font-size: 12px; - color: var(--wds-color-text-light); - letter-spacing: 0.04em; - font-weight: 500; - margin-left: 83px; - min-width: 350px; - display: flex; - align-items: center; - justify-content: space-between; - - & .message-text { - padding: 0 8px 0 16px; - } - - & .close-button { - cursor: pointer; - margin: 3px; - height: 34px; - width: 34px; - display: flex; - justify-content: center; - &:hover { - background-color: ${Colors.GREY_3}; - svg path { - fill: ${Colors.GREY_10}; - } - } - } -`; - -interface TableFilterProps { - columns: ReactTableColumnProps[]; - filters?: ReactTableFilter[]; - applyFilter: (filters: ReactTableFilter[]) => void; - hideFilterPane: (widgetId: string) => void; - widgetId: string; -} - -const defaultFilters = [{ ...DEFAULT_FILTER }]; -const getTableFilters = (filters: ReactTableFilter[] | undefined) => { - if (!filters || filters.length === 0) { - return defaultFilters; - } - return filters; -}; - -function TableFilterPaneContent(props: TableFilterProps) { - const [filters, updateFilters] = React.useState( - getTableFilters(props.filters), - ); - - useEffect(() => { - const updatedFiltersState = getTableFilters(props.filters); - //if props has been updated update the filters state - if (updatedFiltersState !== filters) { - updateFilters(updatedFiltersState); - } - }, [props.filters]); - - const addFilter = () => { - const updatedFilters = filters ? [...filters] : []; - let operator: Operator = OperatorTypes.OR; - if (updatedFilters.length >= 2) { - operator = updatedFilters[1].operator; - } - // New id is generated for new filter here - updatedFilters.push({ - ...DEFAULT_FILTER, - id: generateReactKey(), - operator, - }); - updateFilters(updatedFilters); - }; - - const applyFilter = () => { - props.applyFilter(filters); - }; - - const hideFilter = () => { - props.hideFilterPane(props.widgetId); - }; - - const clearFilters = useCallback(() => { - props.applyFilter([]); - }, [props]); - - const columns: DropdownOption[] = props.columns - .map((column: ReactTableColumnProps) => { - const type = column.metaProperties?.type || ColumnTypes.TEXT; - - return { - label: column.Header, - value: column.alias, - type: type, - }; - }) - .filter((column: { label: string; value: string; type: ColumnTypes }) => { - return FilterableColumnTypes.includes(column.type); - }); - - const hasAnyFilters = !!( - filters.length >= 1 && - filters[0].column && - filters[0].condition - ); - - return ( - { - e.stopPropagation(); - }} - > - -
- {createMessage(TABLE_FILTER_COLUMN_TYPE_CALLOUT)} -
-
- -
-
- e.stopPropagation()}> - {filters.map((filter: ReactTableFilter, index: number) => { - return ( - { - // here updated filters store in state, not in redux - const updatedFilters = filters ? cloneDeep(filters) : []; - updatedFilters[index] = filter; - if (isOperatorChange) { - /* - This if-block updates the operator for all filters after - second filter if the second filter operator is changed - */ - let index = 2; - while (index < updatedFilters.length) { - updatedFilters[index].operator = updatedFilters[1].operator; - index++; - } - } - updateFilters(updatedFilters); - }} - column={filter.column} - columns={columns} - condition={filter.condition} - hasAnyFilters={hasAnyFilters} - id={filter.id} - index={index} - key={filter.id} - operator={ - filters.length >= 2 ? filters[1].operator : filter.operator - } - removeFilter={(index: number) => { - const updatedFilters = cloneDeep(filters); - let newFilters: Array = []; - if (updatedFilters) { - if (index === 1 && updatedFilters.length > 2) { - updatedFilters[2].operator = updatedFilters[1].operator; - } - newFilters = [ - ...updatedFilters.slice(0, index), - ...updatedFilters.slice(index + 1), - ]; - } - // removed filter directly update redux - // with redux update, useEffect will update local state too - props.applyFilter(newFilters); - }} - value={filter.value} - /> - ); - })} - {hasAnyFilters ? ( - - ); } -export const ButtonCell = memo(ButtonCellComponent); + +const MemoizedButtonCell = memo(ButtonCell); + +export { MemoizedButtonCell as ButtonCell }; diff --git a/app/client/src/widgets/wds/WDSTableWidget/component/cellComponents/CheckboxCell.tsx b/app/client/src/widgets/wds/WDSTableWidget/component/cellComponents/CheckboxCell.tsx index b1200db9313..6eca71158da 100644 --- a/app/client/src/widgets/wds/WDSTableWidget/component/cellComponents/CheckboxCell.tsx +++ b/app/client/src/widgets/wds/WDSTableWidget/component/cellComponents/CheckboxCell.tsx @@ -1,51 +1,6 @@ import React, { memo } from "react"; -import type { BaseCellComponentProps, CellAlignment } from "../Constants"; -import { ALIGN_ITEMS, JUSTIFY_CONTENT } from "../Constants"; -import { CellWrapper, TooltipContentWrapper } from "../TableStyledWrappers"; -import CheckboxComponent from "widgets/CheckboxWidget/component/index"; -import { LabelPosition } from "components/constants"; -import styled from "styled-components"; -import { Tooltip } from "@blueprintjs/core"; - -const UnsavedChangesMarker = styled.div<{ accentColor: string }>` - position: absolute; - top: -1px; - right: -3px; - width: 0; - height: 0; - border-left: 5px solid transparent; - border-right: 5px solid transparent; - border-bottom: 5px solid ${(props) => props.accentColor}; - transform: rotateZ(45deg); -`; - -const CheckboxCellWrapper = styled(CellWrapper)<{ - horizontalAlignment?: CellAlignment; -}>` - & div { - justify-content: ${(props) => - props.horizontalAlignment && - JUSTIFY_CONTENT[props.horizontalAlignment]} !important; - - align-items: ${(props) => - props.verticalAlignment && - ALIGN_ITEMS[props.verticalAlignment]} !important; - - & .bp3-checkbox { - gap: 0px; - } - } - & .bp3-disabled { - cursor: grab !important; - & .bp3-control-indicator::before { - cursor: grab !important; - } - } - - & > .bp3-popover-wrapper { - overflow: unset; - } -`; +import type { BaseCellComponentProps } from "../Constants"; +import { Checkbox } from "@design-system/widgets"; type CheckboxCellProps = BaseCellComponentProps & { value: boolean; @@ -60,67 +15,16 @@ type CheckboxCellProps = BaseCellComponentProps & { }; const CheckboxCellComponent = (props: CheckboxCellProps) => { - const { - accentColor, - borderRadius, - cellBackground, - compactMode, - disabledCheckbox, - disabledCheckboxMessage, - hasUnSavedChanges, - horizontalAlignment, - isCellDisabled, - isCellEditable, - isCellVisible, - isHidden, - onChange, - value, - verticalAlignment, - } = props; + const { disabledCheckbox, isCellEditable, onChange, value } = props; - const checkbox = ( - onChange()} - widgetId={""} + isSelected={value} + onChange={() => onChange()} /> ); - return ( - - {hasUnSavedChanges && } - {isCellEditable && !!disabledCheckbox ? ( - - {disabledCheckboxMessage} - - } - hoverOpenDelay={200} - position="top" - > - {checkbox} - - ) : ( - checkbox - )} - - ); }; export const CheckboxCell = memo(CheckboxCellComponent); diff --git a/app/client/src/widgets/wds/WDSTableWidget/component/cellComponents/DateCell.tsx b/app/client/src/widgets/wds/WDSTableWidget/component/cellComponents/DateCell.tsx deleted file mode 100644 index a60ae8f6a18..00000000000 --- a/app/client/src/widgets/wds/WDSTableWidget/component/cellComponents/DateCell.tsx +++ /dev/null @@ -1,358 +0,0 @@ -import React, { useMemo, useRef, useState } from "react"; -import type { VerticalAlignment } from "../Constants"; -import { - ALIGN_ITEMS, - EDITABLE_CELL_PADDING_OFFSET, - TABLE_SIZES, -} from "../Constants"; -import DateComponent from "widgets/DatePickerWidget2/component"; -import { TimePrecision } from "widgets/DatePickerWidget2/constants"; -import type { RenderDefaultPropsType } from "./PlainTextCell"; -import styled from "styled-components"; -import { EditableCellActions } from "widgets/wds/WDSTableWidget/constants"; -import { ISO_DATE_FORMAT } from "constants/WidgetValidation"; -import moment from "moment"; -import { BasicCell } from "./BasicCell"; -import { Colors } from "constants/Colors"; -import ErrorTooltip from "components/editorComponents/ErrorTooltip"; -import { - createMessage, - INPUT_WIDGET_DEFAULT_VALIDATION_ERROR, -} from "@appsmith/constants/messages"; - -type DateComponentProps = RenderDefaultPropsType & - editPropertyType & { - accentColor?: string; - borderRadius?: string; - boxShadow?: string; - closeOnSelection: boolean; - maxDate: string; - minDate: string; - onDateChange?: string; - shortcuts: boolean; - timePrecision: TimePrecision; - inputFormat: string; - outputFormat: string; - onDateSave: ( - rowIndex: number, - alias: string, - value: string, - onSubmit?: string, - ) => void; - onDateSelectedString: string; - firstDayOfWeek?: number; - isRequired: boolean; - updateNewRowValues: ( - alias: string, - value: unknown, - parsedValue: unknown, - ) => void; - }; - -const COMPONENT_DEFAULT_VALUES = { - maxDate: "2121-12-31T18:29:00.000Z", - minDate: "1920-12-31T18:30:00.000Z", - timePrecision: TimePrecision.MINUTE, -}; - -interface editPropertyType { - alias: string; - onDateSelectedString: string; - rowIndex: number; -} - -const DEFAULT_BORDER_RADIUS = "0"; - -const Container = styled.div<{ - isCellEditMode?: boolean; - verticalAlignment?: VerticalAlignment; - cellBackground?: string; -}>` - height: 100%; - width: 100%; - display: flex; - align-items: ${(props) => - props.verticalAlignment && ALIGN_ITEMS[props.verticalAlignment]}; -`; - -const FOCUS_CLASS = "has-focus"; - -const Wrapper = styled.div<{ - accentColor: string; - compactMode: string; - allowCellWrapping?: boolean; - verticalAlignment?: VerticalAlignment; - textSize?: string; - isEditableCellValid: boolean; - paddedInput: boolean; -}>` - padding: 1px; - border: 1px solid - ${(props) => (!props.isEditableCellValid ? Colors.DANGER_SOLID : "#fff")}; - background: #fff; - position: absolute; - width: ${(props) => - props.paddedInput - ? `calc(100% - ${EDITABLE_CELL_PADDING_OFFSET}px)` - : "100%"}; - left: 50%; - transform: translate(-50%, 0); - overflow: hidden; - border-radius: 3px; - display: flex; - height: ${(props) => { - if (props.allowCellWrapping) { - return props.paddedInput - ? `calc(100% - ${EDITABLE_CELL_PADDING_OFFSET}px)` - : "100%"; - } else { - return props.paddedInput - ? `${ - TABLE_SIZES[props.compactMode].ROW_HEIGHT - - EDITABLE_CELL_PADDING_OFFSET - }px` - : `${TABLE_SIZES[props.compactMode].ROW_HEIGHT}px`; - } - }}; - ${(props) => { - switch (props.verticalAlignment) { - case "TOP": - return `top: 0;`; - case "BOTTOM": - return `bottom: 0;`; - case "CENTER": - return ` - top: calc(50% - (${TABLE_SIZES[props.compactMode].ROW_HEIGHT}/2)px); - `; - } - }} - - &&&&& { - .bp3-input, - .bp3-input:focus { - border: none; - /* - * using !important since underlying - * component styles has !important - */ - box-shadow: none !important; - padding: 0px 5px 0px 6px; - font-size: ${(props) => props.textSize}; - background: transparent; - color: inherit; - } - } - - &.${FOCUS_CLASS} { - ${(props) => - props.isEditableCellValid && `border: 1px solid ${props.accentColor}`} - } -`; - -export const DateCell = (props: DateComponentProps) => { - const { - accentColor, - alias, - allowCellWrapping, - borderRadius, - cellBackground, - columnType, - compactMode, - disabledEditIcon, - disabledEditIconMessage, - firstDayOfWeek, - fontStyle, - hasUnsavedChanges, - horizontalAlignment, - inputFormat, - isCellDisabled, - isCellEditable, - isCellEditMode, - isCellVisible, - isHidden, - isNewRow, - isRequired, - maxDate, - minDate, - onDateSave, - onDateSelectedString, - outputFormat, - rowIndex, - shortcuts, - tableWidth, - textColor, - textSize, - timePrecision, - toggleCellEditMode, - updateNewRowValues, - validationErrorMessage, - value, - verticalAlignment, - widgetId, - } = props; - - const [hasFocus, setHasFocus] = useState(false); - const [isValid, setIsValid] = useState(true); - const [showRequiredError, setShowRequiredError] = useState(false); - const contentRef = useRef(null); - - const valueInISOFormat = useMemo(() => { - if (typeof value !== "string") return ""; - - if (moment(value, ISO_DATE_FORMAT, true).isValid()) { - return value; - } - - const valueInSelectedFormat = moment(value, props.outputFormat, true); - - if (valueInSelectedFormat.isValid()) { - return valueInSelectedFormat.format(ISO_DATE_FORMAT); - } - - return value; - }, [value, props.outputFormat]); - - const onDateSelected = (date: string) => { - if (isNewRow) { - updateNewRowValues(alias, date, date); - return; - } - - if (isRequired && !date) { - setIsValid(false); - setShowRequiredError(true); - return; - } - setIsValid(true); - setShowRequiredError(false); - setHasFocus(false); - - const formattedDate = date ? moment(date).format(inputFormat) : ""; - onDateSave(rowIndex, alias, formattedDate, onDateSelectedString); - }; - - const onDateCellEdit = () => { - setHasFocus(true); - if (isRequired && !value) { - setIsValid(false); - setShowRequiredError(true); - } - toggleCellEditMode(true, rowIndex, alias, value); - }; - - const onPopoverClosed = () => { - setHasFocus(false); - setIsValid(true); - toggleCellEditMode( - false, - rowIndex, - alias, - value, - "", - EditableCellActions.DISCARD, - ); - }; - - const onDateOutOfRange = () => { - setIsValid(false); - setShowRequiredError(false); - }; - - const onDateInputFocus = () => { - if (isNewRow) { - setHasFocus(true); - } - }; - - let editor; - - if (isCellEditMode) { - editor = ( - - - - - - ); - } - - return ( - - - {editor} - - ); -}; diff --git a/app/client/src/widgets/wds/WDSTableWidget/component/cellComponents/EditActionsCell.tsx b/app/client/src/widgets/wds/WDSTableWidget/component/cellComponents/EditActionsCell.tsx deleted file mode 100644 index 5e65c9b1621..00000000000 --- a/app/client/src/widgets/wds/WDSTableWidget/component/cellComponents/EditActionsCell.tsx +++ /dev/null @@ -1,93 +0,0 @@ -import React, { memo } from "react"; -import type { EventType } from "constants/AppsmithActionConstants/ActionConstants"; -import type { ButtonColumnActions } from "widgets/wds/WDSTableWidget/constants"; -import { EditableCellActions } from "widgets/wds/WDSTableWidget/constants"; -import { Button } from "./Button"; -import type { BaseCellComponentProps } from "../Constants"; -import { CellWrapper } from "../TableStyledWrappers"; - -type RenderEditActionsProps = BaseCellComponentProps & { - isSelected: boolean; - columnActions: ButtonColumnActions[]; - onCommandClick: ( - dynamicTrigger: string, - onComplete: () => void, - eventType: EventType, - ) => void; - onDiscard: () => void; -}; - -function EditActionCellComponent(props: RenderEditActionsProps) { - const { - allowCellWrapping, - cellBackground, - columnActions, - compactMode, - fontStyle, - horizontalAlignment, - isCellDisabled, - isCellVisible, - isHidden, - isSelected, - onCommandClick, - onDiscard, - textColor, - textSize, - verticalAlignment, - } = props; - - if (!columnActions) { - return ( - - ); - } - - return ( - - {columnActions.map((action: ButtonColumnActions) => { - return ( -