chore: use ads icons (#35633)

## Description
Why did this PR appear? I wanted to replace the icons from `ads-old`
with the icons from `ads`. After that, I had to fix some affected
components in `ads-old` and in the main app. In the process, I
discovered that a large amount of code is simply not being used.

## Automation

/ok-to-test tags="@tag.All"

### 🔍 Cypress test results
<!-- This is an auto-generated comment: Cypress test results  -->
> [!TIP]
> 🟢 🟢 🟢 All cypress tests have passed! 🎉 🎉 🎉
> Workflow run:
<https://github.com/appsmithorg/appsmith/actions/runs/10419944222>
> Commit: 86491f43aff37e34468fb7dc32722b9ef2ec60c9
> <a
href="https://internal.appsmith.com/app/cypress-dashboard/rundetails-65890b3c81d7400d08fa9ee5?branch=master&workflowId=10419944222&attempt=1"
target="_blank">Cypress dashboard</a>.
> Tags: `@tag.All`
> Spec:
> <hr>Fri, 16 Aug 2024 13:28:03 UTC
<!-- end of auto-generated comment: Cypress test results  -->


## Communication
Should the DevRel and Marketing teams inform users about this change?
- [ ] Yes
- [x] No


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

- **New Features**
- Improved precision in UI element targeting for enhanced test
reliability.
- Broadened icon options within the FilePickerComponent for greater
flexibility.

- **Improvements**
- Shifted component imports to a centralized design system for better
consistency.
- Simplified prop structures for the Button component to enhance
clarity.
- Enhanced validation utilities available for form handling and input
validation.

- **Bug Fixes**
- Enhanced robustness of element locators, reducing potential UI
interaction issues.

- **Refactor**
- Adjusted component properties to align with updated design guidelines,
promoting semantic usage.
- Consolidated exports to emphasize type definitions and utility
functions for better maintainability.

- **Chores**
- Cleaned up imports and updated code structure for improved
maintainability.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
Valera Melnikov 2024-08-16 17:23:57 +03:00 committed by GitHub
parent 4a902483df
commit c1c196efbd
59 changed files with 156 additions and 5141 deletions

View File

@ -86,7 +86,7 @@ export default {
shareUserIcons: ".t--workspace-share-user-icons",
toastMessage: "div.Toastify__toast",
uploadLogo: "//div/form/input",
removeLogo: ".remove-button a span",
removeLogo: "[data-testid=t--remove-logo]",
generalTab: "//li//span[text()='General']",
membersTab: "//li//span[text()='Members']",
cancelBtn: "//span[text()='Cancel']",
@ -105,5 +105,5 @@ export default {
noEntityFound:".no-search-results",
initialWorkspace:"[data-testid^='Untitled workspace']",
initialApplication:"[data-testid^='Untitled application']",
_entitySearchBar:"[data-testid='t--application-search-input']";
_entitySearchBar:"[data-testid='t--application-search-input']"
};

View File

@ -1,10 +0,0 @@
# usage ./create_story.sh -f <Folder name under src fodler>
while getopts f: flag
do
case "${flag}" in
f) folder=${OPTARG};;
esac
done
echo "Creating story for folder: $folder"
cat story_template.txt >> src/$folder/$folder.stories.tsx

View File

@ -5,10 +5,8 @@
"main": "src/index.ts",
"sideEffects": false,
"scripts": {
"create-story": "./create_story.sh",
"lint": "yarn g:lint",
"prettier": "yarn g:prettier",
"test:unit": "yarn g:jest"
"prettier": "yarn g:prettier"
},
"contributors": [
"Albin <albin@appsmith.com>",

View File

@ -272,7 +272,7 @@ const ServerLineIcon = importRemixIcon(
async () => import("remixicon-react/ServerLineIcon"),
);
enum Size {
export enum Size {
xxs = "xxs",
xs = "xs",
small = "small",

View File

@ -1,118 +0,0 @@
// TODO: In Phase 2, add a warn when this component doesn't have a <Router> component in it's ancestors
import type { ReactNode } from "react";
import React from "react";
import { Link, useLocation } from "react-router-dom";
import styled from "styled-components";
import Icon from "../Icon";
export interface BreadcrumbsProps {
items: {
href: string;
text: string;
}[];
}
export interface BreadcrumbProps {
children: ReactNode;
}
export const StyledBreadcrumbList = styled.ol`
list-style: none;
display: flex;
align-items: center;
font-size: 16px;
color: var(--ads-breadcrumbs-list-text-color);
margin-bottom: 23px;
.breadcrumb-separator {
color: var(--ads-breadcrumbs-separator-text-color);
margin: auto 6px;
user-select: none;
}
.t--breadcrumb-item {
&.active {
color: var(--ads-breadcrumbs-active-text-color);
font-size: 20px;
}
}
`;
function BreadcrumbSeparator({ children, ...props }: { children: ReactNode }) {
return (
<li className="breadcrumb-separator" {...props}>
{children}
</li>
);
}
function BreadcrumbItem({ children, ...props }: { children: ReactNode }) {
return (
<li className="breadcrumb-item" {...props}>
{children}
</li>
);
}
function BreadcrumbList(props: BreadcrumbProps) {
let children = React.Children.toArray(props.children);
children = children.map((child, index) => (
<BreadcrumbItem key={`breadcrumb_item${index}`}>{child}</BreadcrumbItem>
));
const lastIndex = children.length - 1;
const childrenNew = children.reduce((acc: ReactNode[], child, index) => {
const notLast = index < lastIndex;
if (notLast) {
acc.push(
child,
<BreadcrumbSeparator key={`breadcrumb_sep${index}`}>
<Icon name="right-arrow-2" />
</BreadcrumbSeparator>,
);
} else {
acc.push(child);
}
return acc;
}, []);
return (
<StyledBreadcrumbList className="t--breadcrumb-list">
{childrenNew}
</StyledBreadcrumbList>
);
}
function Breadcrumbs(props: BreadcrumbsProps) {
const { pathname } = useLocation();
return (
<BreadcrumbList>
{props.items.map(({ href, text }) =>
href === pathname ? (
<span
className={`t--breadcrumb-item ${
href === pathname ? `active` : ``
}`}
key={href}
>
{text}
</span>
) : (
<Link
className={`t--breadcrumb-item ${
href === pathname ? `active` : ``
}`}
key={href}
to={href}
>
{text}
</Link>
),
)}
</BreadcrumbList>
);
}
export default Breadcrumbs;

View File

@ -1,46 +0,0 @@
import React from "react";
import "@testing-library/jest-dom";
import { render, screen } from "@testing-library/react";
import Button, { Size } from "./index";
import { create } from "react-test-renderer";
describe("<Button /> component - render", () => {
it("renders the button component with text passed as input", () => {
render(<Button size={Size.medium} tag="button" text="Run" />);
expect(screen.getByRole("button")).toHaveTextContent("Run");
});
});
describe("<Button /> component - loading behaviour", () => {
it("calls the onclick handler when not in loading state", () => {
const fn = jest.fn();
const tree = create(
<Button
isLoading={false}
onClick={fn}
size={Size.medium}
tag="button"
text="Run"
/>,
);
const button = tree.root.findByType("button");
button.props.onClick();
expect(fn.mock.calls.length).toBe(1);
});
it("does not call the onclick handler when in loading state", () => {
const fn = jest.fn();
const tree = create(
<Button
isLoading
onClick={fn}
size={Size.medium}
tag="button"
text="Run"
/>,
);
const button = tree.root.findByType("button");
button.props.onClick();
expect(fn.mock.calls.length).toBe(0);
});
});

View File

@ -1,581 +0,0 @@
import React from "react";
import _ from "lodash";
import styled, { css } from "styled-components";
import { Variant } from "../constants/variants";
import type { CommonComponentProps } from "../types/common";
import { Classes } from "../constants/classes";
import type { IconName } from "../Icon";
import Icon, { IconSize } from "../Icon";
import Spinner from "../Spinner";
import { typography } from "../constants/typography";
const smallButton = css`
font-size: ${typography.btnSmall.fontSize}px;
font-weight: ${typography.btnSmall.fontWeight};
line-height: ${typography.btnSmall.lineHeight}px;
letter-spacing: ${typography.btnSmall.letterSpacing}px;
`;
const mediumButton = css`
font-size: ${typography.btnMedium.fontSize}px;
font-weight: ${typography.btnMedium.fontWeight};
line-height: ${typography.btnMedium.lineHeight}px;
letter-spacing: ${typography.btnMedium.letterSpacing}px;
`;
const largeButton = css`
font-size: ${typography.btnLarge.fontSize}px;
font-weight: ${typography.btnLarge.fontWeight};
line-height: ${typography.btnLarge.lineHeight}px;
letter-spacing: ${typography.btnLarge.letterSpacing}px;
`;
export enum Category {
primary = "primary",
secondary = "secondary",
tertiary = "tertiary",
}
export enum Size {
xxs = "xxs",
xs = "xs",
small = "small",
medium = "medium",
large = "large",
}
interface stateStyleType {
bgColorPrimary: string;
borderColorPrimary: string;
txtColorPrimary: string;
bgColorSecondary: string;
borderColorSecondary: string;
txtColorSecondary: string;
bgColorTertiary: string;
borderColorTertiary: string;
txtColorTertiary: string;
}
interface BtnColorType {
bgColor: string;
txtColor: string;
border: string;
outline: string;
}
interface BtnFontType {
buttonFont: any;
padding: string;
height: number;
}
export enum IconPositions {
left = "left",
right = "right",
}
export type ButtonProps = CommonComponentProps & {
onClick?: (event: React.MouseEvent<HTMLElement>) => void;
text?: string;
category?: Category;
variant?: Variant;
className?: string;
icon?: IconName;
size?: Size;
fill?: boolean;
href?: string;
tabIndex?: number;
tag?: "a" | "button";
type?: "submit" | "reset" | "button";
target?: string;
height?: string;
width?: string;
iconPosition?: IconPositions;
};
const defaultProps = {
category: Category.primary,
variant: Variant.info,
size: Size.small,
isLoading: false,
disabled: false,
fill: undefined,
tag: "a",
};
interface buttonVariant {
main: string;
light: string;
dark: string;
darker: string;
darkest: string;
}
interface ButtonColorType {
[index: string]: buttonVariant;
}
const ButtonColors: ButtonColorType = {
info: {
main: "var(--ads-color-brand)",
light: "var(--ads-old-color-hot-cinnamon)",
dark: "var(--ads-color-brand-hover)",
darker: "var(--ads-color-brand-disabled)",
darkest: "var(--ads-old-color-pot-pourri)",
},
success: {
main: "var(--ads-old-color-jade)",
light: "var(--ads-old-color-fun-green)",
dark: "var(--ads-old-color-fun-green-2)",
darker: "var(--ads-old-color-granny-apple)",
darkest: "var(--ads-old-color-foam)",
},
warning: {
main: "var(--ads-old-color-sun)",
light: "var(--ads-old-color-yellow-sea)",
dark: "var(--ads-old-color-yellow-sea)",
darker: "var(--ads-old-color-champagne)",
darkest: "var(--ads-old-color-early-dawn)",
},
danger: {
main: "var(--ads-old-color-pomegranate)",
light: "var(--ads-old-color-milano-red)",
dark: "var(--ads-old-color-milano-red-2)",
darker: "var(--ads-old-color-cinderella)",
darkest: "var(--ads-old-color-fair-pink)",
},
secondary: {
main: "var(--ads-old-color-mid-gray)",
light: "var(--ads-old-color-gray-10)",
dark: "var(--ads-color-black-5)",
darker: "var(--ads-old-color-gallery)",
darkest: "var(--ads-color-black-450)",
},
tertiary: {
main: "var(--ads-old-color-mid-gray)",
light: "var(--ads-old-color-gray-10)",
dark: "var(--ads-color-black-5)",
darker: "var(--ads-old-color-gallery)",
darkest: "var(--ads-color-black-450)",
},
};
const WhiteTextVariants = [Variant.danger, Variant.warning, Variant.success];
const getDisabledStyles = (props: ButtonProps) => {
const variant = props.variant ?? defaultProps.variant;
const category = props.category ?? defaultProps.category;
const stylesByCategory = {
[Category.primary]: {
txtColorPrimary: "var(--ads-old-color-gray-7)",
bgColorPrimary: ButtonColors[variant].darker,
borderColorPrimary: ButtonColors[variant].darker,
},
[Category.secondary]: {
txtColorSecondary: "var(--ads-color-black-500)",
bgColorSecondary: "var(--ads-color-black-50)",
borderColorSecondary: "var(--ads-color-black-300)",
},
[Category.tertiary]: {
txtColorTertiary: "var(--ads-color-black-500)",
bgColorTertiary: "var(--ads-color-black-0)",
borderColorTertiary: "transparent",
},
};
return stylesByCategory[category];
};
const getMainStateStyles = (props: ButtonProps) => {
const variant = props.variant ?? defaultProps.variant;
const category = props.category ?? defaultProps.category;
const stylesByCategory = {
[Category.primary]: {
bgColorPrimary: ButtonColors[variant].main,
borderColorPrimary: ButtonColors[variant].main,
txtColorPrimary:
WhiteTextVariants.indexOf(variant) === -1
? "var(--ads-color-brand-text)"
: "var(--ads-color-black-0)",
},
[Category.secondary]: {
bgColorSecondary: "var(--ads-color-black-0)",
borderColorSecondary: "var(--ads-color-black-300)",
txtColorSecondary: "var(--ads-color-black-700)",
},
[Category.tertiary]: {
bgColorTertiary: "var(--ads-color-black-0)",
borderColorTertiary: "transparent",
txtColorTertiary: "var(--ads-color-black-700)",
},
};
return stylesByCategory[category];
};
const getHoverStateStyles = (props: ButtonProps) => {
const variant = props.variant ?? defaultProps.variant;
const category = props.category ?? defaultProps.category;
const stylesByCategory = {
[Category.primary]: {
bgColorPrimary: ButtonColors[variant].dark,
txtColorPrimary:
WhiteTextVariants.indexOf(variant) === -1
? "var(--ads-color-brand-text)"
: "var(--ads-color-black-0)",
borderColorPrimary: ButtonColors[variant].dark,
},
[Category.secondary]: {
bgColorSecondary: "var(--ads-color-black-50)",
txtColorSecondary: "var(--ads-color-black-700)",
borderColorSecondary: "var(--ads-color-black-300)",
},
[Category.tertiary]: {
bgColorTertiary: "var(--ads-color-black-100)",
txtColorTertiary: "var(--ads-color-black-700)",
borderColorTertiary: "transparent",
},
};
return stylesByCategory[category];
};
const getActiveStateStyles = (props: ButtonProps) => {
const variant = props.variant ?? defaultProps.variant;
const category = props.category ?? defaultProps.category;
const stylesByCategory = {
[Category.primary]: {
bgColorPrimary: ButtonColors[variant].dark,
borderColorPrimary: ButtonColors[variant].main,
txtColorPrimary:
WhiteTextVariants.indexOf(variant) === -1
? "var(--ads-color-brand-text)"
: "var(--ads-color-black-0)",
},
[Category.secondary]: {
bgColorSecondary: "var(--ads-color-black-100)",
borderColorSecondary: "var(--ads-color-black-600)",
txtColorSecondary: "var(--ads-color-black-800)",
},
[Category.tertiary]: {
bgColorTertiary: "var(--ads-color-black-200)",
borderColorTertiary: "transparent",
txtColorTertiary: "var(--ads-color-black-800)",
},
};
return stylesByCategory[category];
};
const stateStyles = (props: ButtonProps, stateArg: string): stateStyleType => {
const styles = {
bgColorPrimary: "",
borderColorPrimary: "",
txtColorPrimary: "",
bgColorSecondary: "",
borderColorSecondary: "",
txtColorSecondary: "",
bgColorTertiary: "",
borderColorTertiary: "",
txtColorTertiary: "",
};
const state =
props.isLoading || props.disabled
? "disabled"
: (stateArg as keyof typeof stylesByState);
const stylesByState = {
disabled: getDisabledStyles(props),
main: getMainStateStyles(props),
hover: getHoverStateStyles(props),
active: getActiveStateStyles(props),
};
return {
...styles,
...stylesByState[state],
};
};
const btnColorStyles = (props: ButtonProps, state: string): BtnColorType => {
let bgColor = "",
txtColor = "",
border = "",
outline = "";
switch (props.category) {
case Category.primary:
bgColor = stateStyles(props, state).bgColorPrimary;
txtColor = stateStyles(props, state).txtColorPrimary;
border = `1.2px solid ${stateStyles(props, state).borderColorPrimary}`;
break;
case Category.secondary:
bgColor = stateStyles(props, state).bgColorSecondary;
txtColor = stateStyles(props, state).txtColorSecondary;
border = `1.2px solid ${stateStyles(props, state).borderColorSecondary}`;
outline = "2px solid var(--ads-color-blue-150)";
break;
case Category.tertiary:
bgColor = stateStyles(props, state).bgColorTertiary;
txtColor = stateStyles(props, state).txtColorTertiary;
border = `1.2px solid ${stateStyles(props, state).borderColorTertiary}`;
outline = "2px solid var(--ads-color-blue-150)";
break;
}
return { bgColor, txtColor, border, outline };
};
const getPaddingBySize = (props: ButtonProps) => {
const paddingBySize = {
[Size.small]: `0px var(--ads-spaces-3)`,
[Size.medium]: `0px var(--ads-spaces-7)`,
[Size.large]: `0px 26px`,
};
const paddingBySizeForJustIcon = {
[Size.small]: `0px var(--ads-spaces-1)`,
[Size.medium]: `0px var(--ads-spaces-2)`,
[Size.large]: `0px var(--ads-spaces-3)`,
};
const isIconOnly = !props.text && props.icon;
const paddingConfig = isIconOnly ? paddingBySizeForJustIcon : paddingBySize;
const iSizeInConfig =
// @ts-expect-error fix this the next time the file is edited
Object.keys(paddingConfig).indexOf(props.size != null || "") !== -1;
const size: any =
props.size != null && iSizeInConfig ? props.size : Size.small;
return paddingConfig[size as keyof typeof paddingConfig];
};
const getHeightBySize = (props: ButtonProps) => {
const heightBySize = {
[Size.small]: 20,
[Size.medium]: 30,
[Size.large]: 38,
};
const iSizeInConfig =
// @ts-expect-error fix this the next time the file is edited
Object.keys(heightBySize).indexOf(props.size != null || "") !== -1;
const size: any =
props.size != null && iSizeInConfig ? props.size : Size.small;
return heightBySize[size as keyof typeof heightBySize];
};
const getBtnFontBySize = (props: ButtonProps) => {
const fontBySize = {
[Size.small]: smallButton,
[Size.medium]: mediumButton,
[Size.large]: largeButton,
};
const iSizeInConfig =
// @ts-expect-error fix this the next time the file is edited
Object.keys(fontBySize).indexOf(props.size != null || "") !== -1;
const size: any =
props.size != null && iSizeInConfig ? props.size : Size.small;
return fontBySize[size as keyof typeof fontBySize];
};
const btnFontStyles = (props: ButtonProps): BtnFontType => {
const padding = getPaddingBySize(props);
const height = getHeightBySize(props);
const buttonFont = getBtnFontBySize(props);
return { buttonFont, padding, height };
};
const ButtonStyles = css<ButtonProps>`
user-select: none;
width: ${(props) =>
props.width ? props.width : props.fill ? "100%" : "auto"};
height: ${(props) => props.height || btnFontStyles(props).height}px;
border: none;
text-decoration: none;
outline: none;
text-transform: uppercase;
background-color: ${(props) => btnColorStyles(props, "main").bgColor};
color: ${(props) => btnColorStyles(props, "main").txtColor};
border: ${(props) => btnColorStyles(props, "main").border};
border-radius: 0;
${(props) => btnFontStyles(props).buttonFont};
padding: ${(props: ButtonProps) => btnFontStyles(props).padding};
.${Classes.ICON}:not([name="no-response"]) {
svg {
fill: ${(props: ButtonProps) => btnColorStyles(props, "main").txtColor};
}
}
&,
& * {
cursor: ${(props) =>
props.isLoading || props.disabled ? `not-allowed` : `pointer`};
}
&:hover {
text-decoration: none;
background-color: ${(props: ButtonProps) =>
btnColorStyles(props, "hover").bgColor};
color: ${(props: ButtonProps) => btnColorStyles(props, "hover").txtColor};
border: ${(props: ButtonProps) => btnColorStyles(props, "hover").border};
.${Classes.ICON} {
fill: ${(props: ButtonProps) => btnColorStyles(props, "hover").txtColor};
}
}
&:focus-visible {
outline: ${(props: ButtonProps) => btnColorStyles(props, "active").outline};
outline-offset: 0px;
}
font-style: normal;
&:active {
background-color: ${(props: ButtonProps) =>
btnColorStyles(props, "active").bgColor};
color: ${(props: ButtonProps) => btnColorStyles(props, "active").txtColor};
border: ${(props: ButtonProps) => btnColorStyles(props, "active").border};
.${Classes.ICON} {
fill: ${(props: ButtonProps) => btnColorStyles(props, "active").txtColor};
}
}
display: flex;
align-items: center;
justify-content: center;
position: relative;
.${Classes.SPINNER} {
position: absolute;
left: 0;
right: 0;
margin-left: auto;
margin-right: auto;
circle {
stroke: var(--ads-old-color-gray-7);
}
}
.t--right-icon {
margin-left: var(--ads-spaces-1);
}
.t--left-icon {
margin-right: var(--ads-spaces-1);
}
`;
export const StyledButton = styled("button")`
${ButtonStyles}
`;
const StyledLinkButton = styled("a")`
${ButtonStyles}
`;
export const VisibilityWrapper = styled.div`
visibility: hidden;
`;
const IconSizeProp = (size?: Size) => {
const sizeMapping = {
[Size.xxs]: IconSize.XXS,
[Size.xs]: IconSize.XS,
[Size.small]: IconSize.SMALL,
[Size.medium]: IconSize.MEDIUM,
[Size.large]: IconSize.LARGE,
};
return size != null ? sizeMapping[size] : IconSize.SMALL;
};
function TextLoadingState({ text }: { text?: string }) {
return <VisibilityWrapper>{text}</VisibilityWrapper>;
}
function IconLoadingState({ icon, size }: { size?: Size; icon?: IconName }) {
return <Icon invisible name={icon} size={IconSizeProp(size)} />;
}
const getIconContent = (props: ButtonProps, rightPosFlag = false) =>
props.icon ? (
props.isLoading ? (
<IconLoadingState {...props} />
) : (
<Icon
className={rightPosFlag ? "t--right-icon" : "t--left-icon"}
name={props.icon}
size={IconSizeProp(props.size)}
/>
)
) : null;
const getTextContent = (props: ButtonProps) =>
props.text ? (
props.isLoading ? (
<TextLoadingState text={props.text} />
) : (
props.text
)
) : null;
const getButtonContent = (props: ButtonProps) => {
const iconPos =
props.iconPosition != null
? props.iconPosition
: props.tag === "a"
? IconPositions.right
: IconPositions.left;
return (
<>
{iconPos === IconPositions.left && getIconContent(props)}
<span>{getTextContent(props)}</span>
{iconPos === IconPositions.right && getIconContent(props, true)}
{props.isLoading ? <Spinner size={IconSizeProp(props.size)} /> : null}
</>
);
};
function ButtonComponent(props: ButtonProps) {
const { className, cypressSelector, isLoading, onClick } = props;
const filteredProps = _.omit(props, ["fill"]);
return (
<StyledButton
className={className}
data-cy={cypressSelector}
{...filteredProps}
onClick={(e: React.MouseEvent<HTMLElement>) =>
onClick && !isLoading && onClick(e)
}
>
{getButtonContent(props)}
</StyledButton>
);
}
function LinkButtonComponent(props: ButtonProps) {
const { className, cypressSelector, href, onClick } = props;
const filteredProps = _.omit(props, ["fill"]);
return (
<StyledLinkButton
className={className}
data-cy={cypressSelector}
href={href}
{...filteredProps}
onClick={(e: React.MouseEvent<HTMLElement>) =>
!props.disabled && onClick && onClick(e)
}
>
{getButtonContent(props)}
</StyledLinkButton>
);
}
function Button(props: ButtonProps) {
return props.tag === "button" ? (
<ButtonComponent {...props} />
) : (
<LinkButtonComponent {...props} />
);
}
export default Button;
Button.defaultProps = defaultProps;

View File

@ -2,8 +2,8 @@ import type { ReactNode, PropsWithChildren } from "react";
import React, { useState, useEffect } from "react";
import styled from "styled-components";
import { Dialog, Classes } from "@blueprintjs/core";
import type { IconName } from "../Icon";
import Icon, { IconSize } from "../Icon";
import type { IconNames } from "@appsmith/ads";
import { Icon } from "@appsmith/ads";
import { typography } from "../constants/typography";
type DialogProps = PropsWithChildren<{
@ -115,7 +115,7 @@ interface DialogComponentProps {
title?: string;
headerIcon?: {
clickable?: boolean;
name: IconName;
name: IconNames;
fillColor?: string;
hoverColor?: string;
bgColor?: string;
@ -156,11 +156,9 @@ export function DialogComponent(props: DialogComponentProps) {
const headerIcon = props.headerIcon ? (
<HeaderIconWrapper bgColor={props.headerIcon.bgColor}>
<Icon
clickable={props.headerIcon?.clickable}
fillColor={props.headerIcon.fillColor}
hoverFillColor={props.headerIcon.hoverColor}
color={props.headerIcon.fillColor}
name={props.headerIcon.name}
size={IconSize.XL}
size="lg"
/>
</HeaderIconWrapper>
) : null;

View File

@ -12,7 +12,7 @@ import { getTypographyByKey } from "../constants/typography";
// eslint-disable-next-line @typescript-eslint/no-restricted-imports
import { ReactComponent as ProfileImagePlaceholder } from "../assets/icons/others/profile-placeholder.svg";
import Icon, { IconSize } from "../Icon";
import { Spinner } from "@appsmith/ads";
interface Props {
onChange: (file: File) => void;
@ -241,7 +241,7 @@ export default function DisplayImageUpload({
<Suspense
fallback={
<SpinnerContainer>
<Icon name={"loader"} size={IconSize.XL} />
<Spinner size="lg" />
</SpinnerContainer>
}
>

View File

@ -5,7 +5,8 @@ import {
} from "@blueprintjs/core";
import styled from "styled-components";
import type { noop } from "lodash";
import { Icon, IconSize, Text, TextType } from "../index";
import { Spinner } from "@appsmith/ads";
import { Text, TextType } from "../index";
import type { CommonComponentProps } from "../types/common";
export enum EditInteractionKind {
@ -116,14 +117,6 @@ const TextContainer = styled.div<{
}
`;
const IconWrapper = styled.div`
width: var(--ads-spaces-15);
padding-right: var(--ads-spaces-5);
display: flex;
align-items: center;
justify-content: flex-end;
`;
export const EditableTextSubComponent = React.forwardRef(
(props: EditableTextSubComponentProps, ref: any) => {
const {
@ -224,17 +217,6 @@ export const EditableTextSubComponent = React.forwardRef(
[inputValidation, onTextChanged],
);
const iconName =
!isEditing &&
savingState === SavingState.NOT_STARTED &&
!props.hideEditIcon
? "pencil-line"
: !isEditing && savingState === SavingState.SUCCESS
? "success"
: savingState === SavingState.ERROR || (isEditing && !!isInvalid)
? "error"
: undefined;
return (
<>
<TextContainer
@ -258,19 +240,7 @@ export const EditableTextSubComponent = React.forwardRef(
value={value}
/>
{savingState === SavingState.STARTED ? (
<IconWrapper className="icon-wrapper">
<Icon name={"loader"} size={IconSize.XL} />
</IconWrapper>
) : value && !props.hideEditIcon ? (
<IconWrapper className="icon-wrapper">
<Icon
fillColor="var(--ads-v2-color-fg)"
name={iconName}
size={IconSize.XL}
/>
</IconWrapper>
) : null}
{savingState === SavingState.STARTED ? <Spinner size="md" /> : null}
</TextContainer>
{isEditing && !!isInvalid ? (
<Text className="error-message" type={TextType.P2}>

View File

@ -3,9 +3,9 @@ import styled from "styled-components";
import type { DropTargetMonitor } from "react-dnd";
import { DndProvider, useDrop } from "react-dnd";
import HTML5Backend, { NativeTypes } from "react-dnd-html5-backend";
import Button, { Category, IconPositions, Size } from "../Button";
import type { IconName } from "../Icon";
import Icon, { IconSize } from "../Icon";
import { Button } from "@appsmith/ads";
import type { IconNames } from "@appsmith/ads";
import { Icon } from "@appsmith/ads";
import Text, { TextType } from "../Text";
import { toast } from "@appsmith/ads";
import TooltipComponent from "../Tooltip";
@ -14,7 +14,6 @@ import {
ERROR_FILE_TOO_LARGE,
REMOVE_FILE_TOOL_TIP,
} from "../constants/messages";
import { Classes } from "../constants/classes";
import { importSvg } from "../utils/icon-loadables";
const UploadSuccessIcon = importSvg(
@ -51,7 +50,7 @@ export interface FilePickerProps {
logoUploadError?: string;
fileType: FileType;
delayedUpload?: boolean;
uploadIcon?: IconName;
uploadIcon?: IconNames;
title?: string;
description?: string;
containerClickable?: boolean; // when container is clicked, it'll work as button
@ -172,20 +171,10 @@ export const ContainerDiv = styled.div<{
bottom: 0;
border-radius: 0 0 var(--ads-v2-border-radius) var(--ads-v2-border-radius);
}
a {
.ads-v2-button {
width: 110px;
margin: var(--ads-spaces-13) var(--ads-spaces-3) var(--ads-spaces-3) auto;
color: var(--ads-v2-color-fg);
border-radius: var(--ads-v2-border-radius);
border-color: var(--ads-v2-color-border);
text-transform: capitalize;
background: var(--ads-v2-color-bg);
.${Classes.ICON} {
margin-right: calc(var(--ads-spaces-2) - 1px);
}
&:hover {
background: var(--ads-v2-color-bg-subtle);
}
display: flex;
}
}
@ -407,7 +396,7 @@ function FilePickerComponent(props: FilePickerProps) {
<div className="button-wrapper" ref={fileContainerRef}>
<UploadIconWrapper>
<Icon
fillColor={
color={
props.iconFillColor ||
"var(--ads-file-picker-v2-upload-icon-fill-color)"
}
@ -434,12 +423,13 @@ function FilePickerComponent(props: FilePickerProps) {
/>
{!props.containerClickable && (
<Button
category={Category.secondary}
className="browse-button"
kind="secondary"
onClick={(el: React.MouseEvent<HTMLElement>) => ButtonClick(el)}
size={Size.medium}
text="Browse"
/>
size="sm"
>
Browse
</Button>
)}
</form>
</div>
@ -466,13 +456,14 @@ function FilePickerComponent(props: FilePickerProps) {
<div className="remove-button">
<div className="overlay" />
<Button
category={Category.secondary}
icon="delete"
iconPosition={IconPositions.left}
data-testid="t--remove-logo"
kind="secondary"
onClick={() => removeFile()}
size={Size.medium}
text="Remove"
/>
size="sm"
startIcon="delete"
>
Remove
</Button>
</div>
</>
);
@ -493,7 +484,7 @@ function FilePickerComponent(props: FilePickerProps) {
</Text>
<TooltipComponent content={REMOVE_FILE_TOOL_TIP()} position="top">
<IconWrapper className="icon-wrapper" onClick={() => removeFile()}>
<Icon name="close" size={IconSize.XL} />
<Icon name="close" size="lg" />
</IconWrapper>
</TooltipComponent>
</div>

View File

@ -1,6 +1,6 @@
import React, { useState } from "react";
import styled from "styled-components";
import Icon, { IconSize } from "../Icon";
import { Icon } from "@appsmith/ads";
import Text, { TextType } from "../Text";
import { Classes } from "../constants/classes";
@ -60,7 +60,7 @@ function GifPlayer(props: GifPlayerProps) {
<Overlay />
<img src={props.thumbnail} />
<PlayButton>
<Icon name="play" size={IconSize.XXXL} />
<Icon name="play" size="lg" />
<Text color={"var(--ads-v2-color-fg)"} type={TextType.P3}>
Click to play
</Text>

View File

@ -1,982 +0,0 @@
import type { Ref } from "react";
import React, { forwardRef } from "react";
import styled from "styled-components";
import type { CommonComponentProps } from "../types/common";
import { Classes } from "../constants/classes";
import { noop } from "lodash";
import Spinner from "../Spinner";
import { ControlIcons } from "../ControlIcons";
import { importRemixIcon, importSvg } from "../utils/icon-loadables";
const ClearInterval = importSvg(
async () => import("../assets/icons/action/clearInterval.svg"),
);
const ClearStore = importSvg(
async () => import("../assets/icons/action/clearStore.svg"),
);
const CopyToClipboard = importSvg(
async () => import("../assets/icons/action/copyToClipboard.svg"),
);
const DownloadAction = importSvg(
async () => import("../assets/icons/action/download.svg"),
);
const ExecuteJs = importSvg(
async () => import("../assets/icons/action/executeJs.svg"),
);
const ExecuteQuery = importSvg(
async () => import("../assets/icons/action/executeQuery.svg"),
);
const GetGeolocation = importSvg(
async () => import("../assets/icons/action/getGeolocation.svg"),
);
const Modal = importSvg(async () => import("../assets/icons/action/modal.svg"));
const NavigateTo = importSvg(
async () => import("../assets/icons/action/navigateTo.svg"),
);
const RemoveStore = importSvg(
async () => import("../assets/icons/action/removeStore.svg"),
);
const ResetWidget = importSvg(
async () => import("../assets/icons/action/resetWidget.svg"),
);
const SetInterval = importSvg(
async () => import("../assets/icons/action/setInterval.svg"),
);
const ShowAlert = importSvg(
async () => import("../assets/icons/action/showAlert.svg"),
);
const StopWatchGeolocation = importSvg(
async () => import("../assets/icons/action/stopWatchGeolocation.svg"),
);
const StoreValue = importSvg(
async () => import("../assets/icons/action/storeValue.svg"),
);
const WatchGeolocation = importSvg(
async () => import("../assets/icons/action/watchGeolocation.svg"),
);
const RunAPI = importSvg(
async () => import("../assets/icons/action/runApi.svg"),
);
const PostMessage = importSvg(
async () => import("../assets/icons/action/postMessage.svg"),
);
const NoAction = importSvg(
async () => import("../assets/icons/action/noAction.svg"),
);
const BookLineIcon = importSvg(
async () => import("../assets/icons/ads/book-open-line.svg"),
);
const BugIcon = importSvg(async () => import("../assets/icons/ads/bug.svg"));
const CancelIcon = importSvg(
async () => import("../assets/icons/ads/cancel.svg"),
);
const CrossIcon = importSvg(
async () => import("../assets/icons/ads/cross.svg"),
);
const Fork2Icon = importSvg(
async () => import("../assets/icons/ads/fork-2.svg"),
);
const OpenIcon = importSvg(async () => import("../assets/icons/ads/open.svg"));
const UserIcon = importSvg(async () => import("../assets/icons/ads/user.svg"));
const GeneralIcon = importSvg(
async () => import("../assets/icons/ads/general.svg"),
);
const BillingIcon = importSvg(
async () => import("../assets/icons/ads/billing.svg"),
);
const ErrorIcon = importSvg(
async () => import("../assets/icons/ads/error.svg"),
);
const ShineIcon = importSvg(
async () => import("../assets/icons/ads/shine.svg"),
);
const SuccessIcon = importSvg(
async () => import("../assets/icons/ads/success.svg"),
);
const CloseIcon = importSvg(
async () => import("../assets/icons/ads/close.svg"),
);
const WarningTriangleIcon = importSvg(
async () => import("../assets/icons/ads/warning-triangle.svg"),
);
const ShareIcon2 = importSvg(
async () => import("../assets/icons/ads/share-2.svg"),
);
const InviteUserIcon = importSvg(
async () => import("../assets/icons/ads/invite-users.svg"),
);
const ManageIcon = importSvg(
async () => import("../assets/icons/ads/manage.svg"),
);
const ArrowLeft = importSvg(
async () => import("../assets/icons/ads/arrow-left.svg"),
);
const ChevronLeft = importSvg(
async () => import("../assets/icons/ads/chevron_left.svg"),
);
const LinkIcon = importSvg(async () => import("../assets/icons/ads/link.svg"));
const NoResponseIcon = importSvg(
async () => import("../assets/icons/ads/no-response.svg"),
);
const LightningIcon = importSvg(
async () => import("../assets/icons/ads/lightning.svg"),
);
const TrendingFlat = importSvg(
async () => import("../assets/icons/ads/trending-flat.svg"),
);
const PlayIcon = importSvg(async () => import("../assets/icons/ads/play.svg"));
const DesktopIcon = importSvg(
async () => import("../assets/icons/ads/desktop.svg"),
);
const WandIcon = importSvg(async () => import("../assets/icons/ads/wand.svg"));
const MobileIcon = importSvg(
async () => import("../assets/icons/ads/mobile.svg"),
);
const TabletIcon = importSvg(
async () => import("../assets/icons/ads/tablet.svg"),
);
const TabletLandscapeIcon = importSvg(
async () => import("../assets/icons/ads/tablet-landscape.svg"),
);
const FluidIcon = importSvg(
async () => import("../assets/icons/ads/fluid.svg"),
);
const CardContextMenu = importSvg(
async () => import("../assets/icons/ads/card-context-menu.svg"),
);
const SendButton = importSvg(
async () => import("../assets/icons/comments/send-button.svg"),
);
const Pin = importSvg(async () => import("../assets/icons/comments/pin.svg"));
const TrashOutline = importSvg(
async () => import("../assets/icons/form/trash.svg"),
);
const ReadPin = importSvg(
async () => import("../assets/icons/comments/read-pin.svg"),
);
const UnreadPin = importSvg(
async () => import("../assets/icons/comments/unread-pin.svg"),
);
const Chat = importSvg(async () => import("../assets/icons/comments/chat.svg"));
const Unpin = importSvg(
async () => import("../assets/icons/comments/unpinIcon.svg"),
);
const Reaction = importSvg(
async () => import("../assets/icons/comments/reaction.svg"),
);
const Reaction2 = importSvg(
async () => import("../assets/icons/comments/reaction-2.svg"),
);
const Upload = importSvg(async () => import("../assets/icons/ads/upload.svg"));
const ArrowForwardIcon = importSvg(
async () => import("../assets/icons/control/arrow_forward.svg"),
);
const DoubleArrowRightIcon = importSvg(
async () => import("../assets/icons/ads/double-arrow-right.svg"),
);
const CapSolidIcon = importSvg(
async () => import("../assets/icons/control/cap_solid.svg"),
);
const CapDotIcon = importSvg(
async () => import("../assets/icons/control/cap_dot.svg"),
);
const LineDottedIcon = importSvg(
async () => import("../assets/icons/control/line_dotted.svg"),
);
const LineDashedIcon = importSvg(
async () => import("../assets/icons/control/line_dashed.svg"),
);
const TableIcon = importSvg(
async () => import("../assets/icons/ads/tables.svg"),
);
const ColumnIcon = importSvg(
async () => import("../assets/icons/ads/column.svg"),
);
const GearIcon = importSvg(async () => import("../assets/icons/ads/gear.svg"));
const UserV2Icon = importSvg(
async () => import("../assets/icons/ads/user-v2.svg"),
);
const SupportIcon = importSvg(
async () => import("../assets/icons/ads/support.svg"),
);
const Snippet = importSvg(
async () => import("../assets/icons/ads/snippet.svg"),
);
const WorkspaceIcon = importSvg(
async () => import("../assets/icons/ads/workspaceIcon.svg"),
);
const SettingIcon = importSvg(
async () => import("../assets/icons/control/settings.svg"),
);
const DropdownIcon = importSvg(
async () => import("../assets/icons/ads/dropdown.svg"),
);
const ChatIcon = importSvg(
async () => import("../assets/icons/ads/app-icons/chat.svg"),
);
const JsIcon = importSvg(async () => import("../assets/icons/ads/js.svg"));
const ExecuteIcon = importSvg(
async () => import("../assets/icons/ads/execute.svg"),
);
const PackageIcon = importSvg(
async () => import("../assets/icons/ads/package.svg"),
);
const DevicesIcon = importSvg(
async () => import("../assets/icons/ads/devices.svg"),
);
const GridIcon = importSvg(async () => import("../assets/icons/ads/grid.svg"));
const HistoryLineIcon = importSvg(
async () => import("../assets/icons/ads/history-line.svg"),
);
const SuccessLineIcon = importSvg(
async () => import("../assets/icons/ads/success-line.svg"),
);
const ErrorLineIcon = importSvg(
async () => import("../assets/icons/ads/error-line.svg"),
);
const UpdatesIcon = importSvg(
async () => import("../assets/icons/help/updates.svg"),
);
// remix icons
const AddMoreIcon = importRemixIcon(
async () => import("remixicon-react/AddCircleLineIcon"),
);
const AddMoreFillIcon = importRemixIcon(
async () => import("remixicon-react/AddCircleFillIcon"),
);
const ArrowLeftRightIcon = importRemixIcon(
async () => import("remixicon-react/ArrowLeftRightLineIcon"),
);
const ArrowDownLineIcon = importRemixIcon(
async () => import("remixicon-react/ArrowDownLineIcon"),
);
const BookIcon = importRemixIcon(
async () => import("remixicon-react/BookOpenLineIcon"),
);
const BugLineIcon = importRemixIcon(
async () => import("remixicon-react/BugLineIcon"),
);
const ChevronRight = importRemixIcon(
async () => import("remixicon-react/ArrowRightSFillIcon"),
);
const CheckLineIcon = importRemixIcon(
async () => import("remixicon-react/CheckLineIcon"),
);
const CloseLineIcon = importRemixIcon(
async () => import("remixicon-react/CloseLineIcon"),
);
const CloseCircleIcon = importRemixIcon(
async () => import("remixicon-react/CloseCircleFillIcon"),
);
const CloseCircleLineIcon = importRemixIcon(
async () => import("remixicon-react/CloseCircleLineIcon"),
);
const CloudOfflineIcon = importRemixIcon(
async () => import("remixicon-react/CloudOffLineIcon"),
);
const CommentContextMenu = importRemixIcon(
async () => import("remixicon-react/More2FillIcon"),
);
const More2FillIcon = importRemixIcon(
async () => import("remixicon-react/More2FillIcon"),
);
const CompassesLine = importRemixIcon(
async () => import("remixicon-react/CompassesLineIcon"),
);
const ContextMenuIcon = importRemixIcon(
async () => import("remixicon-react/MoreFillIcon"),
);
const CreateNewIcon = importRemixIcon(
async () => import("remixicon-react/AddLineIcon"),
);
const Database2Line = importRemixIcon(
async () => import("remixicon-react/Database2LineIcon"),
);
const DatasourceIcon = importRemixIcon(
async () => import("remixicon-react/CloudFillIcon"),
);
const DeleteBin7 = importRemixIcon(
async () => import("remixicon-react/DeleteBin7LineIcon"),
);
const DiscordIcon = importRemixIcon(
async () => import("remixicon-react/DiscordLineIcon"),
);
const DownArrow = importRemixIcon(
async () => import("remixicon-react/ArrowDownSFillIcon"),
);
const Download = importRemixIcon(
async () => import("remixicon-react/DownloadCloud2LineIcon"),
);
const DuplicateIcon = importRemixIcon(
async () => import("remixicon-react/FileCopyLineIcon"),
);
const EditIcon = importRemixIcon(
async () => import("remixicon-react/PencilFillIcon"),
);
const EditLineIcon = importRemixIcon(
async () => import("remixicon-react/EditLineIcon"),
);
const EditUnderlineIcon = importRemixIcon(
async () => import("remixicon-react/EditLineIcon"),
);
const Emoji = importRemixIcon(
async () => import("remixicon-react/EmotionLineIcon"),
);
const ExpandMore = importRemixIcon(
async () => import("remixicon-react/ArrowDownSLineIcon"),
);
const DownArrowIcon = importRemixIcon(
async () => import("remixicon-react/ArrowDownSLineIcon"),
);
const ExpandLess = importRemixIcon(
async () => import("remixicon-react/ArrowUpSLineIcon"),
);
const EyeOn = importRemixIcon(
async () => import("remixicon-react/EyeLineIcon"),
);
const EyeOff = importRemixIcon(
async () => import("remixicon-react/EyeOffLineIcon"),
);
const FileTransfer = importRemixIcon(
async () => import("remixicon-react/FileTransferLineIcon"),
);
const FileLine = importRemixIcon(
async () => import("remixicon-react/FileLineIcon"),
);
const Filter = importRemixIcon(
async () => import("remixicon-react/Filter2FillIcon"),
);
const ForbidLineIcon = importRemixIcon(
async () => import("remixicon-react/ForbidLineIcon"),
);
const GitMerge = importRemixIcon(
async () => import("remixicon-react/GitMergeLineIcon"),
);
const GitCommit = importRemixIcon(
async () => import("remixicon-react/GitCommitLineIcon"),
);
const GitPullRequst = importRemixIcon(
async () => import("remixicon-react/GitPullRequestLineIcon"),
);
const GlobalLineIcon = importRemixIcon(
async () => import("remixicon-react/GlobalLineIcon"),
);
const GuideIcon = importRemixIcon(
async () => import("remixicon-react/GuideFillIcon"),
);
const HelpIcon = importRemixIcon(
async () => import("remixicon-react/QuestionMarkIcon"),
);
const LightbulbFlashLine = importRemixIcon(
async () => import("remixicon-react/LightbulbFlashLineIcon"),
);
const LinksLineIcon = importRemixIcon(
async () => import("remixicon-react/LinksLineIcon"),
);
const InfoIcon = importRemixIcon(
async () => import("remixicon-react/InformationLineIcon"),
);
const KeyIcon = importRemixIcon(
async () => import("remixicon-react/Key2LineIcon"),
);
const LeftArrowIcon2 = importRemixIcon(
async () => import("remixicon-react/ArrowLeftSLineIcon"),
);
const Link2 = importRemixIcon(async () => import("remixicon-react/LinkIcon"));
const LeftArrowIcon = importRemixIcon(
async () => import("remixicon-react/ArrowLeftLineIcon"),
);
const NewsPaperLine = importRemixIcon(
async () => import("remixicon-react/NewspaperLineIcon"),
);
const OvalCheck = importRemixIcon(
async () => import("remixicon-react/CheckboxCircleLineIcon"),
);
const OvalCheckFill = importRemixIcon(
async () => import("remixicon-react/CheckboxCircleFillIcon"),
);
const Pin3 = importRemixIcon(
async () => import("remixicon-react/Pushpin2FillIcon"),
);
const PlayCircleLineIcon = importRemixIcon(
async () => import("remixicon-react/PlayCircleLineIcon"),
);
const QueryIcon = importRemixIcon(
async () => import("remixicon-react/CodeSSlashLineIcon"),
);
const RemoveIcon = importRemixIcon(
async () => import("remixicon-react/SubtractLineIcon"),
);
const RightArrowIcon = importRemixIcon(
async () => import("remixicon-react/ArrowRightLineIcon"),
);
const RightArrowIcon2 = importRemixIcon(
async () => import("remixicon-react/ArrowRightSLineIcon"),
);
const RocketIcon = importRemixIcon(
async () => import("remixicon-react/RocketLineIcon"),
);
const SearchIcon = importRemixIcon(
async () => import("remixicon-react/SearchLineIcon"),
);
const SortAscIcon = importRemixIcon(
async () => import("remixicon-react/SortAscIcon"),
);
const SortDescIcon = importRemixIcon(
async () => import("remixicon-react/SortDescIcon"),
);
const ShareBoxLineIcon = importRemixIcon(
async () => import("remixicon-react/ShareBoxLineIcon"),
);
const ShareBoxFillIcon = importRemixIcon(
async () => import("remixicon-react/ShareBoxFillIcon"),
);
const ShareForwardIcon = importRemixIcon(
async () => import("remixicon-react/ShareForwardFillIcon"),
);
const Trash = importRemixIcon(
async () => import("remixicon-react/DeleteBinLineIcon"),
);
const UpArrow = importRemixIcon(
async () => import("remixicon-react/ArrowUpSFillIcon"),
);
const WarningIcon = importRemixIcon(
async () => import("remixicon-react/ErrorWarningFillIcon"),
);
const WarningLineIcon = importRemixIcon(
async () => import("remixicon-react/ErrorWarningLineIcon"),
);
const LoginIcon = importRemixIcon(
async () => import("remixicon-react/LoginBoxLineIcon"),
);
const LogoutIcon = importRemixIcon(
async () => import("remixicon-react/LogoutBoxRLineIcon"),
);
const ShareLineIcon = importRemixIcon(
async () => import("remixicon-react/ShareLineIcon"),
);
const LoaderLineIcon = importRemixIcon(
async () => import("remixicon-react/LoaderLineIcon"),
);
const WidgetIcon = importRemixIcon(
async () => import("remixicon-react/FunctionLineIcon"),
);
const RefreshLineIcon = importRemixIcon(
async () => import("remixicon-react/RefreshLineIcon"),
);
const GitBranchLineIcon = importRemixIcon(
async () => import("remixicon-react/GitBranchLineIcon"),
);
const EditBoxLineIcon = importRemixIcon(
async () => import("remixicon-react/EditBoxLineIcon"),
);
const StarLineIcon = importRemixIcon(
async () => import("remixicon-react/StarLineIcon"),
);
const StarFillIcon = importRemixIcon(
async () => import("remixicon-react/StarFillIcon"),
);
const Settings2LineIcon = importRemixIcon(
async () => import("remixicon-react/Settings2LineIcon"),
);
const DownloadIcon = importRemixIcon(
async () => import("remixicon-react/DownloadLineIcon"),
);
const UploadCloud2LineIcon = importRemixIcon(
async () => import("remixicon-react/UploadCloud2LineIcon"),
);
const DownloadLineIcon = importRemixIcon(
async () => import("remixicon-react/DownloadLineIcon"),
);
const UploadLineIcon = importRemixIcon(
async () => import("remixicon-react/UploadLineIcon"),
);
const FileListLineIcon = importRemixIcon(
async () => import("remixicon-react/FileListLineIcon"),
);
const HamburgerIcon = importRemixIcon(
async () => import("remixicon-react/MenuLineIcon"),
);
const MagicLineIcon = importRemixIcon(
async () => import("remixicon-react/MagicLineIcon"),
);
const UserHeartLineIcon = importRemixIcon(
async () => import("remixicon-react/UserHeartLineIcon"),
);
const DvdLineIcon = importRemixIcon(
async () => import("remixicon-react/DvdLineIcon"),
);
const Group2LineIcon = importRemixIcon(
async () => import("remixicon-react/Group2LineIcon"),
);
const CodeViewIcon = importRemixIcon(
async () => import("remixicon-react/CodeViewIcon"),
);
const GroupLineIcon = importRemixIcon(
async () => import("remixicon-react/GroupLineIcon"),
);
const ArrowRightUpLineIcon = importRemixIcon(
async () => import("remixicon-react/ArrowRightUpLineIcon"),
);
const MailCheckLineIcon = importRemixIcon(
async () => import("remixicon-react/MailCheckLineIcon"),
);
const UserFollowLineIcon = importRemixIcon(
async () => import("remixicon-react/UserFollowLineIcon"),
);
const AddBoxLineIcon = importRemixIcon(
async () => import("remixicon-react/AddBoxLineIcon"),
);
const ArrowRightSFillIcon = importRemixIcon(
async () => import("remixicon-react/ArrowRightSFillIcon"),
);
const ArrowDownSFillIcon = importRemixIcon(
async () => import("remixicon-react/ArrowDownSFillIcon"),
);
const MailLineIcon = importRemixIcon(
async () => import("remixicon-react/MailLineIcon"),
);
const LockPasswordLineIcon = importRemixIcon(
async () => import("remixicon-react/LockPasswordLineIcon"),
);
const Timer2LineIcon = importRemixIcon(
async () => import("remixicon-react/Timer2LineIcon"),
);
const MapPin2LineIcon = importRemixIcon(
async () => import("remixicon-react/MapPin2LineIcon"),
);
const User3LineIcon = importRemixIcon(
async () => import("remixicon-react/User3LineIcon"),
);
const User2LineIcon = importRemixIcon(
async () => import("remixicon-react/User2LineIcon"),
);
const Key2LineIcon = importRemixIcon(
async () => import("remixicon-react/Key2LineIcon"),
);
const FileList2LineIcon = importRemixIcon(
async () => import("remixicon-react/FileList2LineIcon"),
);
const Lock2LineIcon = importRemixIcon(
async () => import("remixicon-react/Lock2LineIcon"),
);
const SearchEyeLineIcon = importRemixIcon(
async () => import("remixicon-react/SearchEyeLineIcon"),
);
const AlertLineIcon = importRemixIcon(
async () => import("remixicon-react/AlertLineIcon"),
);
const SettingsLineIcon = importRemixIcon(
async () => import("remixicon-react/SettingsLineIcon"),
);
const LockUnlockLineIcon = importRemixIcon(
async () => import("remixicon-react/LockUnlockLineIcon"),
);
const PantoneLineIcon = importRemixIcon(
async () => import("remixicon-react/PantoneLineIcon"),
);
const QuestionFillIcon = importRemixIcon(
async () => import("remixicon-react/QuestionFillIcon"),
);
const QuestionLineIcon = importRemixIcon(
async () => import("remixicon-react/QuestionLineIcon"),
);
const UserSharedLineIcon = importRemixIcon(
async () => import("remixicon-react/UserSharedLineIcon"),
);
const UserReceived2LineIcon = importRemixIcon(
async () => import("remixicon-react/UserReceived2LineIcon"),
);
const UserAddLineIcon = importRemixIcon(
async () => import("remixicon-react/UserAddLineIcon"),
);
const UserUnfollowLineIcon = importRemixIcon(
async () => import("remixicon-react/UserUnfollowLineIcon"),
);
const DeleteRowIcon = importRemixIcon(
async () => import("remixicon-react/DeleteRowIcon"),
);
const ArrowUpLineIcon = importRemixIcon(
async () => import("remixicon-react/ArrowUpLineIcon"),
);
const MoneyDollarCircleLineIcon = importRemixIcon(
async () => import("remixicon-react/MoneyDollarCircleLineIcon"),
);
const ExternalLinkLineIcon = importRemixIcon(
async () => import("remixicon-react/ExternalLinkLineIcon"),
);
const PencilLineIcon = importRemixIcon(
async () => import("remixicon-react/PencilLineIcon"),
);
export enum IconSize {
XXS = "extraExtraSmall",
XS = "extraSmall",
SMALL = "small",
MEDIUM = "medium",
LARGE = "large",
XL = "extraLarge",
XXL = "extraExtraLarge",
XXXL = "extraExtraExtraLarge",
XXXXL = "extraExtraExtraExtraLarge",
}
const ICON_SIZE_LOOKUP = {
[IconSize.XXS]: 8,
[IconSize.XS]: 10,
[IconSize.SMALL]: 12,
[IconSize.MEDIUM]: 14,
[IconSize.LARGE]: 15,
[IconSize.XL]: 16,
[IconSize.XXL]: 18,
[IconSize.XXXL]: 20,
[IconSize.XXXXL]: 22,
undefined: 12,
};
export const sizeHandler = (size?: IconSize): number => {
return (
ICON_SIZE_LOOKUP[size as keyof typeof ICON_SIZE_LOOKUP] ||
ICON_SIZE_LOOKUP[IconSize.SMALL]
);
};
export const IconWrapper = styled.span<IconProps>`
&:focus {
outline: none;
}
display: flex;
align-items: center;
cursor: ${(props) =>
props.disabled ? "not-allowed" : props.clickable ? "pointer" : "default"};
${(props) =>
props.withWrapper &&
`
min-width: ${sizeHandler(props.size) * 2}px;
height: ${sizeHandler(props.size) * 2}px;
border-radius: 9999px;
justify-content: center;
background-color: ${props.wrapperColor || "rgba(0, 0, 0, 0.1)"};
`}
svg {
width: ${(props) => sizeHandler(props.size)}px;
height: ${(props) => sizeHandler(props.size)}px;
${(props) =>
!props.keepColors
? `
fill: ${props.fillColor || ""};
circle {
fill: ${props.fillColor || ""};
}
path {
fill: ${props.fillColor || ""};
}
`
: ""};
${(props) => (props.invisible ? `visibility: hidden;` : null)};
&:hover {
${(props) =>
!props.keepColors
? `
fill: ${props.hoverFillColor || ""};
path {
fill: ${props.hoverFillColor || ""};
}
`
: ""}
}
}
`;
function getControlIcon(iconName: string) {
const ControlIcon = ControlIcons[iconName];
return <ControlIcon height={24} width={24} />;
}
const ICON_LOOKUP = {
undefined: null,
HEADING_ONE: getControlIcon("HEADING_ONE"),
HEADING_THREE: getControlIcon("HEADING_THREE"),
HEADING_TWO: getControlIcon("HEADING_TWO"),
PARAGRAPH: getControlIcon("PARAGRAPH"),
PARAGRAPH_TWO: getControlIcon("PARAGRAPH_TWO"),
"add-box-line": <AddBoxLineIcon />,
"add-more": <AddMoreIcon />,
"add-more-fill": <AddMoreFillIcon />,
"alert-line": <AlertLineIcon />,
"arrow-down-s-fill": <ArrowDownSFillIcon />,
"arrow-forward": <ArrowForwardIcon />,
"arrow-left": <ArrowLeft />,
"arrow-right-s-fill": <ArrowRightSFillIcon />,
"arrow-right-up-line": <ArrowRightUpLineIcon />,
"arrow-up-line": <ArrowUpLineIcon />,
"book-line": <BookLineIcon />,
"bug-line": <BugLineIcon />,
"cap-dot": <CapDotIcon />,
"cap-solid": <CapSolidIcon />,
"card-context-menu": <CardContextMenu />,
"chat-help": <ChatIcon />,
"check-line": <CheckLineIcon />,
"chevron-left": <ChevronLeft />,
"chevron-right": <ChevronRight />,
"close-circle": <CloseCircleIcon />,
"close-circle-line": <CloseCircleLineIcon />,
"close-modal": <CloseLineIcon />,
"close-x": <CloseLineIcon />,
"cloud-off-line": <CloudOfflineIcon />,
"comment-context-menu": <CommentContextMenu />,
"compasses-line": <CompassesLine />,
"context-menu": <ContextMenuIcon />,
"database-2-line": <Database2Line />,
"delete-blank": <DeleteBin7 />,
"delete-row": <DeleteRowIcon />,
"double-arrow-right": <DoubleArrowRightIcon />,
"down-arrow": <DownArrowIcon />,
"down-arrow-2": <ArrowDownLineIcon />,
"download-line": <DownloadLineIcon />,
"edit-box-line": <EditBoxLineIcon />,
"edit-line": <EditLineIcon />,
"edit-underline": <EditUnderlineIcon />,
"expand-less": <ExpandLess />,
"expand-more": <ExpandMore />,
"external-link-line": <ExternalLinkLineIcon />,
"eye-off": <EyeOff />,
"eye-on": <EyeOn />,
"file-line": <FileLine />,
"file-list-2-line": <FileList2LineIcon />,
"file-list-line": <FileListLineIcon />,
"file-transfer": <FileTransfer />,
"fork-2": <Fork2Icon />,
"forbid-line": <ForbidLineIcon />,
"git-branch": <GitBranchLineIcon />,
"git-commit": <GitCommit />,
"git-pull-request": <GitPullRequst />,
"global-line": <GlobalLineIcon />,
"group-2-line": <Group2LineIcon />,
"group-line": <GroupLineIcon />,
"invite-user": <InviteUserIcon />,
"key-2-line": <Key2LineIcon />,
"left-arrow-2": <LeftArrowIcon2 />,
"lightbulb-flash-line": <LightbulbFlashLine />,
"line-dashed": <LineDashedIcon />,
"line-dotted": <LineDottedIcon />,
"link-2": <Link2 />,
"links-line": <LinksLineIcon />,
"lock-2-line": <Lock2LineIcon />,
"lock-password-line": <LockPasswordLineIcon />,
"lock-unlock-line": <LockUnlockLineIcon />,
"magic-line": <MagicLineIcon />,
"mail-check-line": <MailCheckLineIcon />,
"mail-line": <MailLineIcon />,
"map-pin-2-line": <MapPin2LineIcon />,
"more-2-fill": <More2FillIcon />,
"news-paper": <NewsPaperLine />,
"no-response": <NoResponseIcon />,
"oval-check": <OvalCheck />,
"oval-check-fill": <OvalCheckFill />,
"pin-3": <Pin3 />,
"play-circle-line": <PlayCircleLineIcon />,
"question-fill": <QuestionFillIcon />,
"question-line": <QuestionLineIcon />,
"reaction-2": <Reaction2 />,
"read-pin": <ReadPin />,
"right-arrow": <RightArrowIcon />,
"right-arrow-2": <RightArrowIcon2 />,
"search-eye-line": <SearchEyeLineIcon />,
"send-button": <SendButton />,
"settings-2-line": <Settings2LineIcon />,
"settings-line": <SettingsLineIcon />,
"share-2": <ShareIcon2 />,
"share-box": <ShareBoxFillIcon />,
"share-box-line": <ShareBoxLineIcon />,
"share-line": <ShareLineIcon />,
"sort-asc": <SortAscIcon />,
"sort-desc": <SortDescIcon />,
"star-fill": <StarFillIcon />,
"star-line": <StarLineIcon />,
"swap-horizontal": <ArrowLeftRightIcon />,
"timer-2-line": <Timer2LineIcon />,
"trash-outline": <TrashOutline />,
"trending-flat": <TrendingFlat />,
"unread-pin": <UnreadPin />,
"upload-cloud": <UploadCloud2LineIcon />,
"upload-line": <UploadLineIcon />,
"user-2": <UserV2Icon />,
"user-2-line": <User2LineIcon />,
"user-3-line": <User3LineIcon />,
"user-add-line": <UserAddLineIcon />,
"user-follow-line": <UserFollowLineIcon />,
"user-heart-line": <UserHeartLineIcon />,
"user-received-2-line": <UserReceived2LineIcon />,
"user-shared-line": <UserSharedLineIcon />,
"user-unfollow-line": <UserUnfollowLineIcon />,
"view-all": <RightArrowIcon />,
"view-less": <LeftArrowIcon />,
"warning-line": <WarningLineIcon />,
"warning-triangle": <WarningTriangleIcon />,
"money-dollar-circle-line": <MoneyDollarCircleLineIcon />,
"success-line": <SuccessLineIcon />,
"error-line": <ErrorLineIcon />,
"history-line": <HistoryLineIcon />,
billing: <BillingIcon />,
book: <BookIcon />,
bug: <BugIcon />,
cancel: <CancelIcon />,
chat: <Chat />,
close: <CloseIcon />,
code: <CodeViewIcon />,
column: <ColumnIcon />,
cross: <CrossIcon />,
danger: <ErrorIcon />,
datasource: <DatasourceIcon />,
delete: <Trash />,
desktop: <DesktopIcon />,
discord: <DiscordIcon />,
downArrow: <DownArrow />,
download2: <DownloadIcon />,
download: <Download />,
dropdown: <DropdownIcon />,
duplicate: <DuplicateIcon />,
edit: <EditIcon />,
emoji: <Emoji />,
enterprise: <MagicLineIcon />,
error: <ErrorIcon />,
execute: <ExecuteIcon />,
filter: <Filter />,
fluid: <FluidIcon />,
fork: <GitMerge />,
gear: <GearIcon />,
general: <GeneralIcon />,
guide: <GuideIcon />,
hamburger: <HamburgerIcon />,
help: <HelpIcon />,
info: <InfoIcon />,
js: <JsIcon />,
key: <KeyIcon />,
lightning: <LightningIcon />,
link: <LinkIcon />,
loader: <LoaderLineIcon />,
login: <LoginIcon />,
logout: <LogoutIcon />,
manage: <ManageIcon />,
member: <UserHeartLineIcon />,
minus: <RemoveIcon />,
mobile: <MobileIcon />,
open: <OpenIcon />,
pantone: <PantoneLineIcon />,
pin: <Pin />,
play: <PlayIcon />,
plus: <CreateNewIcon />,
query: <QueryIcon />,
reaction: <Reaction />,
refresh: <RefreshLineIcon />,
rocket: <RocketIcon />,
search: <SearchIcon />,
setting: <SettingIcon />,
share: <ShareForwardIcon />,
shine: <ShineIcon />,
snippet: <Snippet />,
success: <SuccessIcon />,
support: <SupportIcon />,
tables: <TableIcon />,
tablet: <TabletIcon />,
tabletLandscape: <TabletLandscapeIcon />,
trash: <Trash />,
unpin: <Unpin />,
upArrow: <UpArrow />,
upgrade: <DvdLineIcon />,
upload: <Upload />,
user: <UserIcon />,
wand: <WandIcon />,
warning: <WarningIcon />,
widget: <WidgetIcon />,
workspace: <WorkspaceIcon />,
"clear-interval": <ClearInterval />,
"clear-store": <ClearStore />,
"copy-to-clipboard": <CopyToClipboard />,
"download-action": <DownloadAction />,
"execute-js": <ExecuteJs />,
"execute-query": <ExecuteQuery />,
"get-geolocation": <GetGeolocation />,
modal: <Modal />,
"navigate-to": <NavigateTo />,
"remove-store": <RemoveStore />,
"reset-widget": <ResetWidget />,
"set-interval": <SetInterval />,
"show-alert": <ShowAlert />,
"stop-watch-geolocation": <StopWatchGeolocation />,
"store-value": <StoreValue />,
"watch-geolocation": <WatchGeolocation />,
"run-api": <RunAPI />,
"post-message": <PostMessage />,
"no-action": <NoAction />,
package: <PackageIcon />,
devices: <DevicesIcon />,
grid: <GridIcon />,
updates: <UpdatesIcon />,
"pencil-line": <PencilLineIcon />,
};
export const IconCollection = Object.keys(ICON_LOOKUP);
export type IconName = (typeof IconCollection)[number];
export interface IconProps {
size?: IconSize;
name?: IconName;
invisible?: boolean;
className?: string;
onClick?: (e: React.MouseEvent) => void;
fillColor?: string;
hoverFillColor?: string;
keepColors?: boolean;
loaderWithIconWrapper?: boolean;
clickable?: boolean;
disabled?: boolean;
withWrapper?: boolean;
wrapperColor?: string;
}
const Icon = forwardRef(
(
{ onClick, ...props }: IconProps & CommonComponentProps,
ref: Ref<HTMLSpanElement>,
) => {
const iconName = props.name;
const returnIcon =
ICON_LOOKUP[iconName as keyof typeof ICON_LOOKUP] || null;
const clickable = props.clickable === undefined ? true : props.clickable;
let loader = <Spinner size={props.size} />;
if (props.loaderWithIconWrapper) {
loader = (
<IconWrapper className={Classes.ICON} clickable={clickable} {...props}>
<Spinner size={props.size} />
</IconWrapper>
);
}
return returnIcon && !props.isLoading ? (
<IconWrapper
className={`${Classes.ICON} ${props.className}`}
clickable={clickable}
data-cy={props.cypressSelector}
onClick={props.disabled ? noop : onClick}
ref={ref}
{...props}
>
{returnIcon}
</IconWrapper>
) : props.isLoading ? (
loader
) : null;
},
);
Icon.displayName = "Icon";
export default React.memo(Icon);

View File

@ -2,7 +2,7 @@ import React, { useState, useEffect, useRef } from "react";
import styled from "styled-components";
import type { AppIconName } from "../AppIcon";
import AppIcon, { AppIconCollection } from "../AppIcon";
import { Size } from "../Button";
import { Size } from "../AppIcon";
import type { CommonComponentProps } from "../types/common";
import { Classes } from "../constants/classes";

View File

@ -3,15 +3,15 @@ import React, { forwardRef } from "react";
import type { CommonComponentProps } from "../types/common";
import { Classes } from "../constants/classes";
import styled from "styled-components";
import type { IconName } from "../Icon";
import Icon, { IconSize } from "../Icon";
import type { IconNames } from "@appsmith/ads";
import { Icon } from "@appsmith/ads";
import TooltipComponent from "../Tooltip";
import Text, { TextType, FontWeight } from "../Text";
// eslint-disable-next-line @typescript-eslint/no-restricted-imports
import type { PopoverPosition } from "@blueprintjs/core/lib/esnext/components/popover/popoverSharedProps";
export type MenuItemProps = CommonComponentProps & {
icon?: IconName;
icon?: IconNames;
text: string;
label?: ReactNode;
href?: string;
@ -98,14 +98,7 @@ const MenuItemContent = forwardRef(
type={props.type}
>
<IconContainer className={props.containerClassName}>
{props.icon ? (
<Icon
isLoading={props.isLoading}
loaderWithIconWrapper
name={props.icon}
size={IconSize.LARGE}
/>
) : null}
{props.icon ? <Icon name={props.icon} size="md" /> : null}
{props.text && (
<Text type={TextType.H5} weight={FontWeight.NORMAL}>
{props.ellipsize

View File

@ -1,59 +0,0 @@
import React from "react";
import styled, { keyframes } from "styled-components";
import type { IconSize } from "../Icon";
import { sizeHandler } from "../Icon";
import { Classes } from "../constants/classes";
const rotate = keyframes`
100% {
transform: rotate(360deg);
}
`;
const dash = keyframes`
0% {
stroke-dasharray: 1, 150;
stroke-dashoffset: 0;
}
50% {
stroke-dasharray: 90, 150;
stroke-dashoffset: -35;
}
100% {
stroke-dasharray: 90, 150;
stroke-dashoffset: -124;
}
`;
const SvgContainer = styled.svg<SpinnerProp>`
animation: ${rotate} 2s linear infinite;
width: ${(props) => sizeHandler(props.size)}px;
height: ${(props) => sizeHandler(props.size)}px;
`;
const SvgCircle = styled.circle`
stroke: var(--ads-v2-color-fg-subtle);
stroke-linecap: round;
animation: ${dash} 1.5s ease-in-out infinite;
stroke-width: var(--ads-spaces-1);
`;
export interface SpinnerProp {
size?: IconSize;
}
Spinner.defaultProp = {
size: "small",
};
export default function Spinner(props: SpinnerProp) {
return (
<SvgContainer
className={Classes.SPINNER}
size={props.size}
viewBox="0 0 50 50"
>
<SvgCircle cx="25" cy="25" fill="none" r="20" />
</SvgContainer>
);
}

View File

@ -3,8 +3,7 @@ import React from "react";
import styled from "styled-components";
import { Classes } from "../constants/classes";
import { typography } from "../constants/typography";
import Spinner from "../Spinner";
import { IconSize } from "../Icon";
import { Spinner } from "@appsmith/ads";
import { importSvg } from "../utils/icon-loadables";
const DownArrow = importSvg(
@ -192,11 +191,7 @@ function Table(props: TableProps) {
<tr className="no-hover">
<td className="no-border" colSpan={columns?.length}>
<CentralizedWrapper>
{loaderComponent ? (
loaderComponent
) : (
<Spinner size={IconSize.XXL} />
)}
{loaderComponent ? loaderComponent : <Spinner size="lg" />}
</CentralizedWrapper>
</td>
</tr>

View File

@ -1,426 +0,0 @@
import type { RefObject } from "react";
import React, { useCallback, useState, useEffect } from "react";
import { Tab, Tabs, TabList, TabPanel } from "react-tabs";
import "react-tabs/style/react-tabs.css";
import styled from "styled-components";
import type { IconName } from "../Icon";
import Icon, { IconSize } from "../Icon";
import { useResizeObserver } from "../hooks";
import { Classes } from "../constants/classes";
import type { CommonComponentProps } from "../types/common";
import { typography } from "../constants/typography";
export const TAB_MIN_HEIGHT = `36px`;
export interface TabProp {
key: string;
title: string;
count?: number;
panelComponent?: JSX.Element;
icon?: IconName;
iconSize?: IconSize;
}
const TabsWrapper = styled.div<{
shouldOverflow?: boolean;
vertical?: boolean;
responseViewer?: boolean;
}>`
border-radius: 0px;
height: 100%;
overflow: hidden;
.react-tabs {
height: 100%;
}
.react-tabs__tab-panel {
height: calc(100% - ${TAB_MIN_HEIGHT});
overflow: auto;
}
.react-tabs__tab-list {
margin: 0px;
display: flex;
flex-direction: ${(props) => (!!props.vertical ? "column" : "row")};
align-items: ${(props) => (!!props.vertical ? "stretch" : "center")};
border-bottom: none;
color: var(--ads-tabs-default-tab-list-text-color);
path {
fill: var(--ads-tabs-default-tab-list-svg-fill-color);
}
${(props) =>
props.shouldOverflow &&
`
overflow-y: hidden;
overflow-x: auto;
white-space: nowrap;
`}
${(props) =>
props.responseViewer &&
`
margin-left: 30px;
display: flex;
align-items: center;
height: 24px;
background-color: var(--ads-tabs-default-tab-list-response-viewer-background-color) !important;
width: fit-content;
padding-left: 1px;
margin-top: 10px !important;
margin-bottom: 10px !important;
`}
}
.react-tabs__tab {
align-items: center;
text-align: center;
display: inline-flex;
justify-content: center;
border-color: transparent;
position: relative;
padding: 0px 3px;
margin-right: ${(props) =>
!props.vertical ? `calc(var(--ads-spaces-12) - 3px)` : 0};
}
.react-tabs__tab,
.react-tabs__tab:focus {
box-shadow: none;
border: none;
&:after {
content: none;
}
${(props) =>
props.responseViewer &&
`
display: flex;
align-items: center;
cursor: pointer;
height: 22px;
padding: 0 12px;
border: 1px solid var(--ads-tabs-default-tab-focus-response-viewer-border-color);
margin-right: -1px;
margin-left: -1px;
margin-top: -2px;
height: 100%;
`}
}
.react-tabs__tab--selected {
background-color: transparent;
path {
fill: var(--ads-tabs-tab-selected-svg-fill-color);
}
${(props) =>
props.responseViewer &&
`
background-color: var(--ads-tabs-tab-selected-response-viewer-background-color);
border: 1px solid var(--ads-tabs-tab-selected-response-viewer-border-color);
border-radius: 0px;
font-weight: normal;
`}
}
`;
export const TabTitle = styled.span<{ responseViewer?: boolean }>`
font-size: ${typography.h5.fontSize}px;
font-weight: var(--ads-font-weight-bold);
line-height: var(--ads-spaces-6);
letter-spacing: ${typography.h5.letterSpacing}px;
margin: 0;
display: flex;
align-items: center;
${(props) =>
props.responseViewer &&
`
font-size: 12px;
font-weight: normal;
line-height: 16px;
letter-spacing: normal;
text-transform: uppercase;
color: var(--ads-tabs-tab-title-response-viewer-text-color);
`}
`;
export const TabCount = styled.div`
background-color: var(--ads-tabs-count-background-color);
border-radius: 8px;
min-width: 17px;
height: 17px;
font-size: 9px;
margin-left: 4px;
display: flex;
align-items: center;
justify-content: center;
padding: 0 2px;
`;
const TabTitleWrapper = styled.div<{
selected: boolean;
vertical: boolean;
responseViewer?: boolean;
}>`
display: flex;
align-items: center;
width: 100%;
padding: calc(var(--ads-spaces-3) - 1px)
${(props) => (props.vertical ? `calc(var(--ads-spaces-4) - 1px)` : 0)}
calc(var(--ads-spaces-4) - 1px)
${(props) => (props.vertical ? `calc(var(--ads-spaces-4) - 1px)` : 0)};
color: var(--ads-tabs-title-wrapper-text-color);
&:hover {
color: var(--ads-tabs-title-wrapper-hover-text-color);
.${Classes.ICON} {
svg {
fill: var(--ads-tabs-title-wrapper-hover-text-color);
path {
fill: var(--ads-tabs-title-wrapper-hover-text-color);
}
}
}
}
${(props) =>
props.responseViewer &&
`
padding: 0px;
`}
.${Classes.ICON} {
margin-right: var(--ads-spaces-1);
border-radius: 50%;
svg {
width: 16px;
height: 16px;
margin: auto;
fill: var(--ads-tabs-title-wrapper-icon-fill-color);
path {
fill: var(--ads-tabs-title-wrapper-icon-fill-color);
}
}
}
${(props) =>
props.selected
? `
background-color: transparent;
color: var(--ads-color-black-900);
.${Classes.ICON} {
svg {
path {
fill: var(--ads-color-black-900)
}
}
}
.tab-title {
${
props.responseViewer &&
`
font-weight: normal;
`
}
}
&::after {
content: "";
position: absolute;
width: ${props.vertical ? `calc(var(--ads-spaces-1) - 2px)` : "100%"};
bottom: ${props.vertical ? "0%" : `calc(var(--ads-spaces-0) - 1px)`};
top: ${
props.vertical ? `calc(var(--ads-spaces-0) - 1px)` : "calc(100% - 2px)"
};
left: var(--ads-spaces-0);
height: ${props.vertical ? "100%" : `calc(var(--ads-spaces-1) - 2px)`};
background-color: var(--ads-color-brand);
z-index: var(--ads-z-index-3);
${
props.responseViewer &&
`
display: none;
`
}
}
`
: ""}
`;
const CollapseIconWrapper = styled.div`
position: absolute;
right: 14px;
top: calc(var(--ads-spaces-3) - 1px);
cursor: pointer;
`;
export interface TabItemProps {
tab: TabProp;
selected: boolean;
vertical: boolean;
responseViewer?: boolean;
}
function DefaultTabItem(props: TabItemProps) {
const { responseViewer, selected, tab, vertical } = props;
return (
<TabTitleWrapper
responseViewer={responseViewer}
selected={selected}
vertical={vertical}
>
{tab.icon ? (
<Icon
name={tab.icon}
size={tab.iconSize != null ? tab.iconSize : IconSize.XXXL}
/>
) : null}
<TabTitle className="tab-title" responseViewer={responseViewer}>
{tab.title}
</TabTitle>
{tab.count && tab.count > 0 ? (
<TabCount data-testid="t--tab-count">{tab.count}</TabCount>
) : null}
</TabTitleWrapper>
);
}
export type TabbedViewComponentType = CommonComponentProps & {
tabs: Array<TabProp>;
selectedIndex?: number;
onSelect?: (tabIndex: number) => void;
overflow?: boolean;
vertical?: boolean;
tabItemComponent?: (props: TabItemProps) => JSX.Element;
responseViewer?: boolean;
canCollapse?: boolean;
// Reference to container for collapsing or expanding content
containerRef?: RefObject<HTMLElement>;
// height of container when expanded
expandedHeight?: string;
};
// Props required to support a collapsible (foldable) tab component
export interface CollapsibleTabProps {
// Reference to container for collapsing or expanding content
containerRef: RefObject<HTMLDivElement>;
// height of container when expanded( usually the default height of the tab component)
expandedHeight: string;
}
export type CollapsibleTabbedViewComponentType = TabbedViewComponentType &
CollapsibleTabProps;
export const collapsibleTabRequiredPropKeys: Array<keyof CollapsibleTabProps> =
["containerRef", "expandedHeight"];
// Tab is considered collapsible only when all required collapsible props are present
export const isCollapsibleTabComponent = (
props: TabbedViewComponentType | CollapsibleTabbedViewComponentType,
): props is CollapsibleTabbedViewComponentType =>
collapsibleTabRequiredPropKeys.every((key) => key in props);
export function TabComponent(
props: TabbedViewComponentType | CollapsibleTabbedViewComponentType,
) {
const { onSelect, tabItemComponent } = props;
const TabItem = tabItemComponent || DefaultTabItem;
// for setting selected state of an uncontrolled component
const [selectedIndex, setSelectedIndex] = useState(props.selectedIndex || 0);
const [isExpanded, setIsExpanded] = useState(true);
useEffect(() => {
if (typeof props.selectedIndex === "number")
setSelectedIndex(props.selectedIndex);
}, [props.selectedIndex]);
const toggleCollapse = () => {
if (!isCollapsibleTabComponent(props)) return;
const { containerRef, expandedHeight } = props;
if (containerRef?.current && expandedHeight) {
containerRef.current.style.height = isExpanded
? TAB_MIN_HEIGHT
: expandedHeight;
}
setIsExpanded((prev) => !prev);
};
const resizeCallback = useCallback(
(entries: ResizeObserverEntry[]) => {
if (entries && entries.length) {
const {
contentRect: { height },
} = entries[0];
if (height > Number(TAB_MIN_HEIGHT.replace("px", "")) + 6) {
!isExpanded && setIsExpanded(true);
} else {
isExpanded && setIsExpanded(false);
}
}
},
[isExpanded],
);
useResizeObserver(
isCollapsibleTabComponent(props) ? props.containerRef?.current : null,
resizeCallback,
);
useEffect(() => {
if (!isCollapsibleTabComponent(props)) return;
const { containerRef } = props;
if (!isExpanded && containerRef.current) {
containerRef.current.style.height = TAB_MIN_HEIGHT;
}
}, [isExpanded]);
return (
<TabsWrapper
className={props.className}
data-cy={props.cypressSelector}
responseViewer={props.responseViewer}
shouldOverflow={props.overflow}
vertical={props.vertical}
>
{isCollapsibleTabComponent(props) && (
<CollapseIconWrapper className="t--tabs-collapse-icon">
<Icon
name={isExpanded ? "expand-more" : "expand-less"}
onClick={toggleCollapse}
size={IconSize.XXXXL}
/>
</CollapseIconWrapper>
)}
<Tabs
onSelect={(index: number) => {
onSelect ? onSelect(index) : setSelectedIndex(index);
!isExpanded && toggleCollapse();
}}
selectedIndex={props.selectedIndex}
>
<TabList>
{props.tabs.map((tab, index) => (
<Tab
data-cy={`t--tab-${tab.key}`}
data-replay-id={tab.key}
key={tab.key}
>
<TabItem
responseViewer={props.responseViewer}
selected={
index === props.selectedIndex || index === selectedIndex
}
tab={tab}
vertical={!!props.vertical}
/>
</Tab>
))}
</TabList>
{props.tabs.map((tab) => (
<TabPanel key={tab.key}>{tab.panelComponent}</TabPanel>
))}
</Tabs>
</TabsWrapper>
);
}

View File

@ -1,475 +0,0 @@
import type { EventHandler, FocusEvent, Ref } from "react";
import React, {
forwardRef,
useCallback,
useEffect,
useMemo,
useState,
} from "react";
import type { CommonComponentProps } from "../types/common";
import { Classes } from "../constants/classes";
import { typography } from "../constants/typography";
import { Classes as BlueprintClasses } from "@blueprintjs/core";
import styled from "styled-components";
import Text, { TextType } from "../Text";
import {
ERROR_MESSAGE_NAME_EMPTY,
createMessage,
FORM_VALIDATION_INVALID_EMAIL,
} from "../constants/messages";
import type { IconName } from "../Icon";
import Icon, { IconCollection, IconSize } from "../Icon";
import { AsyncControllableInput } from "@blueprintjs/core/lib/esm/components/forms/asyncControllableInput";
import _ from "lodash";
import { replayHighlightClass } from "../constants/classes";
import { hexToRgba } from "../utils/colors";
export type InputType = "text" | "password" | "number" | "email" | "tel";
export type Validator = (value: string) => {
isValid: boolean;
message: string;
};
// TODO (abhinav): Use a regex which adheres to standards RFC5322
const isEmail = (value: string) => {
const re =
/^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
return re.test(value);
};
export function emailValidator(email: string) {
let isValid = true;
if (email) {
isValid = isEmail(email);
}
return {
isValid: isValid,
message: !isValid ? createMessage(FORM_VALIDATION_INVALID_EMAIL) : "",
};
}
export function notEmptyValidator(value: string) {
const isValid = !!value;
return {
isValid: isValid,
message: !isValid ? createMessage(ERROR_MESSAGE_NAME_EMPTY) : "",
};
}
export type TextInputProps = CommonComponentProps & {
autoFocus?: boolean;
placeholder?: string;
fill?: boolean;
defaultValue?: string;
value?: string;
validator?: (value: string) => { isValid: boolean; message: string };
onChange?: (value: string) => void;
readOnly?: boolean;
dataType?: string;
leftIcon?: IconName;
prefix?: string;
helperText?: string;
rightSideComponent?: React.ReactNode;
width?: string;
height?: string;
noBorder?: boolean;
noCaret?: boolean;
onBlur?: EventHandler<FocusEvent<any>>;
onFocus?: EventHandler<FocusEvent<any>>;
errorMsg?: string;
trimValue?: boolean;
$padding?: string;
useTextArea?: boolean;
isCopy?: boolean;
border?: boolean;
style?: any;
tabIndex?: number;
};
interface boxReturnType {
bgColor: string;
color: string;
borderColor: string;
}
const boxStyles = (props: TextInputProps, isValid: boolean): boxReturnType => {
let bgColor = "var(--ads-text-input-text-box-default-background-color)";
let color = "var(--ads-text-input-text-box-default-text-color)";
let borderColor = "var(--ads-text-input-text-box-default-border-color)";
if (props.disabled) {
bgColor = "var(--ads-text-input-text-box-disabled-background-color)";
color = "var(--ads-text-input-text-box-disabled-text-color)";
borderColor = "var(--ads-text-input-text-box-disabled-border-color)";
}
if (props.readOnly) {
bgColor = "var(--ads-text-input-text-box-read-only-background-color)";
color = "var(--ads-text-input-text-box-read-only-text-color)";
borderColor = "var(--ads-text-input-text-box-read-only-border-color)";
}
if (!isValid) {
bgColor = hexToRgba("var(--ads-danger-main)", 0.1);
color = "var(--ads-danger-main)";
borderColor = "var(--ads-danger-main)";
}
return { bgColor, color, borderColor };
};
const InputLoader = styled.div<{
$value?: string;
$noBorder?: boolean;
$isFocused?: boolean;
$isLoading?: boolean;
$height?: string;
}>`
display: ${(props) => (props.$isLoading ? "static" : "none")};
border-radius: 0;
width: ${(props) =>
props.$value && !props.$noBorder && props.$isFocused
? "calc(100% - 50px)"
: "100%"};
height: ${(props) => props.$height || "36px"};
`;
const StyledInput = styled((props) => {
// we are removing non input related props before passing them in the components
// eslint-disable @typescript-eslint/no-unused-vars
const { dataType, inputRef, ...inputProps } = props;
const omitProps = [
"hasLeftIcon",
"inputStyle",
"rightSideComponentWidth",
"validator",
"isValid",
"cypressSelector",
"leftIcon",
"helperText",
"rightSideComponent",
"noBorder",
"isLoading",
"noCaret",
"fill",
"errorMsg",
"useTextArea",
"border",
"asyncControl",
"handleCopy",
"prefix",
];
const HtmlTag = props.useTextArea ? "textarea" : "input";
return props.asyncControl ? (
<AsyncControllableInput
{..._.omit(inputProps, omitProps)}
datatype={dataType}
inputRef={inputRef}
/>
) : (
<HtmlTag ref={inputRef} {..._.omit(inputProps, omitProps)} />
);
})<
TextInputProps & {
inputStyle: boxReturnType;
isValid: boolean;
rightSideComponentWidth: number;
hasLeftIcon: boolean;
$isLoading?: boolean;
}
>`
display: ${(props) => (props.$isLoading ? "none" : "static")};
${(props) => (props.noCaret ? "caret-color: white;" : null)};
color: ${(props) => props.inputStyle.color};
width: ${(props) =>
props.value && !props.noBorder && props.isFocused
? "calc(100% - 50px)"
: "100%"};
border-radius: 0;
outline: 0;
box-shadow: none;
border: none;
padding: 0px var(--ads-spaces-6);
${(props) => (props.$padding ? `padding: ${props.$padding}` : "")};
padding-right: ${(props) =>
`calc(${props.rightSideComponentWidth}px + var(--ads-spaces-6))`};
background-color: transparent;
font-size: ${typography.p1.fontSize}px;
font-weight: ${typography.p1.fontWeight};
line-height: ${typography.p1.lineHeight}px;
letter-spacing: ${typography.p1.letterSpacing}px;
text-overflow: ellipsis;
height: 100%;
&::placeholder {
color: var(--ads-text-input-placeholder-text-color);
}
&:disabled {
cursor: not-allowed;
}
`;
export const InputWrapper = styled.div<{
value?: string;
isFocused: boolean;
fill?: number;
noBorder?: boolean;
height?: string;
width?: string;
inputStyle: boxReturnType;
isValid?: boolean;
disabled?: boolean;
$isLoading?: boolean;
readOnly?: boolean;
}>`
position: relative;
display: flex;
align-items: center;
width: ${(props) =>
props.fill ? "100%" : props.width ? props.width : "260px"};
height: ${(props) => props.height || "36px"};
border: 1.2px solid
${(props) =>
props.noBorder ? "transparent" : props.inputStyle.borderColor};
background-color: ${(props) => props.inputStyle.bgColor};
color: ${(props) => props.inputStyle.color};
${(props) =>
props.isFocused && !props.noBorder && !props.disabled && !props.readOnly
? `
border: 1.2px solid
${
props.isValid
? "var(--appsmith-input-focus-border-color)"
: "var(--ads-danger-main)"
};
`
: null}
.${Classes.TEXT} {
color: var(--ads-danger-main);
}
.helper {
.${Classes.TEXT} {
color: var(--ads-text-input-helper-text-text-color);
}
}
&:hover {
background-color: ${(props) =>
props.disabled || props.readOnly
? props.inputStyle.bgColor
: "var(--ads-text-input-text-box-hover-background-color)"};
}
${(props) => (props.disabled ? "cursor: not-allowed;" : null)}
`;
const MsgWrapper = styled.div`
position: absolute;
bottom: -20px;
left: 0px;
&.helper {
.${Classes.TEXT} {
color: var(--ads-text-input-helper-text-text-color);
}
}
`;
const RightSideContainer = styled.div`
position: absolute;
right: var(--ads-spaces-6);
bottom: 0;
top: 0;
display: flex;
align-items: center;
`;
const IconWrapper = styled.div`
.${Classes.ICON} {
margin-right: var(--ads-spaces-5);
}
`;
const PrefixWrapper = styled.div`
.${Classes.TEXT} {
padding-left: var(--ads-spaces-2);
color: var(--ads-color-black-400);
}
`;
const initialValidation = (props: TextInputProps) => {
let validationObj = { isValid: true, message: "" };
if (props.defaultValue && props.validator) {
validationObj = props.validator(props.defaultValue);
}
return validationObj;
};
const TextInput = forwardRef(
(props: TextInputProps, ref: Ref<HTMLInputElement>) => {
//
const [validation, setValidation] = useState<{
isValid: boolean;
message: string;
}>(initialValidation(props));
const [rightSideComponentWidth, setRightSideComponentWidth] = useState(0);
const [isFocused, setIsFocused] = useState(false);
const [inputValue, setInputValue] = useState(props.defaultValue);
const { trimValue = false } = props;
const setRightSideRef = useCallback((ref: HTMLDivElement) => {
if (ref) {
const { width } = ref.getBoundingClientRect();
setRightSideComponentWidth(width);
}
}, []);
const inputStyle = useMemo(
() => boxStyles(props, validation?.isValid),
[props, validation?.isValid],
);
// set the default value
useEffect(() => {
if (props.defaultValue) {
const inputValue = props.defaultValue;
setInputValue(inputValue);
checkValidator(inputValue);
props.onChange && props.onChange(inputValue);
}
}, [props.defaultValue]);
const checkValidator = (inputValue: string) => {
const inputValueValidation =
props.validator && props.validator(inputValue);
if (inputValueValidation) {
props.validator && setValidation(inputValueValidation);
}
};
const memoizedChangeHandler = useCallback(
(el) => {
const inputValue: string = trimValue
? el.target.value.trim()
: el.target.value;
setInputValue(inputValue);
checkValidator(inputValue);
return props.onChange && props.onChange(inputValue);
},
[props.onChange, setValidation, trimValue],
);
const onBlurHandler = useCallback(
(e: React.FocusEvent<any>) => {
setIsFocused(false);
if (props.onBlur) props.onBlur(e);
},
[setIsFocused, props.onBlur],
);
const onFocusHandler = useCallback((e: React.FocusEvent<any>) => {
setIsFocused(true);
if (props.onFocus) props.onFocus(e);
}, []);
const ErrorMessage = (
<MsgWrapper>
<Text type={TextType.P3}>
{props.errorMsg ? props.errorMsg : validation?.message}
</Text>
</MsgWrapper>
);
const HelperMessage = (
<MsgWrapper className="helper">
<Text type={TextType.P3}>* {props.helperText}</Text>
</MsgWrapper>
);
const iconColor = !validation?.isValid
? "var(--ads-danger-main)"
: "var(--ads-text-input-icon-path-color)";
const hasLeftIcon = props.leftIcon
? IconCollection.includes(props.leftIcon)
: false;
return (
<InputWrapper
$isLoading={props.isLoading}
className={replayHighlightClass}
disabled={props.disabled}
fill={props.fill ? 1 : 0}
height={props.height || undefined}
inputStyle={inputStyle}
isFocused={isFocused}
isValid={validation?.isValid}
noBorder={props.noBorder}
readOnly={props.readOnly}
value={inputValue}
width={props.width || undefined}
>
{props.leftIcon && (
<IconWrapper className="left-icon">
<Icon
fillColor={iconColor}
name={props.leftIcon}
size={IconSize.MEDIUM}
/>
</IconWrapper>
)}
{props.prefix && (
<PrefixWrapper className="prefix">
<Text type={TextType.P1}>{props.prefix}</Text>
</PrefixWrapper>
)}
<InputLoader
$height={props.height}
$isFocused={isFocused}
$isLoading={props.isLoading}
$noBorder={props.noBorder}
$value={props.value}
className={BlueprintClasses.SKELETON}
/>
<StyledInput
$isLoading={props.isLoading}
autoFocus={props.autoFocus}
defaultValue={props.defaultValue}
inputStyle={inputStyle}
isValid={validation?.isValid}
ref={ref}
type={props.dataType || "text"}
{...props}
data-cy={props.cypressSelector}
hasLeftIcon={hasLeftIcon}
inputRef={ref}
name={props?.name}
onBlur={onBlurHandler}
onChange={memoizedChangeHandler}
onFocus={onFocusHandler}
placeholder={props.placeholder}
readOnly={props.readOnly}
rightSideComponentWidth={rightSideComponentWidth}
tabIndex={props.tabIndex ?? 0}
/>
{validation?.isValid &&
props.helperText &&
props.helperText.length > 0 &&
HelperMessage}
{ErrorMessage}
<RightSideContainer className="right-icon" ref={setRightSideRef}>
{props.rightSideComponent}
</RightSideContainer>
</InputWrapper>
);
},
);
TextInput.displayName = "TextInput";
export default TextInput;

View File

@ -18,7 +18,7 @@ import {
Classes,
} from "@blueprintjs/core";
import styled from "styled-components";
import Icon, { IconSize } from "../Icon";
import { Icon } from "@appsmith/ads";
import { replayHighlightClass } from "../constants/classes";
import useDSEvent from "../hooks/useDSEvent";
import { DSEventTypes } from "../types/common";
@ -626,7 +626,7 @@ function TreeDropdown(props: TreeDropdownProps) {
}`}
elementRef={buttonRef}
onKeyDown={handleKeydown}
rightIcon={<Icon name="down-arrow" size={IconSize.XXL} />}
rightIcon={<Icon name="down-arrow" size="md" />}
text={
selectedLabelModifier
? selectedLabelModifier(selectedOptionFromProps, displayValue)

View File

@ -1,5 +1,5 @@
export enum Classes {
ICON = "cs-icon",
ICON = "ads-v2-icon",
APP_ICON = "cs-app-icon",
TEXT = "cs-text",
BP3_POPOVER_ARROW_BORDER = "bp3-popover-arrow-border",

View File

@ -3,12 +3,6 @@
export { default as AppIcon } from "./AppIcon";
export * from "./AppIcon";
export { default as Breadcrumbs } from "./Breadcrumbs";
export * from "./Breadcrumbs";
export { default as Button } from "./Button";
export * from "./Button";
export { default as Checkbox } from "./Checkbox";
export * from "./Checkbox";
@ -26,8 +20,11 @@ export * from "./DisplayImageUpload";
export { default as DraggableList } from "./DraggableList";
export * from "./DraggableList";
export { default as Dropdown } from "./Dropdown";
export * from "./Dropdown";
export type {
DropdownOption,
DropdownOnSelect,
RenderDropdownOptionType,
} from "./Dropdown";
export { default as EditableText } from "./EditableText";
export * from "./EditableText";
@ -48,9 +45,6 @@ export * from "./GifPlayer";
export * from "./HighlightText";
export { default as Icon } from "./Icon";
export * from "./Icon";
export { default as IconSelector } from "./IconSelector";
export * from "./IconSelector";
@ -69,9 +63,6 @@ export * from "./RectangularSwitcher";
export { default as SearchComponent } from "./SearchComponent";
export * from "./SearchComponent";
export { default as Spinner } from "./Spinner";
export * from "./Spinner";
export { default as Statusbar } from "./Statusbar";
export * from "./Statusbar";
@ -81,8 +72,6 @@ export * from "./Switch";
export { default as Switcher } from "./Switcher";
export * from "./Switcher";
export * from "./Tabs";
export { default as Table } from "./Table";
export * from "./Table";
@ -92,9 +81,6 @@ export * from "./TagInput";
export { default as Text } from "./Text";
export * from "./Text";
export { default as TextInput } from "./TextInput";
export * from "./TextInput";
export { default as TooltipComponent } from "./Tooltip";
export * from "./Tooltip";
@ -108,3 +94,5 @@ export * from "./constants/variants";
export * from "./types/common";
export * from "./utils/colors";
export * from "./utils/icon-loadables";
export * from "./utils/emailValidator";
export * from "./utils/notEmptyValidator";

View File

@ -0,0 +1,21 @@
import {
createMessage,
FORM_VALIDATION_INVALID_EMAIL,
} from "../constants/messages";
const isEmail = (value: string) => {
const re =
/^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
return re.test(value);
};
export function emailValidator(email: string) {
let isValid = true;
if (email) {
isValid = isEmail(email);
}
return {
isValid: isValid,
message: !isValid ? createMessage(FORM_VALIDATION_INVALID_EMAIL) : "",
};
}

View File

@ -0,0 +1,9 @@
import { createMessage, ERROR_MESSAGE_NAME_EMPTY } from "../constants/messages";
export function notEmptyValidator(value: string) {
const isValid = !!value;
return {
isValid: isValid,
message: !isValid ? createMessage(ERROR_MESSAGE_NAME_EMPTY) : "",
};
}

View File

@ -1,2 +1,3 @@
export * from "./Icon";
export * from "./Icon.types";
export { IconCollection } from "./Icon.provider";

View File

@ -1,6 +1,5 @@
import React from "react";
import styled from "styled-components";
import type { TabProp } from "@appsmith/ads-old";
import { getTypographyByKey } from "@appsmith/ads-old";
import type { Theme } from "constants/DefaultTheme";
@ -40,7 +39,9 @@ const Wrapper = styled.div<WrapperProps>`
`;
export default function TabItemBackgroundFill(props: {
tab: TabProp;
tab: {
title: string;
};
selected: boolean;
vertical: boolean;
}) {

View File

@ -1,8 +1,5 @@
import type {
SwitcherProps,
TreeDropdownOption,
IconName,
} from "@appsmith/ads-old";
import type { SwitcherProps, TreeDropdownOption } from "@appsmith/ads-old";
import type { IconNames } from "@appsmith/ads";
import type { EntityTypeValue, MetaArgs } from "ee/entities/DataTree/types";
import type React from "react";
import type { AdditionalDynamicDataTree } from "utils/autocomplete/customTreeTypeDefCreator";
@ -177,7 +174,7 @@ export interface FieldGroupValueType {
defaultParams: string;
value?: string;
children?: TreeDropdownOption[];
icon?: IconName;
icon?: IconNames;
}
export interface FieldGroupConfig {

View File

@ -1,10 +1,10 @@
import React from "react";
import type { CollapsibleTabProps } from "@appsmith/ads-old";
import AnalyticsUtil from "ee/utils/AnalyticsUtil";
import { DEBUGGER_TAB_KEYS } from "./Debugger/helpers";
import { Tab, TabPanel, Tabs, TabsList } from "@appsmith/ads";
import styled from "styled-components";
import { LIST_HEADER_HEIGHT, FOOTER_MARGIN } from "./Debugger/DebuggerLogs";
import type { RefObject } from "react";
const TabPanelWrapper = styled(TabPanel)`
margin-top: 0;
@ -40,8 +40,12 @@ interface EntityBottomTabsProps {
isCollapsed?: boolean;
}
type CollapsibleEntityBottomTabsProps = EntityBottomTabsProps &
CollapsibleTabProps;
type CollapsibleEntityBottomTabsProps = EntityBottomTabsProps & {
// Reference to container for collapsing or expanding content
containerRef: RefObject<HTMLDivElement>;
// height of container when expanded( usually the default height of the tab component)
expandedHeight: string;
};
// Using this if there are debugger related tabs
function EntityBottomTabs(
@ -60,23 +64,6 @@ function EntityBottomTabs(
}
};
// if (props.isCollapsed) {
// return (
// <Flex alignItems="center" gap="spaces-3" height="100%" pl="spaces-5">
// {props.tabs.map((tab) => (
// <Button
// key={tab.key}
// kind="tertiary"
// onClick={() => onTabSelect(tab.key)}
// size="md"
// >
// {tab.title}
// </Button>
// ))}
// </Flex>
// );
// }
return (
<Tabs
className="h-full"

View File

@ -66,7 +66,7 @@ const FileImportCard = styled.div<{ fillCardWidth: boolean }>`
height: 100%;
justify-content: flex-start;
.cs-icon {
.ads-v2-icon {
border-radius: 50%;
width: ${(props) => props.theme.spaces[12] + 2}px;
height: ${(props) => props.theme.spaces[12] + 2}px;
@ -113,7 +113,7 @@ const StatusbarWrapper = styled.div`
align-items: center;
justify-content: center;
.cs-icon {
.ads-v2-icon {
margin: auto;
border-radius: var(--ads-v2-border-radius-circle);
width: 32px;

View File

@ -1,41 +0,0 @@
import React from "react";
import type { BaseFieldProps } from "redux-form";
import { Field } from "redux-form";
import type { TextInputProps } from "@appsmith/ads-old";
import { TextInput } from "@appsmith/ads-old";
type RenderComponentProps = TextInputProps & {
input?: {
onChange?: (value: number) => void;
value?: number;
};
};
function RenderComponent(props: RenderComponentProps) {
const onChangeHandler = (value: number) => {
props.input && props.input.onChange && props.input.onChange(value);
};
return (
<TextInput
dataType={props.dataType}
defaultValue={props.input?.value?.toString()}
onChange={(value: string) => onChangeHandler(Number(value))}
/>
);
}
class NumberField extends React.Component<BaseFieldProps & TextInputProps> {
render() {
return (
<Field
component={RenderComponent}
{...this.props}
disabled={this.props.disabled}
noValidate
/>
);
}
}
export default NumberField;

View File

@ -1,61 +0,0 @@
import React from "react";
import type { ControlProps } from "./BaseControl";
import BaseControl from "./BaseControl";
import type { ControlType } from "constants/PropertyControlConstants";
import NumberField from "components/editorComponents/form/fields/NumberField";
import { Classes, Text, TextType } from "@appsmith/ads-old";
import styled from "styled-components";
const FormGroup = styled.div`
display: flex;
align-items: center;
.${Classes.TEXT} {
color: ${(props) => props.theme.colors.apiPane.settings.textColor};
margin-right: ${(props) => props.theme.spaces[12]}px;
}
`;
export function InputText(props: {
label: string;
value: string;
placeholder?: string;
dataType?: string;
name: string;
}) {
const { dataType, label, name, placeholder } = props;
return (
<FormGroup data-testid={name}>
<Text type={TextType.P1}>{label}</Text>
<NumberField dataType={dataType} name={name} placeholder={placeholder} />
</FormGroup>
);
}
class InputNumberControl extends BaseControl<InputControlProps> {
render() {
const { configProperty, dataType, label, placeholderText, propertyValue } =
this.props;
return (
<InputText
dataType={dataType}
label={label}
name={configProperty}
placeholder={placeholderText}
value={propertyValue}
/>
);
}
getControlType(): ControlType {
return "NUMBER_INPUT";
}
}
export interface InputControlProps extends ControlProps {
placeholderText: string;
}
export default InputNumberControl;

View File

@ -1,6 +1,5 @@
import * as React from "react";
import styled from "styled-components";
import type { TextInputProps } from "@appsmith/ads-old";
import type { ContainerOrientation } from "constants/WidgetConstants";
import { Input, Icon } from "@appsmith/ads";
import useInteractionAnalyticsEvent from "utils/hooks/useInteractionAnalyticsEvent";
@ -90,7 +89,21 @@ export const StyledNavigateToFieldsContainer = styled.div`
width: 95%;
`;
export const InputGroup = React.forwardRef((props: TextInputProps, ref) => {
interface InputGroupProps {
autoFocus?: boolean;
className?: string;
dataType?: string;
onBlur?: () => void;
onFocus?: () => void;
placeholder?: string;
value?: string;
width?: string;
onChange?: (value: string) => void;
defaultValue?: string;
tabIndex?: number;
}
export const InputGroup = React.forwardRef((props: InputGroupProps, ref) => {
let inputRef = React.useRef<HTMLInputElement>(null);
const wrapperRef = React.useRef<HTMLInputElement>(null);
const { dispatchInteractionAnalyticsEvent } =

View File

@ -1,7 +1,6 @@
import React from "react";
import type { WrappedFieldMetaProps, WrappedFieldInputProps } from "redux-form";
import { Field } from "redux-form";
import type { InputType } from "@appsmith/ads-old";
import { Input, NumberInput } from "@appsmith/ads";
import type { Intent } from "constants/DefaultTheme";
@ -48,7 +47,7 @@ export interface FormTextFieldProps {
name: string;
placeholder: string;
description?: string;
type?: InputType;
type?: "text" | "password" | "number" | "email" | "tel";
label?: React.ReactNode;
intent?: Intent;
disabled?: boolean;

View File

@ -7,7 +7,7 @@ import { Link, Text } from "@appsmith/ads";
export const HelpPopoverStyle = createGlobalStyle`
.bp3-portal {
.delete-menu-item {
.cs-icon, .cs-text {
.ads-v2-icon, .cs-text {
color: var(--appsmith-color-red-500) !important;
svg {
path {

View File

@ -2,14 +2,10 @@ import localStorage from "utils/localStorage";
import { GridDefaults } from "./WidgetConstants";
import { APP_MAX_WIDTH, type AppMaxWidth } from "@appsmith/wds-theming";
export const CANVAS_DEFAULT_HEIGHT_PX = 1292;
export const CANVAS_DEFAULT_MIN_HEIGHT_PX = 380;
export const CANVAS_DEFAULT_GRID_HEIGHT_PX = 1;
export const CANVAS_DEFAULT_GRID_WIDTH_PX = 1;
export const CANVAS_DEFAULT_MIN_ROWS = Math.ceil(
CANVAS_DEFAULT_MIN_HEIGHT_PX / GridDefaults.DEFAULT_GRID_ROW_HEIGHT,
);
export const CANVAS_BACKGROUND_COLOR = "#FFFFFF";
export const DEFAULT_ENTITY_EXPLORER_WIDTH = 256;
export const DEFAULT_PROPERTY_PANE_WIDTH = 288;
export const APP_SETTINGS_PANE_WIDTH = 525;
@ -40,7 +36,6 @@ export const getPersistentAppStore = (appId: string, branch?: string) => {
return store;
};
export const TOOLTIP_HOVER_ON_DELAY = 1000;
export const TOOLTIP_HOVER_ON_DELAY_IN_S = 1;
export const MOBILE_MAX_WIDTH = 767;
@ -63,11 +58,6 @@ export const NAVIGATION_SETTINGS = {
STATIC: "static",
STICKY: "sticky",
},
ITEM_STYLE: {
TEXT_ICON: "textIcon",
TEXT: "text",
ICON: "icon",
},
COLOR_STYLE: {
LIGHT: "light",
THEME: "theme",
@ -87,7 +77,6 @@ export interface NavigationSetting {
orientation: (typeof NAVIGATION_SETTINGS.ORIENTATION)[keyof typeof NAVIGATION_SETTINGS.ORIENTATION];
navStyle: (typeof NAVIGATION_SETTINGS.NAV_STYLE)[keyof typeof NAVIGATION_SETTINGS.NAV_STYLE];
position: (typeof NAVIGATION_SETTINGS.POSITION)[keyof typeof NAVIGATION_SETTINGS.POSITION];
itemStyle: (typeof NAVIGATION_SETTINGS.ITEM_STYLE)[keyof typeof NAVIGATION_SETTINGS.ITEM_STYLE];
colorStyle: (typeof NAVIGATION_SETTINGS.COLOR_STYLE)[keyof typeof NAVIGATION_SETTINGS.COLOR_STYLE];
logoAssetId: string;
logoConfiguration: (typeof NAVIGATION_SETTINGS.LOGO_CONFIGURATION)[keyof typeof NAVIGATION_SETTINGS.LOGO_CONFIGURATION];
@ -127,7 +116,6 @@ export const defaultNavigationSetting = {
orientation: NAVIGATION_SETTINGS.ORIENTATION.TOP,
navStyle: NAVIGATION_SETTINGS.NAV_STYLE.STACKED,
position: NAVIGATION_SETTINGS.POSITION.STATIC,
itemStyle: NAVIGATION_SETTINGS.ITEM_STYLE.TEXT,
colorStyle: NAVIGATION_SETTINGS.COLOR_STYLE.LIGHT,
logoAssetId: NAVIGATION_SETTINGS.LOGO_ASSET_ID,
logoConfiguration:

View File

@ -1,26 +0,0 @@
import React from "react";
import { Breadcrumbs } from "@appsmith/ads-old";
import { BreadcrumbCategories } from "ee/pages/AdminSettings/BreadcrumbCategories";
export const getBreadcrumbList = (category: string, subCategory?: string) => {
const breadcrumbList = [
BreadcrumbCategories.HOMEPAGE,
...(subCategory
? [BreadcrumbCategories[category], BreadcrumbCategories[subCategory]]
: [BreadcrumbCategories[category]]),
];
return breadcrumbList;
};
function SettingsBreadcrumbs({
category,
subCategory,
}: {
category: string;
subCategory?: string;
}) {
return <Breadcrumbs items={getBreadcrumbList(category, subCategory)} />;
}
export default SettingsBreadcrumbs;

View File

@ -197,7 +197,6 @@ export function Sidebar(props: SidebarProps) {
key={page.pageId}
>
<MenuItem
isMinimal={isMinimal}
key={page.pageId}
navigationSetting={
currentApplicationDetails?.applicationDetail

View File

@ -1,14 +1,10 @@
import { useLocation } from "react-router-dom";
import React, { useEffect, useLayoutEffect, useRef, useState } from "react";
// import { get } from "lodash";
// import { useSelector } from "react-redux";
import type {
ApplicationPayload,
Page,
} from "ee/constants/ReduxActionConstants";
// import { NAVIGATION_SETTINGS } from "constants/AppConstants";
import { useWindowSizeHooks } from "utils/hooks/dragResizeHooks";
// import { getSelectedAppTheme } from "selectors/appThemingSelectors";
import MenuItem from "./components/MenuItem";
import { Container } from "./TopInline.styled";
import MenuItemContainer from "./components/MenuItemContainer";
@ -21,9 +17,6 @@ import { useSelector } from "react-redux";
import { getIsAppSettingsPaneWithNavigationTabOpen } from "selectors/appSettingsPaneSelectors";
import { throttle } from "lodash";
// TODO - @Dhruvik - ImprovedAppNav
// Replace with NavigationProps if nothing changes
// appsmith/app/client/src/pages/AppViewer/Navigation/constants.ts
interface TopInlineProps {
currentApplicationDetails?: ApplicationPayload;
pages: Page[];
@ -31,15 +24,6 @@ interface TopInlineProps {
export function TopInline(props: TopInlineProps) {
const { currentApplicationDetails, pages } = props;
// const selectedTheme = useSelector(getSelectedAppTheme);
// const navColorStyle =
// currentApplicationDetails?.applicationDetail?.navigationSetting?.colorStyle ||
// NAVIGATION_SETTINGS.COLOR_STYLE.LIGHT;
// const primaryColor = get(
// selectedTheme,
// "properties.colors.primaryColor",
// "inherit",
// );
const location = useLocation();
const { pathname } = location;
const [query, setQuery] = useState("");

View File

@ -10,9 +10,7 @@ import { builderURL, viewerURL } from "ee/RouteBuilder";
import { getAppMode } from "ee/selectors/applicationSelectors";
import { getSelectedAppTheme } from "selectors/appThemingSelectors";
import { trimQueryString } from "utils/helpers";
import { Icon } from "@appsmith/ads-old";
import MenuText from "./MenuText";
import classNames from "classnames";
import { StyledMenuItem } from "./MenuItem.styled";
import { NavigationMethod } from "utils/history";
@ -20,15 +18,9 @@ interface MenuItemProps {
page: Page;
query: string;
navigationSetting?: NavigationSetting;
isMinimal?: boolean;
}
const MenuItem = ({
isMinimal,
navigationSetting,
page,
query,
}: MenuItemProps) => {
const MenuItem = ({ navigationSetting, page, query }: MenuItemProps) => {
const appMode = useSelector(getAppMode);
const pageURL = useHref(
appMode === APP_MODE.PUBLISHED ? viewerURL : builderURL,
@ -61,28 +53,11 @@ const MenuItem = ({
state: { invokedBy: NavigationMethod.AppNavigation },
}}
>
{navigationSetting?.itemStyle !== NAVIGATION_SETTINGS.ITEM_STYLE.TEXT && (
<Icon
className={classNames({
"page-icon": true,
"mr-2":
navigationSetting?.itemStyle ===
NAVIGATION_SETTINGS.ITEM_STYLE.TEXT_ICON && !isMinimal,
"mx-auto": isMinimal,
})}
name="file-line"
// @ts-expect-error Fix this the next time the file is edited
size="large"
/>
)}
{navigationSetting?.itemStyle !== NAVIGATION_SETTINGS.ITEM_STYLE.ICON &&
!isMinimal && (
<MenuText
name={page.pageName}
navColorStyle={navColorStyle}
primaryColor={primaryColor}
/>
)}
<MenuText
name={page.pageName}
navColorStyle={navColorStyle}
primaryColor={primaryColor}
/>
</StyledMenuItem>
);
};

View File

@ -6,7 +6,6 @@ import { useSelector } from "react-redux";
import { getSelectedAppTheme } from "selectors/appThemingSelectors";
import { Icon } from "@appsmith/ads";
import MenuText from "./MenuText";
import classNames from "classnames";
import {
StyledMenuDropdownContainer,
StyledMenuItemInDropdown,
@ -57,32 +56,14 @@ const MoreDropdownButton = ({
}}
primaryColor={primaryColor}
>
{navigationSetting?.itemStyle !==
NAVIGATION_SETTINGS.ITEM_STYLE.TEXT && (
<Icon
className={classNames({
"page-icon": true,
"mr-2":
navigationSetting?.itemStyle ===
NAVIGATION_SETTINGS.ITEM_STYLE.TEXT_ICON,
})}
name="context-menu"
size="md"
<>
<MenuText
name="More"
navColorStyle={navColorStyle}
primaryColor={primaryColor}
/>
)}
{navigationSetting?.itemStyle !==
NAVIGATION_SETTINGS.ITEM_STYLE.ICON && (
<>
<MenuText
name="More"
navColorStyle={navColorStyle}
primaryColor={primaryColor}
/>
{/*@ts-expect-error Fix this the next time the file is edited*/}
<Icon className="page-icon ml-2" name="expand-more" size="large" />
</>
)}
<Icon className="page-icon ml-2" name="expand-more" size="md" />
</>
</StyleMoreDropdownButton>
</div>
);
@ -124,25 +105,11 @@ const MoreDropdownButton = ({
state: { invokedBy: NavigationMethod.AppNavigation },
}}
>
{navigationSetting?.itemStyle !==
NAVIGATION_SETTINGS.ITEM_STYLE.TEXT && (
<Icon
className={classNames({
"page-icon mr-2": true,
})}
name="file-line"
// @ts-expect-error Fix this the next time the file is edited
size="large"
/>
)}
{navigationSetting?.itemStyle !==
NAVIGATION_SETTINGS.ITEM_STYLE.ICON && (
<MenuText
name={page.pageName}
navColorStyle={navColorStyle}
primaryColor={primaryColor}
/>
)}
<MenuText
name={page.pageName}
navColorStyle={navColorStyle}
primaryColor={primaryColor}
/>
</StyledMenuItemInDropdown>
);
})}

View File

@ -97,7 +97,7 @@ const DatasourceCard = styled.div`
opacity: 0;
visibility: hidden;
}
.cs-icon {
.ads-v2-icon {
opacity: 0;
transition: 0.3s all ease;
}
@ -107,7 +107,7 @@ const DatasourceCard = styled.div`
}
&:hover {
background-color: var(--ads-v2-color-bg-subtle);
.cs-icon {
.ads-v2-icon {
opacity: 1;
}
}

View File

@ -2,11 +2,6 @@ import React, { useCallback, useEffect, useState } from "react";
import { useDispatch, useSelector } from "react-redux";
import { getCurrentApplication } from "ee/selectors/applicationSelectors";
import { APP_NAVIGATION_SETTING, createMessage } from "ee/constants/messages";
// import { ReactComponent as NavOrientationTopIcon } from "assets/icons/settings/nav-orientation-top.svg";
// import { ReactComponent as NavOrientationSideIcon } from "assets/icons/settings/nav-orientation-side.svg";
// import { ReactComponent as NavStyleInlineIcon } from "assets/icons/settings/nav-style-inline.svg";
// import { ReactComponent as NavStyleStackedIcon } from "assets/icons/settings/nav-style-stacked.svg";
// import { ReactComponent as NavStyleSidebarIcon } from "assets/icons/settings/nav-style-sidebar.svg";
import type { NavigationSetting } from "constants/AppConstants";
import { NAVIGATION_SETTINGS } from "constants/AppConstants";
import _, { debounce, isEmpty, isPlainObject } from "lodash";
@ -22,15 +17,6 @@ import LogoInput from "pages/Editor/NavigationSettings/LogoInput";
import SwitchSettingForLogoConfiguration from "./SwitchSettingForLogoConfiguration";
import { selectFeatureFlags } from "ee/selectors/featureFlagsSelectors";
/**
* TODO - @Dhruvik - ImprovedAppNav
* Revisit these imports in v1.1
* https://www.notion.so/appsmith/Ship-Faster-33b32ed5b6334810a0b4f42e03db4a5b?pvs=4
*/
// import { ReactComponent as NavPositionStickyIcon } from "assets/icons/settings/nav-position-sticky.svg";
// import { ReactComponent as NavPositionStaticIcon } from "assets/icons/settings/nav-position-static.svg";
// import { ReactComponent as NavStyleMinimalIcon } from "assets/icons/settings/nav-style-minimal.svg";
export type UpdateSetting = (
key: keyof NavigationSetting,
value: NavigationSetting[keyof NavigationSetting],
@ -158,32 +144,6 @@ function NavigationSettings() {
: NAVIGATION_SETTINGS.NAV_STYLE.SIDEBAR;
}
/**
* TODO - @Dhruvik - ImprovedAppNav
* Uncomment to change these settings automatically in v1.1
* https://www.notion.so/appsmith/Ship-Faster-33b32ed5b6334810a0b4f42e03db4a5b
*
* When the orientation is side and nav style changes -
* 1. to minimal, change the item style to icon
* 1. to sidebar, change the item style to text + icon
*/
// if (
// newSettings.orientation ===
// NAVIGATION_SETTINGS.ORIENTATION.SIDE &&
// navigationSetting.navStyle !== newSettings.navStyle
// ) {
// if (
// newSettings.navStyle === NAVIGATION_SETTINGS.NAV_STYLE.MINIMAL
// ) {
// newSettings.itemStyle = NAVIGATION_SETTINGS.ITEM_STYLE.ICON;
// } else if (
// newSettings.navStyle === NAVIGATION_SETTINGS.NAV_STYLE.SIDEBAR
// ) {
// newSettings.itemStyle =
// NAVIGATION_SETTINGS.ITEM_STYLE.TEXT_ICON;
// }
// }
payload.applicationDetail = {
navigationSetting: newSettings,
};
@ -225,23 +185,15 @@ function NavigationSettings() {
{
label: _.startCase(NAVIGATION_SETTINGS.ORIENTATION.TOP),
value: NAVIGATION_SETTINGS.ORIENTATION.TOP,
// startIcon:<NavOrientationTopIcon />,
},
{
label: _.startCase(NAVIGATION_SETTINGS.ORIENTATION.SIDE),
value: NAVIGATION_SETTINGS.ORIENTATION.SIDE,
// startIcon:<NavOrientationSideIcon />,
},
]}
updateSetting={updateSetting}
/>
{/**
* TODO - @Dhruvik - ImprovedAppNav
* Remove check for orientation = top when adding sidebar minimal to show sidebar
* variants as well.
* https://www.notion.so/appsmith/Ship-Faster-33b32ed5b6334810a0b4f42e03db4a5b
*/}
{navigationSetting?.orientation ===
NAVIGATION_SETTINGS.ORIENTATION.TOP && (
<ButtonGroupSetting
@ -252,7 +204,6 @@ function NavigationSettings() {
{
label: _.startCase(NAVIGATION_SETTINGS.NAV_STYLE.STACKED),
value: NAVIGATION_SETTINGS.NAV_STYLE.STACKED,
// startIcon:<NavStyleStackedIcon />,
hidden:
navigationSetting?.orientation ===
NAVIGATION_SETTINGS.ORIENTATION.SIDE,
@ -260,7 +211,6 @@ function NavigationSettings() {
{
label: _.startCase(NAVIGATION_SETTINGS.NAV_STYLE.INLINE),
value: NAVIGATION_SETTINGS.NAV_STYLE.INLINE,
// startIcon:<NavStyleInlineIcon />,
hidden:
navigationSetting?.orientation ===
NAVIGATION_SETTINGS.ORIENTATION.SIDE,
@ -268,90 +218,15 @@ function NavigationSettings() {
{
label: _.startCase(NAVIGATION_SETTINGS.NAV_STYLE.SIDEBAR),
value: NAVIGATION_SETTINGS.NAV_STYLE.SIDEBAR,
// startIcon:<NavStyleSidebarIcon />,
hidden:
navigationSetting?.orientation ===
NAVIGATION_SETTINGS.ORIENTATION.TOP,
},
/**
* TODO - @Dhruvik - ImprovedAppNav
* Hiding minimal sidebar for v1
* https://www.notion.so/appsmith/Ship-Faster-33b32ed5b6334810a0b4f42e03db4a5b
*/
// {
// label: _.startCase(NAVIGATION_SETTINGS.NAV_STYLE.MINIMAL),
// value: NAVIGATION_SETTINGS.NAV_STYLE.MINIMAL,
// startIcon:<NavStyleMinimalIcon />,
// hidden:
// navigationSetting?.orientation ===
// NAVIGATION_SETTINGS.ORIENTATION.TOP,
// },
]}
updateSetting={updateSetting}
/>
)}
{/**
* TODO - @Dhruvik - ImprovedAppNav
* Hiding position for v1
* https://www.notion.so/appsmith/Logo-configuration-option-can-be-multiselect-2a436598539c4db99d1f030850fd8918?pvs=4
*/}
{/* <ButtonGroupSetting
heading={createMessage(APP_NAVIGATION_SETTING.positionLabel)}
keyName="position"
navigationSetting={navigationSetting}
options={[
{
label: _.startCase(NAVIGATION_SETTINGS.POSITION.STATIC),
value: NAVIGATION_SETTINGS.POSITION.STATIC,
startIcon:<NavPositionStaticIcon />,
},
{
label: _.startCase(NAVIGATION_SETTINGS.POSITION.STICKY),
value: NAVIGATION_SETTINGS.POSITION.STICKY,
startIcon:<NavPositionStickyIcon />,
},
]}
updateSetting={updateSetting}
/> */}
{/**
* TODO - @Dhruvik - ImprovedAppNav
* Hiding item style for v1
* https://www.notion.so/appsmith/Logo-configuration-option-can-be-multiselect-2a436598539c4db99d1f030850fd8918?pvs=4
*/}
{/* <ButtonGroupSetting
heading={createMessage(APP_NAVIGATION_SETTING.itemStyleLabel)}
keyName="itemStyle"
navigationSetting={navigationSetting}
options={[
{
label: "Text + Icon",
value: NAVIGATION_SETTINGS.ITEM_STYLE.TEXT_ICON,
hidden:
navigationSetting?.navStyle ===
NAVIGATION_SETTINGS.NAV_STYLE.MINIMAL,
},
{
label: _.startCase(NAVIGATION_SETTINGS.ITEM_STYLE.TEXT),
value: NAVIGATION_SETTINGS.ITEM_STYLE.TEXT,
hidden:
navigationSetting?.navStyle ===
NAVIGATION_SETTINGS.NAV_STYLE.MINIMAL,
},
{
label: _.startCase(NAVIGATION_SETTINGS.ITEM_STYLE.ICON),
value: NAVIGATION_SETTINGS.ITEM_STYLE.ICON,
hidden:
navigationSetting?.orientation ===
NAVIGATION_SETTINGS.ORIENTATION.SIDE &&
navigationSetting?.navStyle ===
NAVIGATION_SETTINGS.NAV_STYLE.SIDEBAR,
},
]}
updateSetting={updateSetting}
/> */}
<ButtonGroupSetting
heading={createMessage(APP_NAVIGATION_SETTING.colorStyleLabel)}
keyName="colorStyle"

View File

@ -9,7 +9,7 @@ const SectionLabel = styled.div`
letter-spacing: -0.17px;
color: var(--ads-v2-color-fg);
display: flex;
.cs-icon {
.ads-v2-icon {
margin-left: ${(props) => props.theme.spaces[2]}px;
}
`;

View File

@ -22,7 +22,6 @@ export type EditableAppNameProps = CommonComponentProps & {
onBlur?: (value: string) => void;
isEditingDefault?: boolean;
inputValidation?: (value: string) => string | boolean;
hideEditIcon?: boolean;
fill?: boolean;
isError?: boolean;
isEditing: boolean;

View File

@ -123,7 +123,6 @@ export function EditorName(props: EditorNameProps) {
defaultValue={defaultValue}
editInteractionKind={props.editInteractionKind}
fill={props.fill}
hideEditIcon
inputValidation={inputValidation}
isEditing={isEditing}
isEditingDefault={isEditingDefault}

View File

@ -52,7 +52,7 @@ const Wrapper = styled.div`
margin-bottom: 16px;
.left-icon {
margin-left: 14px;
.cs-icon {
.ads-v2-icon {
margin-right: 0;
}
}

View File

@ -372,7 +372,6 @@ function GeneratePageForm() {
value: column.name,
subText: column.type,
icon: columnIcon,
// @ts-expect-error Fix this the next time the file is edited
iconSize: "md",
iconColor: "var(--ads-v2-color-fg)",
});
@ -448,8 +447,7 @@ function GeneratePageForm() {
iconSize: "md",
iconColor: "var(--ads-v2-color-fg)",
}));
// @ts-expect-error Fix this the next time the file is edited
setSelectedDatasourceTableOptions(tables);
setSelectedDatasourceTableOptions(tables as DropdownOptions);
}
}, [bucketList, isS3Plugin, setSelectedDatasourceTableOptions]);
@ -482,8 +480,7 @@ function GeneratePageForm() {
columns,
},
}));
// @ts-expect-error Fix this the next time the file is edited
setSelectedDatasourceTableOptions(newTables);
setSelectedDatasourceTableOptions(newTables as DropdownOptions);
}
}
}
@ -774,9 +771,7 @@ function GeneratePageForm() {
<StyledIconWrapper>
<Icon
color={table?.iconColor}
// @ts-expect-error Fix this the next time the file is edited
name={table.icon}
// @ts-expect-error Fix this the next time the file is edited
name={table.icon as string}
size={table.iconSize}
/>
</StyledIconWrapper>
@ -849,9 +844,7 @@ function GeneratePageForm() {
<StyledIconWrapper>
<Icon
color={column?.iconColor}
// @ts-expect-error Fix this the next time the file is edited
name={column.icon}
// @ts-expect-error Fix this the next time the file is edited
name={column.icon as string}
size={column.iconSize}
/>
</StyledIconWrapper>

View File

@ -1,403 +0,0 @@
import React from "react";
import { connect } from "react-redux";
import type { InjectedFormProps } from "redux-form";
import { reduxForm } from "redux-form";
import styled from "styled-components";
import type { AppState } from "ee/reducers";
import { API_HOME_SCREEN_FORM } from "ee/constants/forms";
import ActiveDataSources from "./ActiveDataSources";
import {
getDatasources,
getMockDatasources,
} from "ee/selectors/entitiesSelector";
import type { Datasource, MockDatasource } from "entities/Datasource";
import type { TabProp } from "@appsmith/ads-old";
import { IconSize } from "@appsmith/ads-old";
import { INTEGRATION_TABS, INTEGRATION_EDITOR_MODES } from "constants/routes";
import BackButton from "../DataSourceEditor/BackButton";
import UnsupportedPluginDialog from "./UnsupportedPluginDialog";
import { getQueryParams } from "utils/URLUtils";
import { getIsGeneratePageInitiator } from "utils/GenerateCrudUtil";
import { getCurrentApplicationId } from "selectors/editorSelectors";
import { integrationEditorURL } from "ee/RouteBuilder";
import { getCurrentAppWorkspace } from "ee/selectors/selectedWorkspaceSelectors";
import { Tab, TabPanel, Tabs, TabsList } from "@appsmith/ads";
import Debugger, {
ResizerContentContainer,
ResizerMainContainer,
} from "../DataSourceEditor/Debugger";
import { showDebuggerFlag } from "selectors/debuggerSelectors";
import AnalyticsUtil from "ee/utils/AnalyticsUtil";
import { DatasourceCreateEntryPoints } from "constants/Datasource";
import { selectFeatureFlags } from "ee/selectors/featureFlagsSelectors";
import { isGACEnabled } from "ee/utils/planHelpers";
import { getHasCreateDatasourcePermission } from "ee/utils/BusinessFeatures/permissionPageHelpers";
import CreateNewDatasourceTab from "./CreateNewDatasourceTab";
const HeaderFlex = styled.div`
font-size: 20px;
display: flex;
align-items: center;
color: var(--ads-v2-color-fg-emphasis-plus);
padding: 0 var(--ads-v2-spaces-7);
`;
const ApiHomePage = styled.div`
display: flex;
flex-direction: column;
padding-top: 20px;
/* margin-left: 10px; */
flex: 1;
overflow: hidden !important;
.closeBtn {
position: absolute;
left: 70%;
}
.fontSize16 {
font-size: 16px;
}
.integrations-content-container {
padding: 0 var(--ads-v2-spaces-7);
}
.t--vertical-menu {
overflow: auto;
}
`;
const MainTabsContainer = styled.div`
width: 100%;
height: 100%;
padding: 0 var(--ads-v2-spaces-7);
/* .react-tabs__tab-list {
margin: 2px;
} */
`;
const SectionGrid = styled.div<{ isActiveTab?: boolean }>`
margin-top: 16px;
display: grid;
grid-template-columns: 1fr;
grid-template-rows: auto minmax(0, 1fr);
gap: 10px 16px;
flex: 1;
min-height: 100%;
`;
interface IntegrationsHomeScreenProps {
basePageId: string;
selectedTab: string;
location: {
search: string;
pathname: string;
};
history: {
replace: (data: string) => void;
push: (data: string) => void;
};
isCreating: boolean;
dataSources: Datasource[];
mockDatasources: MockDatasource[];
applicationId: string;
canCreateDatasource?: boolean;
showDebugger: boolean;
}
interface IntegrationsHomeScreenState {
page: number;
activePrimaryMenuId: string;
activeSecondaryMenuId: number;
unsupportedPluginDialogVisible: boolean;
}
type Props = IntegrationsHomeScreenProps &
InjectedFormProps<{ category: string }, IntegrationsHomeScreenProps>;
const PRIMARY_MENU_IDS = {
ACTIVE: "ACTIVE",
CREATE_NEW: "CREATE_NEW",
};
const getSecondaryMenuIds = (hasActiveSources = false) => {
return {
API: 0 + (hasActiveSources ? 0 : 1),
DATABASE: 1 + (hasActiveSources ? 0 : 1),
MOCK_DATABASE: 2 - (hasActiveSources ? 0 : 2),
};
};
const TERTIARY_MENU_IDS = {
ACTIVE_CONNECTIONS: 0,
MOCK_DATABASE: 1,
};
class IntegrationsHomeScreen extends React.Component<
Props,
IntegrationsHomeScreenState
> {
unsupportedPluginContinueAction: () => void;
constructor(props: Props) {
super(props);
this.unsupportedPluginContinueAction = () => null;
this.state = {
page: 1,
activePrimaryMenuId: PRIMARY_MENU_IDS.CREATE_NEW,
activeSecondaryMenuId: getSecondaryMenuIds(
props.mockDatasources.length > 0,
).API,
unsupportedPluginDialogVisible: false,
};
}
syncActivePrimaryMenu = () => {
// on mount/update if syncing the primary active menu.
const { selectedTab } = this.props;
if (
(selectedTab === INTEGRATION_TABS.NEW &&
this.state.activePrimaryMenuId !== PRIMARY_MENU_IDS.CREATE_NEW) ||
(selectedTab === INTEGRATION_TABS.ACTIVE &&
this.state.activePrimaryMenuId !== PRIMARY_MENU_IDS.ACTIVE)
) {
this.setState({
activePrimaryMenuId:
selectedTab === INTEGRATION_TABS.NEW
? PRIMARY_MENU_IDS.CREATE_NEW
: PRIMARY_MENU_IDS.ACTIVE,
});
}
};
componentDidMount() {
const { basePageId, dataSources, history } = this.props;
const queryParams = getQueryParams();
const redirectMode = queryParams.mode;
const isGeneratePageInitiator = getIsGeneratePageInitiator();
if (isGeneratePageInitiator) {
if (redirectMode === INTEGRATION_EDITOR_MODES.AUTO) {
delete queryParams.mode;
delete queryParams.from;
history.replace(
integrationEditorURL({
basePageId,
selectedTab: INTEGRATION_TABS.NEW,
params: queryParams,
}),
);
}
} else if (
dataSources.length > 0 &&
redirectMode === INTEGRATION_EDITOR_MODES.AUTO
) {
// User will be taken to active tab if there are datasources
history.replace(
integrationEditorURL({
basePageId,
selectedTab: INTEGRATION_TABS.ACTIVE,
}),
);
} else if (redirectMode === INTEGRATION_EDITOR_MODES.MOCK) {
// If there are no datasources -> new user
history.replace(
integrationEditorURL({
basePageId,
selectedTab: INTEGRATION_TABS.NEW,
}),
);
this.onSelectSecondaryMenu(
getSecondaryMenuIds(dataSources.length > 0).MOCK_DATABASE,
);
} else {
this.syncActivePrimaryMenu();
}
}
componentDidUpdate(prevProps: Props) {
this.syncActivePrimaryMenu();
const { basePageId, dataSources, history } = this.props;
if (dataSources.length === 0 && prevProps.dataSources.length > 0) {
history.replace(
integrationEditorURL({
basePageId,
selectedTab: INTEGRATION_TABS.NEW,
}),
);
this.onSelectSecondaryMenu(
getSecondaryMenuIds(dataSources.length > 0).MOCK_DATABASE,
);
}
}
onSelectPrimaryMenu = (activePrimaryMenuId: string) => {
const { basePageId, dataSources, history } = this.props;
if (activePrimaryMenuId === this.state.activePrimaryMenuId) {
return;
}
history.push(
integrationEditorURL({
basePageId,
selectedTab:
activePrimaryMenuId === PRIMARY_MENU_IDS.ACTIVE
? INTEGRATION_TABS.ACTIVE
: INTEGRATION_TABS.NEW,
}),
);
this.setState({
activeSecondaryMenuId:
activePrimaryMenuId === PRIMARY_MENU_IDS.ACTIVE
? TERTIARY_MENU_IDS.ACTIVE_CONNECTIONS
: getSecondaryMenuIds(dataSources.length > 0).API,
});
};
onSelectSecondaryMenu = (activeSecondaryMenuId: number) => {
this.setState({ activeSecondaryMenuId });
};
render() {
const {
basePageId,
canCreateDatasource = false,
dataSources,
location,
showDebugger,
} = this.props;
const { unsupportedPluginDialogVisible } = this.state;
let currentScreen;
const { activePrimaryMenuId } = this.state;
const PRIMARY_MENU: TabProp[] = [
{
key: "ACTIVE",
title: "Active",
panelComponent: <div />,
},
...(canCreateDatasource
? [
{
key: "CREATE_NEW",
title: "Create new",
panelComponent: <div />,
icon: "plus",
iconSize: IconSize.XS,
},
]
: []),
].filter(Boolean);
const isGeneratePageInitiator = getIsGeneratePageInitiator();
// Avoid user to switch tabs when in generate page flow by hiding the tabs itself.
const showTabs = !isGeneratePageInitiator;
if (activePrimaryMenuId === PRIMARY_MENU_IDS.CREATE_NEW) {
currentScreen = <CreateNewDatasourceTab />;
} else {
currentScreen = (
<ActiveDataSources
basePageId={basePageId}
dataSources={dataSources}
history={this.props.history}
location={location}
onCreateNew={() => {
this.onSelectPrimaryMenu(PRIMARY_MENU_IDS.CREATE_NEW);
// Event for datasource creation click
const entryPoint = DatasourceCreateEntryPoints.ACTIVE_DATASOURCE;
AnalyticsUtil.logEvent("NAVIGATE_TO_CREATE_NEW_DATASOURCE_PAGE", {
entryPoint,
});
}}
/>
);
}
return (
<>
<BackButton />
<UnsupportedPluginDialog
isModalOpen={unsupportedPluginDialogVisible}
onClose={() =>
this.setState({ unsupportedPluginDialogVisible: false })
}
onContinue={this.unsupportedPluginContinueAction}
/>
<ApiHomePage
className="t--integrationsHomePage"
style={{ overflow: "auto" }}
>
<HeaderFlex>
<p className="sectionHeadings">Datasources in your workspace</p>
</HeaderFlex>
<SectionGrid
isActiveTab={
this.state.activePrimaryMenuId !== PRIMARY_MENU_IDS.ACTIVE
}
>
<MainTabsContainer>
{showTabs && (
<Tabs
data-testid="t--datasource-tab"
onValueChange={this.onSelectPrimaryMenu}
value={this.state.activePrimaryMenuId}
>
<TabsList>
{PRIMARY_MENU.map((tab: TabProp) => (
<Tab
data-testid={`t--tab-${tab.key}`}
key={tab.key}
value={tab.key}
>
{tab.title}
</Tab>
))}
</TabsList>
{PRIMARY_MENU.map((tab: TabProp) => (
<TabPanel key={tab.key} value={tab.key}>
{tab.panelComponent}
</TabPanel>
))}
</Tabs>
)}
</MainTabsContainer>
<ResizerMainContainer>
<ResizerContentContainer className="integrations-content-container">
{currentScreen}
</ResizerContentContainer>
{showDebugger && <Debugger />}
</ResizerMainContainer>
</SectionGrid>
</ApiHomePage>
</>
);
}
}
const mapStateToProps = (state: AppState) => {
// Debugger render flag
const showDebugger = showDebuggerFlag(state);
const userWorkspacePermissions =
getCurrentAppWorkspace(state).userPermissions ?? [];
const featureFlags = selectFeatureFlags(state);
const isFeatureEnabled = isGACEnabled(featureFlags);
const canCreateDatasource = getHasCreateDatasourcePermission(
isFeatureEnabled,
userWorkspacePermissions,
);
return {
dataSources: getDatasources(state),
mockDatasources: getMockDatasources(state),
isCreating: state.ui.apiPane.isCreating,
applicationId: getCurrentApplicationId(state),
canCreateDatasource,
showDebugger,
};
};
export default connect(mapStateToProps)(
reduxForm<{ category: string }, IntegrationsHomeScreenProps>({
form: API_HOME_SCREEN_FORM,
})(IntegrationsHomeScreen),
);

View File

@ -1,33 +0,0 @@
import React from "react";
import IntegrationsHomeScreen from "./IntegrationsHomeScreen";
import type { RouteComponentProps } from "react-router";
import * as Sentry from "@sentry/react";
type Props = RouteComponentProps<{
basePageId: string;
selectedTab: string;
}>;
const integrationsEditor = (props: Props) => {
const { history, location, match } = props;
return (
<div
style={{
position: "relative",
height: "100%",
display: "flex",
flexDirection: "column",
}}
>
<IntegrationsHomeScreen
basePageId={match.params.basePageId}
history={history}
location={location}
selectedTab={match.params.selectedTab}
/>
</div>
);
};
export default Sentry.withProfiler(integrationsEditor);

View File

@ -1,20 +0,0 @@
import styled from "styled-components";
import { MenuItem } from "@appsmith/ads-old";
import { Colors } from "constants/Colors";
const DangerMenuItem = styled(MenuItem)`
&&,
&& .cs-text {
color: ${Colors.DANGER_SOLID};
}
&&,
&&:hover {
svg,
svg path {
fill: ${Colors.DANGER_SOLID};
}
}
`;
export default DangerMenuItem;

View File

@ -50,7 +50,7 @@ const DsTitle = styled.div`
text-overflow: ellipsis;
padding-right: 4px;
}
.cs-icon {
.ads-v2-icon {
margin-left: ${(props) => props.theme.spaces[2]}px;
}
`;

View File

@ -1,73 +0,0 @@
import React from "react";
import type {
DefaultDropDownValueNodeProps,
DropdownOption,
} from "@appsmith/ads-old";
import {
Dropdown,
DropdownWrapper,
DropdownContainer as DropdownComponentContainer,
} from "@appsmith/ads-old";
import { Colors } from "constants/Colors";
import styled from "styled-components";
import { Classes as GitSyncClasses } from "pages/Editor/gitSync/constants";
import { importSvg } from "@appsmith/ads-old";
const ChevronDown = importSvg(
async () => import("assets/icons/ads/chevron-down.svg"),
);
const SelectedValueNodeContainer = styled.div`
color: ${Colors.CRUSTA};
display: flex;
align-items: center;
& .label {
margin-right: ${(props) => props.theme.spaces[2]}px;
}
`;
function SelectedValueNode(props: DefaultDropDownValueNodeProps) {
const { selected } = props;
return (
<SelectedValueNodeContainer>
<span className="label">{(selected as DropdownOption).label}</span>
<ChevronDown />
</SelectedValueNodeContainer>
);
}
const DropdownContainer = styled.div`
& ${DropdownComponentContainer} {
width: max-content;
}
&&&& ${DropdownWrapper} {
padding: 0;
}
`;
interface OptionSelectorProps {
options: DropdownOption[];
selected: DropdownOption;
// TODO: Fix this the next time the file is edited
// eslint-disable-next-line @typescript-eslint/no-explicit-any
onSelect?: (value?: string, dropdownOption?: any) => void;
}
function OptionSelector({ onSelect, options, selected }: OptionSelectorProps) {
return (
<DropdownContainer className={GitSyncClasses.OPTION_SELECTOR_WRAPPER}>
<Dropdown
SelectedValueNode={SelectedValueNode}
bgColor={"transparent"}
className="auth-type-dropdown"
onSelect={onSelect}
options={options}
selected={selected}
showDropIcon={false}
showLabelOnly
/>
</DropdownContainer>
);
}
export default OptionSelector;

View File

@ -1,7 +1,6 @@
import React from "react";
import styled from "styled-components";
import type { Theme } from "constants/DefaultTheme";
import type { TabProp } from "@appsmith/ads-old";
import { getTypographyByKey } from "@appsmith/ads-old";
import { Colors } from "constants/Colors";
@ -40,7 +39,10 @@ const Wrapper = styled.div<WrapperProps>`
`;
export default function TabItem(props: {
tab: TabProp;
tab: {
key: string;
title: string;
};
selected: boolean;
vertical: boolean;
}) {

View File

@ -75,7 +75,7 @@ const FileImportCard = styled.div<{ fillCardWidth: boolean }>`
height: 100%;
justify-content: flex-start;
.cs-icon {
.ads-v2-icon {
border-radius: 50%;
width: ${(props) => props.theme.spaces[12] + 2}px;
height: ${(props) => props.theme.spaces[12] + 2}px;
@ -146,7 +146,7 @@ const StatusbarWrapper = styled.div`
align-items: center;
justify-content: center;
.cs-icon {
.ads-v2-icon {
margin: auto;
border-radius: var(--ads-v2-border-radius-circle);
width: 32px;

View File

@ -62,7 +62,7 @@ const UserNameSection = styled.div`
const StyledMenuItem = styled(MenuItem)`
svg,
.cs-icon svg path {
.ads-v2-icon svg path {
width: 18px;
height: 18px;
fill: var(--ads-v2-color-fg);

View File

@ -40,11 +40,9 @@ const ApplicationSearchItem = (props: Props) => {
>
<CircleAppIcon
className="!mr-1"
color="var(--ads-v2-color-fg)"
// @ts-expect-error Fix this the next time the file is edited
name={
application?.icon ||
(getApplicationIcon(application.id) as AppIconName)
(application?.icon ||
getApplicationIcon(application.id)) as AppIconName
}
size={Size.xxs}
/>

View File

@ -1,27 +0,0 @@
import React, { useState } from "react";
import { useDispatch, useSelector } from "react-redux";
import { setThemeMode } from "actions/themeActions";
import { MenuItem, RectangularSwitcher } from "@appsmith/ads-old";
import { getCurrentThemeMode, ThemeMode } from "selectors/themeSelectors";
export default function ThemeSwitcher(props: { className?: string }) {
const dispatch = useDispatch();
const themeMode = useSelector(getCurrentThemeMode);
const [switchedOn, setSwitchOn] = useState(themeMode === ThemeMode.DARK);
return (
<MenuItem
label={
<RectangularSwitcher
className={props.className}
onSwitch={(value: boolean) => {
setSwitchOn(value);
dispatch(setThemeMode(value ? ThemeMode.DARK : ThemeMode.LIGHT));
}}
value={switchedOn}
/>
}
text="Theme"
/>
);
}

View File

@ -1,5 +1,3 @@
// import React, { JSXElementConstructor } from "react";
// import { IconProps, IconWrapper } from "constants/IconConstants";
import type React from "react";
import { Alignment, Classes } from "@blueprintjs/core";
import { Classes as DTClasses } from "@blueprintjs/datetime";
@ -112,7 +110,6 @@ export const hexToRgba = (color: string, alpha: number) => {
};
const ALPHANUMERIC = "1234567890abcdefghijklmnopqrstuvwxyz";
// const ALPHABET = "abcdefghijklmnopqrstuvwxyz";
export const generateReactKey = ({
prefix = "",