+
);
+
+export const BorderlessAppIcon = () => (
+
+);
diff --git a/app/client/src/components/stories/IconSelector.stories.tsx b/app/client/src/components/stories/IconSelector.stories.tsx
new file mode 100644
index 0000000000..9058aad848
--- /dev/null
+++ b/app/client/src/components/stories/IconSelector.stories.tsx
@@ -0,0 +1,54 @@
+import React from "react";
+import { withKnobs, select, boolean, text } from "@storybook/addon-knobs";
+import { withDesign } from "storybook-addon-designs";
+import IconSelector from "../ads/IconSelector";
+import { action } from "@storybook/addon-actions";
+import { AppIconName } from "../ads/AppIcon";
+
+export default {
+ title: "IconSelector",
+ component: IconSelector,
+ decorators: [withKnobs, withDesign],
+};
+
+export const IconPicker = () => (
+
+
+
+);
diff --git a/app/client/src/components/stories/Table.stories.tsx b/app/client/src/components/stories/Table.stories.tsx
index 5144f8ae7f..1e40156835 100644
--- a/app/client/src/components/stories/Table.stories.tsx
+++ b/app/client/src/components/stories/Table.stories.tsx
@@ -1,7 +1,7 @@
import React from "react";
import Table from "../ads/Table";
import Button, { Category, Variant, Size } from "../ads/Button";
-import { Icon } from "../ads/Icon";
+import Icon from "../ads/Icon";
export default {
title: "Table",
From 6ff6b5e1a1aa90bc016e4401bd19722ef12c163e Mon Sep 17 00:00:00 2001
From: devrk96
Date: Wed, 26 Aug 2020 12:55:27 +0530
Subject: [PATCH 05/11] Search input component (#403)
* search input implemented with both variant
* classname bug resolved in icon component
* PR comments resolved
* ellipsis added for long search keywords
---
app/client/src/assets/icons/ads/close.svg | 3 +
app/client/src/assets/icons/ads/search.svg | 4 +
app/client/src/components/ads/Icon.tsx | 13 +-
app/client/src/components/ads/SearchInput.tsx | 138 ++++++++++++++++++
.../stories/SearchInput.stories.tsx | 26 ++++
5 files changed, 183 insertions(+), 1 deletion(-)
create mode 100644 app/client/src/assets/icons/ads/close.svg
create mode 100644 app/client/src/assets/icons/ads/search.svg
create mode 100644 app/client/src/components/ads/SearchInput.tsx
create mode 100644 app/client/src/components/stories/SearchInput.stories.tsx
diff --git a/app/client/src/assets/icons/ads/close.svg b/app/client/src/assets/icons/ads/close.svg
new file mode 100644
index 0000000000..afaca4c528
--- /dev/null
+++ b/app/client/src/assets/icons/ads/close.svg
@@ -0,0 +1,3 @@
+
diff --git a/app/client/src/assets/icons/ads/search.svg b/app/client/src/assets/icons/ads/search.svg
new file mode 100644
index 0000000000..e3e23f0e53
--- /dev/null
+++ b/app/client/src/assets/icons/ads/search.svg
@@ -0,0 +1,4 @@
+
diff --git a/app/client/src/components/ads/Icon.tsx b/app/client/src/components/ads/Icon.tsx
index c662dcda7c..c6a3a078fb 100644
--- a/app/client/src/components/ads/Icon.tsx
+++ b/app/client/src/components/ads/Icon.tsx
@@ -3,7 +3,8 @@ import { ReactComponent as DeleteIcon } from "assets/icons/ads/delete.svg";
import { ReactComponent as UserIcon } from "assets/icons/ads/user.svg";
import { ReactComponent as GeneralIcon } from "assets/icons/ads/general.svg";
import { ReactComponent as BillingIcon } from "assets/icons/ads/billing.svg";
-
+import { ReactComponent as SearchIcon } from "assets/icons/ads/search.svg";
+import { ReactComponent as CloseIcon } from "assets/icons/ads/close.svg";
import styled from "styled-components";
import { Size } from "./Button";
import { sizeHandler } from "./Spinner";
@@ -14,6 +15,8 @@ export type IconName =
| "user"
| "general"
| "billing"
+ | "search"
+ | "close"
| undefined;
const IconWrapper = styled.div`
@@ -50,6 +53,7 @@ export type IconProps = {
name?: IconName;
invisible?: boolean;
className?: string;
+ click?: () => void;
};
const Icon = (props: IconProps) => {
@@ -67,6 +71,12 @@ const Icon = (props: IconProps) => {
case "billing":
returnIcon = ;
break;
+ case "search":
+ returnIcon = ;
+ break;
+ case "close":
+ returnIcon = ;
+ break;
default:
returnIcon = null;
break;
@@ -75,6 +85,7 @@ const Icon = (props: IconProps) => {
props.click && props.click()}
>
{returnIcon}
diff --git a/app/client/src/components/ads/SearchInput.tsx b/app/client/src/components/ads/SearchInput.tsx
new file mode 100644
index 0000000000..91816d479d
--- /dev/null
+++ b/app/client/src/components/ads/SearchInput.tsx
@@ -0,0 +1,138 @@
+import React, { forwardRef, Ref, useCallback, useMemo, useState } from "react";
+import { CommonComponentProps } from "./common";
+import styled from "styled-components";
+import { Size } from "./Button";
+import { Icon } from "./Icon";
+
+export enum SearchVariant {
+ BACKGROUND = "BACKGROUND",
+ SEAMLESS = "SEAMLESS",
+}
+
+export type TextInputProps = CommonComponentProps & {
+ placeholder?: string;
+ fill?: boolean;
+ defaultValue?: string;
+ variant?: SearchVariant;
+ onChange?: (value: string) => void;
+};
+
+const StyledInput = styled.input<
+ TextInputProps & { value?: string; isFocused: boolean }
+>`
+ width: ${props =>
+ props.value && props.variant === SearchVariant.BACKGROUND && props.isFocused
+ ? "calc(100% - 50px)"
+ : "100%"};
+ border-radius: 0;
+ outline: 0;
+ box-shadow: none;
+ border: none;
+ padding: 0;
+ background-color: transparent;
+ font-size: ${props => props.theme.typography.p1.fontSize}px;
+ font-weight: ${props => props.theme.typography.p1.fontWeight};
+ line-height: ${props => props.theme.typography.p1.lineHeight}px;
+ letter-spacing: ${props => props.theme.typography.p1.letterSpacing}px;
+ text-overflow: ellipsis;
+
+ color: ${props => props.theme.colors.blackShades[9]};
+
+ &::placeholder {
+ color: ${props => props.theme.colors.blackShades[5]};
+ }
+`;
+
+const InputWrapper = styled.div<{
+ value?: string;
+ isFocused: boolean;
+ variant?: SearchVariant;
+ fill?: boolean;
+}>`
+ display: flex;
+ align-items: center;
+ padding: ${props => props.theme.spaces[3]}px
+ ${props => props.theme.spaces[4]}px ${props => props.theme.spaces[3]}px
+ ${props => props.theme.spaces[6]}px;
+ width: ${props => (props.fill ? "100%" : "210px")};
+ background-color: ${props =>
+ props.variant === SearchVariant.SEAMLESS ? "transparent" : "#262626"};
+ ${props =>
+ props.variant === SearchVariant.BACKGROUND
+ ? props.isFocused || props.value
+ ? `box-shadow: 0px 1px 0px ${props.theme.colors.info.main}`
+ : `box-shadow: 0px 1px 0px ${props.theme.colors.blackShades[4]}`
+ : null}
+
+ .search-icon {
+ margin-right: ${props => props.theme.spaces[5]}px;
+
+ svg {
+ path,
+ circle {
+ stroke: ${props =>
+ props.isFocused || props.value
+ ? props.theme.colors.blackShades[7]
+ : props.theme.colors.blackShades[5]};
+ }
+ }
+ }
+
+ .close-icon {
+ margin-right: ${props => props.theme.spaces[4]}px;
+ margin-left: ${props => props.theme.spaces[4]}px;
+ }
+`;
+
+const SearchInput = forwardRef(
+ (props: TextInputProps, ref: Ref) => {
+ const [searchValue, setSearchValue] = useState(props.defaultValue);
+ const [isFocused, setIsFocused] = useState(false);
+
+ const memoizedChangeHandler = useCallback(
+ el => {
+ setSearchValue(el.target.value);
+ return props.onChange && props.onChange(el.target.value);
+ },
+ [props],
+ );
+
+ return (
+
+
+ setIsFocused(true)}
+ onBlur={() => setIsFocused(false)}
+ onChange={memoizedChangeHandler}
+ />
+ {searchValue && props.variant === SearchVariant.BACKGROUND ? (
+ setSearchValue("")}
+ />
+ ) : null}
+
+ );
+ },
+);
+
+SearchInput.defaultProps = {
+ fill: false,
+};
+
+SearchInput.displayName = "SearchInput";
+
+export default SearchInput;
diff --git a/app/client/src/components/stories/SearchInput.stories.tsx b/app/client/src/components/stories/SearchInput.stories.tsx
new file mode 100644
index 0000000000..c245cc932e
--- /dev/null
+++ b/app/client/src/components/stories/SearchInput.stories.tsx
@@ -0,0 +1,26 @@
+import React from "react";
+import { withKnobs, boolean, text, select } from "@storybook/addon-knobs";
+import { action } from "@storybook/addon-actions";
+import SearchInput, { SearchVariant } from "../ads/SearchInput";
+
+export default {
+ title: "Search Input",
+ component: SearchInput,
+ decorators: [withKnobs],
+};
+
+export const SearchInputStory = () => (
+
+
+
+);
From f35e2d7f05de32b17a1456032cebcf3acf1271d7 Mon Sep 17 00:00:00 2001
From: satbir121 <39981226+satbir121@users.noreply.github.com>
Date: Wed, 26 Aug 2020 13:53:43 +0530
Subject: [PATCH 06/11] Fixing icon path. (#429)
---
app/client/src/components/ads/SearchInput.tsx | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/app/client/src/components/ads/SearchInput.tsx b/app/client/src/components/ads/SearchInput.tsx
index 91816d479d..dbe8fb4d36 100644
--- a/app/client/src/components/ads/SearchInput.tsx
+++ b/app/client/src/components/ads/SearchInput.tsx
@@ -2,7 +2,7 @@ import React, { forwardRef, Ref, useCallback, useMemo, useState } from "react";
import { CommonComponentProps } from "./common";
import styled from "styled-components";
import { Size } from "./Button";
-import { Icon } from "./Icon";
+import Icon from "./Icon";
export enum SearchVariant {
BACKGROUND = "BACKGROUND",
From 372fb3b33d91e426c7d67ac5e735c29e2db5caec Mon Sep 17 00:00:00 2001
From: devrk96
Date: Wed, 26 Aug 2020 14:34:58 +0530
Subject: [PATCH 07/11] Editable text component (#362)
* editable text component started
* success and error callback implemented
* feedback implemented and success or error state corrected
* editable input ui fixed
* PR comments resolved
* isSaving state refactored from PR comment
* icon import updated
* Changing path
* icon import fixed
Co-authored-by: Satbir Singh
---
app/client/src/assets/icons/ads/edit.svg | 3 +
app/client/src/assets/icons/ads/error.svg | 4 +
app/client/src/assets/icons/ads/success.svg | 4 +
.../src/components/ads/EditableInput.tsx | 26 --
.../src/components/ads/EditableText.tsx | 292 ++++++++++++++++++
app/client/src/components/ads/Icon.tsx | 21 +-
.../stories/ColorSelector.stories.tsx | 2 +-
.../stories/EditableText.stories.tsx | 60 ++++
8 files changed, 383 insertions(+), 29 deletions(-)
create mode 100644 app/client/src/assets/icons/ads/edit.svg
create mode 100644 app/client/src/assets/icons/ads/error.svg
create mode 100644 app/client/src/assets/icons/ads/success.svg
delete mode 100644 app/client/src/components/ads/EditableInput.tsx
create mode 100644 app/client/src/components/ads/EditableText.tsx
create mode 100644 app/client/src/components/stories/EditableText.stories.tsx
diff --git a/app/client/src/assets/icons/ads/edit.svg b/app/client/src/assets/icons/ads/edit.svg
new file mode 100644
index 0000000000..93eaaa6946
--- /dev/null
+++ b/app/client/src/assets/icons/ads/edit.svg
@@ -0,0 +1,3 @@
+
diff --git a/app/client/src/assets/icons/ads/error.svg b/app/client/src/assets/icons/ads/error.svg
new file mode 100644
index 0000000000..43f866b350
--- /dev/null
+++ b/app/client/src/assets/icons/ads/error.svg
@@ -0,0 +1,4 @@
+
diff --git a/app/client/src/assets/icons/ads/success.svg b/app/client/src/assets/icons/ads/success.svg
new file mode 100644
index 0000000000..c5c3d40e41
--- /dev/null
+++ b/app/client/src/assets/icons/ads/success.svg
@@ -0,0 +1,4 @@
+
diff --git a/app/client/src/components/ads/EditableInput.tsx b/app/client/src/components/ads/EditableInput.tsx
deleted file mode 100644
index 816ad2d1b3..0000000000
--- a/app/client/src/components/ads/EditableInput.tsx
+++ /dev/null
@@ -1,26 +0,0 @@
-import { CommonComponentProps } from "./common";
-
-export enum EditInteractionKind {
- SINGLE,
- DOUBLE,
-}
-
-type EditableTextProps = CommonComponentProps & {
- type: "text" | "password" | "email" | "phone" | "date";
- defaultValue: string;
- onTextChanged: (value: string) => void;
- placeholder: string;
- cypressSelector?: string;
- valueTransform?: (value: string) => string;
- isEditingDefault?: boolean;
- forceDefault?: boolean;
- updating?: boolean;
- isInvalid?: (value: string) => string | boolean;
- editInteractionKind: EditInteractionKind;
- hideEditIcon?: boolean;
-};
-
-// Check EditableText Component
-export default function(props: EditableTextProps) {
- return null;
-}
diff --git a/app/client/src/components/ads/EditableText.tsx b/app/client/src/components/ads/EditableText.tsx
new file mode 100644
index 0000000000..1a4aa7f9a6
--- /dev/null
+++ b/app/client/src/components/ads/EditableText.tsx
@@ -0,0 +1,292 @@
+import React, { useState, useEffect, useMemo, useCallback } from "react";
+import { EditableText as BlueprintEditableText } from "@blueprintjs/core";
+import styled from "styled-components";
+import { Size } from "./Button";
+import Text, { TextType } from "./Text";
+import Spinner from "./Spinner";
+import { hexToRgba } from "./common";
+import { theme } from "constants/DefaultTheme";
+import { noop } from "lodash";
+import Icon from "./Icon";
+
+export enum EditInteractionKind {
+ SINGLE = "SINGLE",
+ DOUBLE = "DOUBLE",
+}
+
+export type SavingStateHandler = (
+ isSaving: boolean,
+ state?: SavingState,
+) => void;
+
+export enum SavingState {
+ NOT_STARTED = "NOT_STARTED",
+ SUCCESS = "SUCCESS",
+ ERROR = "ERROR",
+}
+
+type EditableTextProps = {
+ defaultValue: string;
+ onTextChanged: (value: string) => void;
+ placeholder: string;
+ className?: string;
+ valueTransform?: (value: string) => string;
+ isEditingDefault?: boolean;
+ forceDefault?: boolean;
+ updating?: boolean;
+ isInvalid?: (value: string) => string | boolean;
+ editInteractionKind: EditInteractionKind;
+ hideEditIcon?: boolean;
+ fill?: boolean;
+ onSubmit: (
+ value: string,
+ callback: SavingStateHandler,
+ ) => { saving: SavingState };
+};
+
+const EditableTextWrapper = styled.div<{
+ fill?: boolean;
+}>`
+ width: ${props => (!props.fill ? "234px" : "100%")};
+ .error-message {
+ color: ${props => props.theme.colors.danger.main};
+ }
+`;
+
+const editModeBgcolor = (
+ isInvalid: boolean,
+ isEditing: boolean,
+ savingState: { isSaving: boolean; name?: SavingState },
+): string => {
+ if (
+ (isInvalid && isEditing) ||
+ (!savingState.isSaving && savingState.name === SavingState.ERROR)
+ ) {
+ return hexToRgba(theme.colors.danger.main, 0.08);
+ } else if (!isInvalid && isEditing) {
+ return theme.colors.blackShades[2];
+ } else {
+ return "transparent";
+ }
+};
+
+const TextContainer = styled.div<{
+ isInvalid: boolean;
+ isEditing: boolean;
+ bgColor: string;
+}>`
+ display: flex;
+ align-items: center;
+ ${props =>
+ props.isEditing && props.isInvalid
+ ? `margin-bottom: ${props.theme.spaces[2]}px`
+ : null};
+ .bp3-editable-text.bp3-editable-text-editing::before,
+ .bp3-editable-text.bp3-disabled::before {
+ display: none;
+ }
+
+ &&& .bp3-editable-text-content,
+ &&& .bp3-editable-text-input {
+ font-size: ${props => props.theme.typography.p1.fontSize}px;
+ line-height: ${props => props.theme.typography.p1.lineHeight}px;
+ letter-spacing: ${props => props.theme.typography.p1.letterSpacing}px;
+ font-weight: ${props => props.theme.typography.p1.fontWeight}px;
+ }
+
+ & .bp3-editable-text-content {
+ cursor: pointer;
+ color: ${props => props.theme.colors.blackShades[9]};
+ overflow: hidden;
+ text-overflow: ellipsis;
+ ${props => (props.isEditing ? "display: none" : "display: block")};
+ }
+
+ & .bp3-editable-text-input {
+ border: none;
+ outline: none;
+ height: ${props => props.theme.spaces[13] + 3}px;
+ padding: ${props => props.theme.spaces[0]}px;
+ color: ${props => props.theme.colors.blackShades[9]};
+ min-width: 100%;
+ border-radius: ${props => props.theme.spaces[0]}px;
+ }
+
+ & .bp3-editable-text {
+ overflow: hidden;
+ padding: ${props => props.theme.spaces[4]}px
+ ${props => props.theme.spaces[5]}px;
+ width: calc(100% - 40px);
+ background-color: ${props => props.bgColor};
+ }
+
+ .icon-wrapper {
+ background-color: ${props => props.bgColor};
+ }
+`;
+
+const IconWrapper = styled.div`
+ width: ${props => props.theme.spaces[13] + 4}px;
+ padding-right: ${props => props.theme.spaces[5]}px;
+ height: ${props => props.theme.spaces[13] + 3}px;
+ display: flex;
+ align-items: center;
+ justify-content: flex-end;
+`;
+
+export const AdsEditableText = (props: EditableTextProps) => {
+ const [isEditing, setIsEditing] = useState(!!props.isEditingDefault);
+ const [value, setValue] = useState(props.defaultValue);
+ const [lastValidValue, setLastValidValue] = useState(props.defaultValue);
+ const [isInvalid, setIsInvalid] = useState(false);
+ const [changeStarted, setChangeStarted] = useState(false);
+ const [savingState, setSavingState] = useState<{
+ isSaving: boolean;
+ name?: SavingState;
+ }>({ isSaving: false, name: SavingState.NOT_STARTED });
+
+ useEffect(() => {
+ setValue(props.defaultValue);
+ setIsEditing(!!props.isEditingDefault);
+ }, [props.defaultValue, props.isEditingDefault]);
+
+ useEffect(() => {
+ if (props.forceDefault === true) setValue(props.defaultValue);
+ }, [props.forceDefault, props.defaultValue]);
+
+ const bgColor = useMemo(
+ () => editModeBgcolor(!!isInvalid, isEditing, savingState),
+ [isInvalid, isEditing, savingState],
+ );
+
+ /* should I write ? */
+ const editMode = useCallback((e: React.MouseEvent) => {
+ setIsEditing(true);
+ const errorMessage = props.isInvalid && props.isInvalid(props.defaultValue);
+ setIsInvalid(errorMessage ? errorMessage : false);
+ e.preventDefault();
+ e.stopPropagation();
+ }, []);
+
+ const onConfirm = (_value: string) => {
+ if (
+ (!savingState.isSaving && savingState.name === SavingState.ERROR) ||
+ isInvalid
+ ) {
+ setValue(lastValidValue);
+ setSavingState({ isSaving: false, name: SavingState.NOT_STARTED });
+ } else if (changeStarted) {
+ props.onTextChanged(_value);
+ props.onSubmit(_value, SavingStateHandler);
+ }
+ setIsEditing(false);
+ setChangeStarted(false);
+ };
+
+ const onInputchange = useCallback((_value: string) => {
+ let finalVal: string = _value;
+ if (props.valueTransform) {
+ finalVal = props.valueTransform(_value);
+ }
+ setValue(finalVal);
+
+ const errorMessage = props.isInvalid && props.isInvalid(finalVal);
+ const error = errorMessage ? errorMessage : false;
+ if (!error) {
+ setLastValidValue(finalVal);
+ }
+ setIsInvalid(error);
+ setChangeStarted(true);
+ }, []);
+
+ const SavingStateHandler = (isSaving: boolean, state?: SavingState) => {
+ setIsEditing(false);
+ if (isSaving) {
+ setSavingState({ isSaving: true });
+ } else {
+ switch (state) {
+ case SavingState.SUCCESS:
+ setSavingState({ isSaving: false, name: SavingState.SUCCESS });
+ break;
+ default:
+ setValue(props.defaultValue);
+ setSavingState({ isSaving: false, name: SavingState.NOT_STARTED });
+ break;
+ }
+ }
+ };
+
+ const iconName =
+ !isEditing && savingState.name === SavingState.NOT_STARTED
+ ? "edit"
+ : !isEditing && savingState.name === SavingState.SUCCESS
+ ? "success"
+ : (isEditing && savingState.name === SavingState.ERROR) ||
+ (isEditing && !!isInvalid)
+ ? "error"
+ : undefined;
+
+ const nonEditMode = () => {
+ if (
+ !isEditing &&
+ !savingState.isSaving &&
+ savingState.name === SavingState.SUCCESS
+ ) {
+ setSavingState({ isSaving: false, name: SavingState.NOT_STARTED });
+ }
+ };
+
+ return (
+
+
+
+
+
+ {savingState.isSaving ? (
+
+ ) : (
+
+ )}
+
+
+ {isEditing && !!isInvalid ? (
+
+ {isInvalid}
+
+ ) : null}
+
+ );
+};
+
+AdsEditableText.defaultProps = {
+ fill: false,
+};
+
+export default AdsEditableText;
diff --git a/app/client/src/components/ads/Icon.tsx b/app/client/src/components/ads/Icon.tsx
index c6a3a078fb..3f547a05d9 100644
--- a/app/client/src/components/ads/Icon.tsx
+++ b/app/client/src/components/ads/Icon.tsx
@@ -3,6 +3,9 @@ import { ReactComponent as DeleteIcon } from "assets/icons/ads/delete.svg";
import { ReactComponent as UserIcon } from "assets/icons/ads/user.svg";
import { ReactComponent as GeneralIcon } from "assets/icons/ads/general.svg";
import { ReactComponent as BillingIcon } from "assets/icons/ads/billing.svg";
+import { ReactComponent as EditIcon } from "assets/icons/ads/edit.svg";
+import { ReactComponent as ErrorIcon } from "assets/icons/ads/error.svg";
+import { ReactComponent as SuccessIcon } from "assets/icons/ads/success.svg";
import { ReactComponent as SearchIcon } from "assets/icons/ads/search.svg";
import { ReactComponent as CloseIcon } from "assets/icons/ads/close.svg";
import styled from "styled-components";
@@ -15,6 +18,9 @@ export type IconName =
| "user"
| "general"
| "billing"
+ | "edit"
+ | "error"
+ | "success"
| "search"
| "close"
| undefined;
@@ -25,8 +31,10 @@ const IconWrapper = styled.div`
}
display: flex;
svg {
- width: ${props => sizeHandler(props)}px;
- height: ${props => sizeHandler(props)}px;
+ width: ${props =>
+ props.size ? sizeHandler(props) : props.theme.spaces[9]}px;
+ height: ${props =>
+ props.size ? sizeHandler(props) : props.theme.spaces[9]}px;
path {
fill: ${props => props.theme.colors.blackShades[4]};
}
@@ -71,6 +79,15 @@ const Icon = (props: IconProps) => {
case "billing":
returnIcon = ;
break;
+ case "edit":
+ returnIcon = ;
+ break;
+ case "error":
+ returnIcon = ;
+ break;
+ case "success":
+ returnIcon = ;
+ break;
case "search":
returnIcon = ;
break;
diff --git a/app/client/src/components/stories/ColorSelector.stories.tsx b/app/client/src/components/stories/ColorSelector.stories.tsx
index 8303226525..9ca90b491c 100644
--- a/app/client/src/components/stories/ColorSelector.stories.tsx
+++ b/app/client/src/components/stories/ColorSelector.stories.tsx
@@ -1,6 +1,6 @@
import React from "react";
import { action } from "@storybook/addon-actions";
-import ColorSelector, { appColorPalette } from "../ads/ColorSelector";
+import ColorSelector, { appColorPalette } from "components/ads/ColorSelector";
import { withKnobs, array, boolean } from "@storybook/addon-knobs";
import { withDesign } from "storybook-addon-designs";
diff --git a/app/client/src/components/stories/EditableText.stories.tsx b/app/client/src/components/stories/EditableText.stories.tsx
new file mode 100644
index 0000000000..de5a12f3b3
--- /dev/null
+++ b/app/client/src/components/stories/EditableText.stories.tsx
@@ -0,0 +1,60 @@
+import React from "react";
+import { boolean, select, text, withKnobs } from "@storybook/addon-knobs";
+import { withDesign } from "storybook-addon-designs";
+import AdsEditableText, {
+ EditInteractionKind,
+ SavingStateHandler,
+ SavingState,
+} from "../ads/EditableText";
+import { action } from "@storybook/addon-actions";
+
+export default {
+ title: "EditableText",
+ component: AdsEditableText,
+ decorators: [withKnobs, withDesign],
+};
+
+const calls = (value: string, callback: any) => {
+ console.log("value", value);
+
+ // setTimeout(() => {
+ // return callback(SavingState.ERROR);
+ // }, 2000);
+
+ setTimeout(() => {
+ return callback(false, SavingState.SUCCESS);
+ }, 2000);
+
+ return callback(true);
+};
+
+const errorFunction = (name: string) => {
+ if (name === "") {
+ return "Name cannot be empty";
+ } else {
+ return false;
+ }
+};
+
+export const EditableTextStory = () => (
+
+
value.toUpperCase()}
+ placeholder={text("placeholder", "Edit input")}
+ hideEditIcon={boolean("hideEditIcon", false)}
+ isInvalid={name => errorFunction(name)}
+ isEditingDefault={boolean("isEditingDefault", false)}
+ fill={boolean("fill", false)}
+ onSubmit={(value: string, callback: SavingStateHandler) =>
+ calls(value, callback)
+ }
+ >
+
+);
From 5eb4d272976d29c53eaef5b73a4fcf64132e2270 Mon Sep 17 00:00:00 2001
From: Hetu Nandu
Date: Wed, 26 Aug 2020 14:46:20 +0530
Subject: [PATCH 08/11] Stringify nested objects in sql query responses (#430)
---
.../pages/Editor/DataSourceEditor/DBForm.tsx | 2 +-
.../src/pages/Editor/QueryEditor/Table.tsx | 35 +++++++++++++++++++
2 files changed, 36 insertions(+), 1 deletion(-)
diff --git a/app/client/src/pages/Editor/DataSourceEditor/DBForm.tsx b/app/client/src/pages/Editor/DataSourceEditor/DBForm.tsx
index 842416c00a..0d867162b1 100644
--- a/app/client/src/pages/Editor/DataSourceEditor/DBForm.tsx
+++ b/app/client/src/pages/Editor/DataSourceEditor/DBForm.tsx
@@ -16,7 +16,7 @@ import FormControlFactory from "utils/FormControlFactory";
import { HelpBaseURL, HelpMap } from "constants/HelpConstants";
import Button from "components/editorComponents/Button";
import { Datasource } from "api/DatasourcesApi";
-import { reduxForm, InjectedFormProps, Field } from "redux-form";
+import { reduxForm, InjectedFormProps } from "redux-form";
import { BaseButton } from "components/designSystems/blueprint/ButtonComponent";
import { APPSMITH_IP_ADDRESS } from "constants/DatasourceEditorConstants";
import { getAppsmithConfigs } from "configs";
diff --git a/app/client/src/pages/Editor/QueryEditor/Table.tsx b/app/client/src/pages/Editor/QueryEditor/Table.tsx
index 36d8e4e627..9dc40037f5 100644
--- a/app/client/src/pages/Editor/QueryEditor/Table.tsx
+++ b/app/client/src/pages/Editor/QueryEditor/Table.tsx
@@ -6,6 +6,8 @@ import {
import { useTable, useFlexLayout } from "react-table";
import styled from "styled-components";
import { CompactModeTypes, TABLE_SIZES } from "widgets/TableWidget";
+import AutoToolTipComponent from "components/designSystems/appsmith/AutoToolTipComponent";
+import { getType, Types } from "utils/TypeHelpers";
interface TableProps {
data: Record[];
@@ -30,6 +32,38 @@ const StyledTableWrapped = styled(TableWrapper)`
}
`;
+const renderCell = (props: any) => {
+ const value = props.cell.value;
+ let displayValue;
+ switch (getType(value)) {
+ case Types.NUMBER:
+ case Types.BOOLEAN:
+ displayValue = value.toString();
+ break;
+ case Types.ARRAY:
+ case Types.FUNCTION:
+ case Types.OBJECT:
+ displayValue = JSON.stringify(value);
+ break;
+ case Types.STRING:
+ displayValue = value;
+ break;
+ case Types.NULL:
+ case Types.UNDEFINED:
+ case Types.UNKNOWN:
+ displayValue = "";
+ break;
+ default:
+ displayValue = "";
+ }
+
+ return (
+
+ {displayValue}
+
+ );
+};
+
const Table = (props: TableProps) => {
const data = React.useMemo(() => props.data, [props.data]);
const columns = React.useMemo(() => {
@@ -38,6 +72,7 @@ const Table = (props: TableProps) => {
return {
Header: key,
accessor: key,
+ Cell: renderCell,
};
});
}
From f744f3aacdf31b06bd9643215e1d700f36fdfef2 Mon Sep 17 00:00:00 2001
From: Hetu Nandu
Date: Wed, 26 Aug 2020 14:54:44 +0530
Subject: [PATCH 09/11] add support for smart look (#431)
---
app/client/public/index.html | 12 ++++++++++++
app/client/src/configs/index.ts | 2 ++
2 files changed, 14 insertions(+)
diff --git a/app/client/public/index.html b/app/client/public/index.html
index 5702864a80..05e60b0deb 100755
--- a/app/client/public/index.html
+++ b/app/client/public/index.html
@@ -33,6 +33,18 @@
gtag('config', "%REACT_APP_GOOGLE_ANALYTICS_ID%");
+
diff --git a/app/client/src/configs/index.ts b/app/client/src/configs/index.ts
index eab451cd81..56e6d1b02b 100644
--- a/app/client/src/configs/index.ts
+++ b/app/client/src/configs/index.ts
@@ -30,6 +30,7 @@ type INJECTED_CONFIGS = {
};
intercomAppID: string;
mailEnabled: boolean;
+ smartLookKey: string;
};
declare global {
interface Window {
@@ -94,6 +95,7 @@ const getConfigsFromEnvVars = (): INJECTED_CONFIGS => {
mailEnabled: process.env.REACT_APP_MAIL_ENABLED
? process.env.REACT_APP_MAIL_ENABLED.length > 0
: false,
+ smartLookKey: process.env.REACT_APP_SMART_LOOK_KEY || "",
};
};
From aa06bc2d3d5fc236ad959debc6abd4783eed63b4 Mon Sep 17 00:00:00 2001
From: Hetu Nandu
Date: Wed, 26 Aug 2020 15:51:57 +0530
Subject: [PATCH 10/11] Fix cloud hosting error (#433)
---
app/client/public/index.html | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/app/client/public/index.html b/app/client/public/index.html
index 05e60b0deb..7a51cdaa5e 100755
--- a/app/client/public/index.html
+++ b/app/client/public/index.html
@@ -34,8 +34,8 @@
gtag('config', "%REACT_APP_GOOGLE_ANALYTICS_ID%");