Feature/help

This commit is contained in:
Satbir Singh 2020-05-28 18:10:26 +00:00
parent 4ed4f9548f
commit b7b74ffd02
47 changed files with 1764 additions and 147 deletions

View File

@ -0,0 +1,10 @@
{
"HelpButton":"t--helpGlobalButton",
"DocSearchResult": "t--docHit",
"DocSearchResultTitle": "t--docHitTitle",
"DocSearchResultDesc": "t--docHitDesc",
"DocSearchResultOpenLink": "t--docOpenLink",
"DocSearchModal": "t--docSearchModal",
"DocMinimise": "t--docsMinimize",
"DocSearch": "ais-SearchBox-input"
}

View File

@ -1,5 +1,6 @@
{
"editIcon": ".t--widget-propertypane-toggle",
"helpIcon": ".t--widget-help-control",
"editPropCrossButton": ".t--property-pane-close-btn",
"deleteWidgetIcon": ".t--widget-delete-control",
"dropdownSelectButton": ".t--open-dropdown-Select-Action",

View File

@ -0,0 +1,117 @@
var https = require("https");
const algoliasearch = require("algoliasearch");
const client = algoliasearch("AZ2Z9CJSJ0", "e92300d4e8dbaf2cbaa9ebbbeb4e06e6");
const index = client.initIndex("test_appsmith");
var options = {
headers: {
Authorization:
"Bearer aEhCb3hxVzVYWFJCY0g4b1owZmdKcTdJUmc0MjotTTY5cHFwVDlxTWx0cFU2akh4MC0tTTY5cHFwVWFobjBaRWNzTjh0WA==",
Cookie: "__cfduid=d8bac210f6e11cb26a8cd921f77727e3f1588323072",
},
};
console.log("Loading function");
function getPage(pageId) {
return new Promise((resolve, reject) => {
https.get(
`https://api-beta.gitbook.com/v1/spaces/-Lzuzdhj8LjrQPaeyCxr/content/v/master/id/${pageId}?format=markdown`,
options,
res => {
res.setEncoding("utf8");
let rawData = "";
res.on("data", chunk => {
rawData += chunk;
});
res.on("end", () => {
try {
const parsedData = JSON.parse(rawData);
resolve(parsedData);
} catch (e) {
reject(e);
console.error(e.message);
}
});
},
);
});
}
const pages = [];
function pushChildPages(masterPage) {
if (masterPage.pages) {
masterPage.pages.forEach(page => {
page.path = masterPage.path + "/" + page.path;
pushChildPages(page);
page.pages = undefined;
pages.push(page);
});
}
}
exports.handler = async event => {
const response = await new Promise((resolve, reject) => {
const req = https.get(
"https://api-beta.gitbook.com/v1/spaces/-Lzuzdhj8LjrQPaeyCxr/content",
options,
res => {
res.setEncoding("utf8");
let rawData = "";
res.on("data", chunk => {
rawData += chunk;
});
res.on("end", () => {
try {
const parsedData = JSON.parse(rawData);
let masterPage = parsedData.variants[0].page;
pushChildPages(masterPage);
masterPage.pages = undefined;
pages.push(masterPage);
let promises = pages.map(page => page.uid).map(getPage);
Promise.all(promises).then(updatedPages => {
updatedPages.forEach((page, index) => {
page.path = pages[index].path;
page.pages = undefined;
page.objectID = page.uid;
});
resolve({
statusCode: 200,
body: JSON.stringify(updatedPages),
});
// index.replaceAllObjects(updatedPages, {
// autoGenerateObjectIDIfNotExist: true
// }).then(({ objectIDs }) => {
// console.log(objectIDs);
// resolve({
// statusCode: 200,
// body: JSON.stringify(updatedPages)
// })
// }).catch(e => {
// reject({
// statusCode: 500,
// body: 'Algolia upload failed.'
// })
// })
});
} catch (e) {
reject({
statusCode: 500,
body: "Most probably gitbook getPage apis failed",
});
}
});
},
);
});
return response;
};

View File

@ -15,6 +15,7 @@
"@blueprintjs/timezone": "^3.6.0",
"@craco/craco": "^5.6.1",
"@manaflair/redux-batch": "^1.0.0",
"@optimizely/optimizely-sdk": "^4.0.0",
"@sentry/browser": "^5.6.3",
"@sentry/webpack-plugin": "^1.10.0",
"@syncfusion/ej2-react-grids": "^17.4.40",
@ -28,6 +29,7 @@
"@types/react": "^16.8.2",
"@types/react-dom": "^16.8.0",
"@types/react-helmet": "^5.0.14",
"@types/react-instantsearch-dom": "^6.3.0",
"@types/react-redux": "^7.0.1",
"@types/react-router-dom": "^5.1.2",
"@types/styled-components": "^4.1.8",
@ -40,6 +42,7 @@
"@uppy/react": "^1.4.5",
"@uppy/url": "^1.3.2",
"@uppy/webcam": "^1.3.1",
"algoliasearch": "^4.2.0",
"axios": "^0.18.0",
"chance": "^1.1.3",
"codemirror": "^5.50.0",
@ -51,6 +54,8 @@
"fusioncharts": "^3.15.0-sr.1",
"history": "^4.10.1",
"husky": "^3.0.5",
"instantsearch.css": "^7.4.2",
"instantsearch.js": "^4.4.1",
"interweave": "^12.1.1",
"interweave-autolink": "^4.0.1",
"json-fn": "^1.1.1",
@ -76,6 +81,7 @@
"react-google-maps": "^9.4.5",
"react-helmet": "^5.2.1",
"react-infinite-scroller": "^1.2.4",
"react-instantsearch-dom": "^6.4.0",
"react-json-view": "^1.19.1",
"react-paginating": "^1.4.0",
"react-redux": "^7.1.3",

View File

@ -0,0 +1,14 @@
import { ReduxActionTypes } from "constants/ReduxActionConstants";
export const setHelpDefaultRefinement = (payload: string) => {
return {
type: ReduxActionTypes.SET_DEFAULT_REFINEMENT,
payload,
};
};
export const setHelpModalVisibility = (payload: boolean) => {
return {
type: ReduxActionTypes.SET_HELP_MODAL_OPEN,
payload,
};
};

View File

@ -0,0 +1,3 @@
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M10 0C4.48 0 0 4.48 0 10C0 15.52 4.48 20 10 20C15.52 20 20 15.52 20 10C20 4.48 15.52 0 10 0ZM11 17H9V15H11V17ZM13.07 9.25L12.17 10.17C11.45 10.9 11 11.5 11 13H9V12.5C9 11.4 9.45 10.4 10.17 9.67L11.41 8.41C11.78 8.05 12 7.55 12 7C12 5.9 11.1 5 10 5C8.9 5 8 5.9 8 7H6C6 4.79 7.79 3 10 3C12.21 3 14 4.79 14 7C14 7.88 13.64 8.68 13.07 9.25Z" fill="black" fill-opacity="0.87"/>
</svg>

After

Width:  |  Height:  |  Size: 485 B

View File

@ -0,0 +1,7 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<g opacity="0.5">
<path d="M12.8226 8.76754V13.4341C12.8226 13.8466 12.6587 14.2423 12.367 14.534C12.0753 14.8257 11.6796 14.9896 11.2671 14.9896H2.71176C2.29922 14.9896 1.90356 14.8257 1.61185 14.534C1.32013 14.2423 1.15625 13.8466 1.15625 13.4341V4.87876C1.15625 4.46621 1.32013 4.07056 1.61185 3.77884C1.90356 3.48713 2.29922 3.32324 2.71176 3.32324H7.3783" stroke="black" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M10.4888 0.991211H15.1553V5.65775" stroke="black" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M6.60107 9.54653L15.1564 0.991211" stroke="black" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 806 B

View File

@ -0,0 +1,70 @@
import styled from "styled-components";
import { hexToRgb } from "utils/AppsmithUtils";
export default styled.span<{
animate?: boolean;
width?: number;
height?: number;
color?: string;
}>`
&&& {
display: block;
width: ${props => props.width || 8}px;
height: ${props => props.height || 8}px;
border-radius: 50%;
background: ${props => props.color || props.theme.colors.notification};
cursor: pointer;
box-shadow: 0 0 0
rgba(
${props => {
const rgb = hexToRgb(props.color || props.theme.colors.notification);
return `${rgb.r}, ${rgb.g}, ${rgb.b}`;
}},
0.4
);
animation: ${props => (!!props.animate ? "pulse 2s infinite" : "")};
&:hover {
animation: none;
}
@keyframes pulse {
0% {
box-shadow: 0 0 0 0
rgba(
${props => {
const rgb = hexToRgb(
props.color || props.theme.colors.notification,
);
return `${rgb.r}, ${rgb.g}, ${rgb.b}`;
}},
0.4
);
}
70% {
box-shadow: 0 0 0 15px
rgba(
${props => {
const rgb = hexToRgb(
props.color || props.theme.colors.notification,
);
return `${rgb.r}, ${rgb.g}, ${rgb.b}`;
}},
0
);
}
100% {
box-shadow: 0 0 0 0
rgba(
${props => {
const rgb = hexToRgb(
props.color || props.theme.colors.notification,
);
return `${rgb.r}, ${rgb.g}, ${rgb.b}`;
}},
0
);
}
}
}
`;

View File

@ -0,0 +1,52 @@
import React, { ReactNode } from "react";
// import { Button, Collapse, Pre } from "@blueprintjs/core";
import { Icon } from "@blueprintjs/core";
import styled from "constants/DefaultTheme";
interface CollapsibleHelpProps {
children?: ReactNode;
}
const HelpIcon = styled(Icon)`
margin-right: 14.5px;
margin-left: 4px;
height: 100%;
background-color: #ef7541;
border: 2px solid rgba(239, 123, 99);
border-radius: 50%;
`;
const Container = styled.div`
background-color: rgba(239, 123, 99, 0.15);
border-radius: 4px;
padding: 10px 10px;
width: 100%;
position: relative;
display: flex;
align-items: center;
margin-top: 18px;
margin-bottom: 19px;
margin-left: 6px;
width: 89%;
`;
const LeftBar = styled.div`
border: 1px solid #ef7541;
border-radius: 4px;
position: absolute;
top: 1px;
left: 0;
height: 96%;
`;
export default function CollapsibleHelp(props: CollapsibleHelpProps) {
// const [isOpen, setIsOpen] = useState(false);
return (
<Container>
<LeftBar />
<HelpIcon color={"#FDEBE8"} icon="help"></HelpIcon>
<div>{props.children}</div>
</Container>
);
}

View File

@ -0,0 +1,325 @@
import React from "react";
import algoliasearch from "algoliasearch/lite";
import {
InstantSearch,
Hits,
SearchBox,
// Pagination,
Highlight,
// ClearRefinements,
// RefinementList,
Configure,
} from "react-instantsearch-dom";
// import "instantsearch.css/themes/reset.css";
import "instantsearch.css/themes/algolia.css";
// import "./search.css";
import PropTypes from "prop-types";
import { Icon } from "@blueprintjs/core";
import { useDispatch, useSelector } from "react-redux";
import {
setHelpModalVisibility,
setHelpDefaultRefinement,
} from "actions/helpActions";
import styled from "styled-components";
import { HelpIcons } from "icons/HelpIcons";
import { HelpBaseURL } from "constants/HelpConstants";
import { getDefaultRefinement } from "selectors/helpSelectors";
const searchClient = algoliasearch(
"AZ2Z9CJSJ0",
"d113611dccb80ac14aaa72a6e3ac6d10",
);
// const StyledBack = styled(Button)`
// position: absolute;
// top: 36px;
// left: 5px;
// z-index: 26;
// `;
// const StyledAnchor = styled.a`
// position: absolute;
// right: 24px;
// top: 40px;
// z-index: 26;
// `;
// const headerHeight = 91;
// const OpenIcon = styled(Icon)`
// position: absolute;
// right: 0;
// top: 3px;
// color: #888;
// `;
const OenLinkIcon = HelpIcons.OPEN_LINK;
const StyledOpenLinkIcon = styled(OenLinkIcon)`
position: absolute;
right: 0;
top: 0;
color: #888;
width: 12px;
height: 12px;
svg {
width: 12px;
height: 12px;
}
`;
function Hit(props: any) {
// const dispatch = useDispatch();
return (
<div
className="t--docHit"
style={{
cursor: "pointer",
}}
onClick={() => {
window.open(
(props.hit.path as string).replace("master", HelpBaseURL),
"_blank",
);
// console.log(props);
// dispatch(
// setHelpUrl(
// (props.hit.path as string).replace(
// "master",
// HelpBaseURL,
// ),
// ),
// );
}}
>
<div className="hit-name t--docHitTitle">
<div>
<Highlight attribute="title" hit={props.hit} />
</div>
<StyledOpenLinkIcon className="t--docOpenLink"></StyledOpenLinkIcon>
</div>
<div className="hit-description t--docHitDesc">
<Highlight attribute="description" hit={props.hit} />
{/* <Highlight attribute="document" hit={props.hit} /> */}
</div>
</div>
);
}
Hit.propTypes = {
hit: PropTypes.object.isRequired,
};
const Header = styled.div`
position: absolute;
width: 100%;
background: #363e44;
padding-bottom: 20px;
border-top-right-radius: 3px;
border-top-left-radius: 3px;
`;
const SearchContainer = styled.div`
height: 100%;
.ais-SearchBox {
position: relative;
width: 316px;
height: 50px;
margin: 17px;
}
.ais-SearchBox-form {
height: 100%;
}
[class^="ais-"] {
font-size: inherit;
}
.ais-Hits {
margin-top: 142px;
height: calc(100% - 142px);
overflow: auto;
border: 1px solid #d0d7dd;
border-bottom-left-radius: 3px;
border-bottom-right-radius: 3px;
}
.ais-SearchBox-input {
height: 100%;
padding: 4px 48px;
padding-right: 14px;
}
.ais-SearchBox-submitIcon {
width: 18px;
height: 18px;
}
.ais-Pagination {
margin-top: 1em;
}
.ais-Hits-list {
margin: 0;
}
.ais-Hits-item {
margin-bottom: 1em;
width: 100%;
margin: 0;
padding: 20px;
border: 0;
border-bottom: 1px solid #d0d7dd;
box-sizing: border-box;
box-shadow: none;
}
.ais-Hits-item:hover {
background-color: #f8f9fa;
}
.hit-name {
margin-bottom: 0.5em;
font-weight: 500;
font-size: 16px;
line-height: 23px;
color: #000000;
position: relative;
}
.hit-description {
color: #888;
font-size: 14px;
margin-bottom: 0.5em;
font-style: normal;
font-weight: normal;
font-size: 12px;
line-height: 20px;
/*Making description two lines*/
height: 42px;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 2; /* number of lines to show */
-webkit-box-orient: vertical;
/*Making description two lines*/
/* or 167% */
letter-spacing: 0.2px;
}
.ais-Highlight-highlighted {
background-color: #ffb100;
}
.ais-SearchBox-submit {
left: 16px;
}
`;
export default function DocumentationSearch(props: { hitsPerPage: number }) {
const dispatch = useDispatch();
const defaultRefinement = useSelector(getDefaultRefinement);
return (
<SearchContainer className="ais-InstantSearch t--docSearchModal">
<Icon
className="t--docsMinimize"
style={{
position: "absolute",
top: 10,
right: 10,
padding: 8,
cursor: "pointer",
zIndex: 1,
}}
icon="minus"
color="white"
iconSize={18}
onClick={() => {
dispatch(setHelpModalVisibility(false));
dispatch(setHelpDefaultRefinement(""));
}}
></Icon>
<div
style={{
height: "100%",
overflow: "auto",
}}
>
<InstantSearch indexName="test_appsmith" searchClient={searchClient}>
<Configure hitsPerPage={props.hitsPerPage} />
<Header>
<h3
style={{
padding: "0 115px",
marginTop: "14px",
}}
>
<span
style={{
textAlign: "center",
color: "white",
// zIndex: 55,
position: "relative",
fontWeight: 500,
fontSize: "16px",
lineHeight: "24px",
letterSpacing: "0.2px",
margin: "0 auto",
width: "121px",
}}
>
Documentation
</span>
</h3>
<SearchBox defaultRefinement={defaultRefinement} />
</Header>
<Hits hitComponent={Hit as any} />
</InstantSearch>
</div>
{/* <div
style={{
display: url ? "block" : "none",
}}
>
<div
style={{
position: "absolute",
height: `${headerHeight}px`,
backgroundColor: "white",
width: "100%",
top: "0",
}}
>
<StyledBack
// text="back"
intent={"primary"}
iconAlignment={Position.LEFT}
// icon="chevron-left"
icon="arrow-left"
onClick={() => {
dispatch(setHelpUrl(""));
}}
/>
<StyledAnchor href={url} target="_blank">
Open in docs
<Icon icon="document-open"></Icon>
</StyledAnchor>
</div>
<iframe
src={url}
width={"100%"}
height={`${531 - headerHeight}px`}
style={{
border: "0",
}}
></iframe>
</div> */}
</SearchContainer>
);
}

View File

@ -0,0 +1,84 @@
import React, { useContext } from "react";
import DocumentationSearch from "components/designSystems/appsmith/help/DocumentationSearch";
import Button from "components/editorComponents/Button";
import { useSelector } from "store";
import { useDispatch } from "react-redux";
import {
getHelpModalOpen,
getHelpModalDimensions,
} from "selectors/helpSelectors";
import {
setHelpDefaultRefinement,
setHelpModalVisibility,
} from "actions/helpActions";
import styled from "styled-components";
import { IntentColors, theme } from "constants/DefaultTheme";
import { Position } from "@blueprintjs/core";
import ModalComponent from "components/designSystems/blueprint/ModalComponent";
import { LayersContext } from "constants/Layers";
const HelpButton = styled(Button)<{
highlight: boolean;
layer: number;
}>`
&&&&& {
position: absolute;
bottom: 46px;
right: 27px;
z-index: ${props => props.layer};
background: ${props =>
props.highlight ? "#231f20" : theme.colors.primaryDarker};
width: 105px;
height: 40px;
border-radius: 134px;
color: white;
border: 0;
box-shadow: 2px 4px 5px #888888;
}
`;
export function HelpModal() {
const isHelpModalOpen = useSelector(getHelpModalOpen);
const helpDimensions = useSelector(getHelpModalDimensions);
const helpModalOpen = useSelector(getHelpModalOpen);
const dispatch = useDispatch();
const layers = useContext(LayersContext);
return (
<>
<ModalComponent
canOutsideClickClose
canEscapeKeyClose
scrollContents
width={helpDimensions.width}
height={helpDimensions.height}
top={window.innerHeight - 95 - helpDimensions.height}
left={window.innerWidth - 31 - helpDimensions.width}
data-cy={"help-modal"}
hasBackDrop={false}
onClose={() => {
dispatch(setHelpModalVisibility(false));
dispatch(setHelpDefaultRefinement(""));
}}
isOpen={isHelpModalOpen}
zIndex={layers.help}
>
<DocumentationSearch hitsPerPage={5} />
</ModalComponent>
<HelpButton
className="t--helpGlobalButton"
highlight={!helpModalOpen}
text="Docs"
icon="search"
filled
intent={IntentColors.primary}
iconAlignment={Position.LEFT}
layer={layers.help}
onClick={() => {
dispatch(setHelpModalVisibility(!helpModalOpen));
}}
/>
</>
);
}

View File

@ -2,9 +2,9 @@ import styled from "styled-components";
import { Callout } from "@blueprintjs/core";
import { Colors } from "constants/Colors";
const CalloutComponent = styled(Callout)`
const CalloutComponent = styled(Callout)<{ background?: string }>`
&& {
background-color: ${Colors.WHITE_SMOKE};
background-color: ${props => props.background || Colors.WHITE_SMOKE};
}
`;

View File

@ -5,18 +5,21 @@ import { getCanvasClassName } from "utils/generators";
const Container = styled.div<{
width: number;
height: number;
top?: number;
left?: number;
zIndex?: number;
}>`
&&& {
.${Classes.OVERLAY} {
.${Classes.OVERLAY_BACKDROP} {
z-index: 1;
z-index: ${props => props.zIndex};
}
position: fixed;
top: ${props => props.theme.headerHeight};
right: 0;
bottom: 0;
height: 100vh;
z-index: 1;
z-index: ${props => props.zIndex};
width: 100%;
display: flex;
justify-content: center;
@ -27,6 +30,9 @@ const Container = styled.div<{
min-height: ${props => props.height}px;
background: white;
border-radius: ${props => props.theme.radii[1]}px;
top: ${props => props.top}px;
left: ${props => props.left}px;
// z-index: ${props => props.zIndex};
}
}
}
@ -52,6 +58,10 @@ export type ModalComponentProps = {
canEscapeKeyClose: boolean;
scrollContents: boolean;
height: number;
top?: number;
left?: number;
hasBackDrop?: boolean;
zIndex?: number;
};
/* eslint-disable react/display-name */
@ -65,7 +75,13 @@ export const ModalComponent = (props: ModalComponentProps) => {
}
}, [props.scrollContents]);
return (
<Container width={props.width} height={props.height}>
<Container
width={props.width}
height={props.height}
top={props.top}
left={props.left}
zIndex={props.zIndex !== undefined ? props.zIndex : 1}
>
<Overlay
isOpen={props.isOpen}
onClose={props.onClose}
@ -73,6 +89,9 @@ export const ModalComponent = (props: ModalComponentProps) => {
canEscapeKeyClose={props.canEscapeKeyClose}
usePortal={false}
enforceFocus={false}
hasBackdrop={
props.hasBackDrop !== undefined ? !!props.hasBackDrop : true
}
>
<div>
<Content

View File

@ -168,7 +168,9 @@ const Wrapper = styled.div<{
&& {
.binding-highlight {
color: ${props =>
props.editorTheme === THEMES.DARK ? "#f7c75b" : "#ffb100"};
props.editorTheme === THEMES.DARK
? props.theme.colors.bindingTextDark
: props.theme.colors.bindingText};
font-weight: 700;
}
.CodeMirror {

View File

@ -2,26 +2,45 @@ import React from "react";
import styled from "styled-components";
import { NavLink } from "react-router-dom";
import AnalyticsUtil from "utils/AnalyticsUtil";
import NotificationIcon from "components/designSystems/appsmith/NotificationIcon";
import { theme } from "constants/DefaultTheme";
type MenuBarItemProps = {
icon: Function;
path: string;
title: string;
exact: boolean;
width: number;
height: number;
external?: boolean;
className?: string;
highlight?: boolean;
onClick?: Function;
};
// const AnmiatedNotificationIcon = <NotificationIcon pla></NotificationIcon>
const StyledNotificationIcon = styled(NotificationIcon)`
position: absolute;
top: -4px;
right: -3px;
`;
type Props = MenuBarItemProps;
const IconContainer = styled.div`
const IconContainer = styled.div<{
width: number;
height: number;
}>`
display: flex;
align-items: center;
justify-content: center;
margin: 0 auto;
margin-bottom: 5px;
background-color: ${props => props.theme.colors.menuButtonBGInactive};
border-radius: ${props => props.theme.radii[1]}px;
height: 32px;
width: 32px;
height: ${props => props.height}px;
width: ${props => props.width}px;
svg path {
fill: ${props => props.theme.colors.menuIconColorInactive};
}
@ -55,30 +74,80 @@ const ItemContainer = styled.div`
}
}
}
span {
width: 100%;
display: inline-block;
text-align: center;
}
}
`;
const Anchor = styled.a`
width: 64px;
display: inline-block;
`;
const ExternalLink = function(props: any) {
return (
<Anchor
onClick={() => {
props.onClick && props.onClick();
}}
href={props.to}
className={props.className}
target="_blank"
>
{props.children}
</Anchor>
);
};
const DetailsContainer = styled.div`
position: relative;
`;
class NavBarItem extends React.Component<Props> {
render(): React.ReactNode {
const { title, icon, path, exact } = this.props;
const {
title,
icon,
path,
exact,
width,
height,
external,
highlight,
onClick,
} = this.props;
const Link = external ? ExternalLink : NavLink;
return (
<ItemContainer>
<NavLink
<Link
exact={exact}
to={path}
className={this.props.className}
onClick={() => {
onClick && onClick();
AnalyticsUtil.logEvent("SIDEBAR_NAVIGATION", {
navPage: this.props.title.toUpperCase(),
});
}}
>
<React.Fragment>
<IconContainer>{icon({ width: 24, height: 24 })}</IconContainer>
{title}
</React.Fragment>
</NavLink>
<DetailsContainer>
<IconContainer width={width} height={height}>
{icon({ width: width - 8, height: height - 8 })}
</IconContainer>
<span>{title}</span>
{highlight && (
<StyledNotificationIcon
animate
width={9}
height={9}
color={theme.colors.primary}
/>
)}
</DetailsContainer>
</Link>
</ItemContainer>
);
}

View File

@ -1,13 +1,13 @@
import React, { useContext } from "react";
import styled from "styled-components";
import { useSelector } from "react-redux";
import { useSelector, useDispatch } from "react-redux";
import { AppState } from "reducers";
import { ControlIcons } from "icons/ControlIcons";
import { EditorContext } from "components/editorComponents/EditorContextProvider";
import { theme } from "constants/DefaultTheme";
import { Colors } from "constants/Colors";
import { PropertyPaneReduxState } from "reducers/uiReducers/propertyPaneReducer";
import { Tooltip } from "@blueprintjs/core";
import { Tooltip, Icon } from "@blueprintjs/core";
import {
useShowPropertyPane,
useWidgetSelection,
@ -15,6 +15,13 @@ import {
import AnalyticsUtil from "utils/AnalyticsUtil";
import { WidgetOperations } from "widgets/BaseWidget";
import { WidgetType } from "constants/WidgetConstants";
import { HelpMap, HelpBaseURL } from "constants/HelpConstants";
import {
setHelpDefaultRefinement,
setHelpModalVisibility,
} from "actions/helpActions";
import FeatureFlag from "utils/featureFlags";
import { FeatureFlagsEnum } from "configs/types";
const CONTROL_ICON_SIZE = 20;
@ -38,6 +45,13 @@ const PositionStyle = styled.div<{ selected?: boolean }>`
}
`;
const HelpControl = styled.div`
position: absolute;
right: ${props => props.theme.spaces[13] * 2 - 10}px;
top: -${props => props.theme.spaces[2]}px;
cursor: pointer;
`;
const DeleteControl = styled.div`
position: absolute;
right: ${props => props.theme.spaces[13]}px;
@ -58,6 +72,26 @@ const deleteControlIcon = (
);
const EditIcon = ControlIcons.EDIT_CONTROL;
const HelpIcon = styled(Icon)<{ width: number; height: number }>`
width: ${props => props.width}px;
height: ${props => props.width}px;
color: ${Colors.SHARK};
svg {
width: ${props => props.width}px;
height: ${props => props.width}px;
}
`;
// const HelpIcon = ControlIcons.HELP_CONTROL;
const helpControlIcon = (
<HelpIcon
width={CONTROL_ICON_SIZE}
height={CONTROL_ICON_SIZE}
icon="help"
></HelpIcon>
);
type WidgetNameComponentProps = {
widgetName?: string;
widgetId: string;
@ -68,6 +102,7 @@ type WidgetNameComponentProps = {
export const WidgetNameComponent = (props: WidgetNameComponentProps) => {
const { updateWidget } = useContext(EditorContext);
const dispatch = useDispatch();
const showPropertyPane = useShowPropertyPane();
// Dispatch hook handy to set a widget as focused/selected
const { selectWidget } = useWidgetSelection();
@ -148,6 +183,20 @@ export const WidgetNameComponent = (props: WidgetNameComponentProps) => {
return showWidgetName ? (
<PositionStyle selected={selectedWidget === props.widgetId}>
<pre>{props.widgetName}</pre>
{FeatureFlag.check(FeatureFlagsEnum.documentationV2) && (
<HelpControl
className="control t--widget-help-control"
onClick={() => {
dispatch(setHelpDefaultRefinement(HelpMap[props.type].searchKey));
dispatch(setHelpModalVisibility(true));
// window.open(`${HelpBaseURL}${HelpMap[props.type]}`, "_blank");
}}
>
<Tooltip content="Open Help" hoverOpenDelay={500}>
{helpControlIcon}
</Tooltip>
</HelpControl>
)}
<DeleteControl
className="control t--widget-delete-control"
onClick={deleteWidget}

View File

@ -7,6 +7,17 @@ const autoConfig = (baseUrl: string): AppsmithUIConfigs => ({
enabled: false,
key: "NZALSCjsaxOIyprzITLz2yZwFzQynGt1",
},
featureFlag: {
// remoteConfig: {
// optimizely: "PVDSYRhBhvUVY3tN6mkV1s",
// },
default: {
documentationv2: true,
apipanev2: true,
datasourcepane: true,
querypane: true,
},
},
});
export default autoConfig;

View File

@ -1,6 +1,5 @@
import { SENTRY_STAGE_CONFIG } from "constants/ThirdPartyConstants";
import { AppsmithUIConfigs } from "./types";
import { FeatureFlagEnum } from "utils/featureFlags";
const devConfig = (baseUrl: string): AppsmithUIConfigs => ({
sentry: {
@ -14,14 +13,20 @@ const devConfig = (baseUrl: string): AppsmithUIConfigs => ({
enabled: false,
key: "NZALSCjsaxOIyprzITLz2yZwFzQynGt1",
},
featureFlag: {
remoteConfig: {
optimizely: "PVDSYRhBhvUVY3tN6mkV1s",
},
default: {
documentationv2: true,
apipanev2: true,
datasourcepane: true,
querypane: true,
},
},
apiUrl: "/api/",
baseUrl,
logLevel: "debug",
featureFlags: [
FeatureFlagEnum.ApiPaneV2,
FeatureFlagEnum.DatasourcePane,
FeatureFlagEnum.QueryPane,
],
});
export default devConfig;

View File

@ -4,7 +4,6 @@ import {
HOTJAR_PROD_HJSV,
} from "constants/ThirdPartyConstants";
import { AppsmithUIConfigs } from "./types";
import { FeatureFlagEnum } from "utils/featureFlags";
export const prodConfig = (baseUrl: string): AppsmithUIConfigs => ({
sentry: {
@ -25,11 +24,17 @@ export const prodConfig = (baseUrl: string): AppsmithUIConfigs => ({
apiUrl: "/api/",
baseUrl,
logLevel: "error",
featureFlags: [
FeatureFlagEnum.ApiPaneV2,
FeatureFlagEnum.DatasourcePane,
FeatureFlagEnum.QueryPane,
],
featureFlag: {
remoteConfig: {
optimizely: "Jq3K2kVdvuvxecHyHbVYcj",
},
default: {
documentationv2: true,
apipanev2: true,
datasourcepane: true,
querypane: true,
},
},
});
export default prodConfig;

View File

@ -1,6 +1,5 @@
import { SENTRY_STAGE_CONFIG } from "constants/ThirdPartyConstants";
import { AppsmithUIConfigs } from "./types";
import { FeatureFlagEnum } from "utils/featureFlags";
const stageConfig = (baseUrl: string): AppsmithUIConfigs => ({
sentry: {
@ -14,14 +13,20 @@ const stageConfig = (baseUrl: string): AppsmithUIConfigs => ({
enabled: true,
key: "NZALSCjsaxOIyprzITLz2yZwFzQynGt1",
},
featureFlag: {
remoteConfig: {
optimizely: "2qP3XSwgM9pHYTEYbtbAQx",
},
default: {
documentationv2: true,
apipanev2: true,
datasourcepane: true,
querypane: true,
},
},
apiUrl: "/api/",
baseUrl,
logLevel: "info",
featureFlags: [
FeatureFlagEnum.ApiPaneV2,
FeatureFlagEnum.DatasourcePane,
FeatureFlagEnum.QueryPane,
],
});
export default stageConfig;

View File

@ -1,5 +1,4 @@
import { LogLevelDesc } from "loglevel";
import { FeatureFlagEnum } from "utils/featureFlags";
export type SentryConfig = {
dsn: string;
@ -11,6 +10,24 @@ export type HotjarConfig = {
sv: string;
};
type Milliseconds = number;
export enum FeatureFlagsEnum {
ApiPaneV2 = "apipanev2",
DatasourcePane = "datasourcepane",
QueryPane = "querypane",
documentationV2 = "documentationv2",
}
export type FeatureFlags = Record<FeatureFlagsEnum, boolean>;
export type FeatureFlagConfig = {
remoteConfig?: {
optimizely: string;
};
default: FeatureFlags;
};
export type AppsmithUIConfigs = {
sentry: {
enabled: boolean;
@ -20,6 +37,7 @@ export type AppsmithUIConfigs = {
enabled: boolean;
config?: HotjarConfig;
};
featureFlag: FeatureFlagConfig;
segment: {
enabled: boolean;
key: string;
@ -27,5 +45,4 @@ export type AppsmithUIConfigs = {
apiUrl: string;
baseUrl: string;
logLevel: LogLevelDesc;
featureFlags: Array<FeatureFlagEnum>;
};

View File

@ -12,6 +12,8 @@ export const Colors: Record<string, string> = {
GRAY_CHATEAU: "#A2A6A8",
LIGHT_GREYISH_BLUE: "#B0BFCB",
SUNGLOW: "#FFCB33",
SOFT_ORANGE: "#f7c75b",
PURE_ORANGE: "#ffb100",
BLACK: "#000000",
BLACK_PEARL: "#040627",

View File

@ -347,6 +347,9 @@ export const theme: Theme = {
widgetSecondaryBorder: Colors.MERCURY,
messageBG: Colors.CONCRETE,
paneIcon: Colors.TROUT,
notification: Colors.JAFFA,
bindingTextDark: Colors.SOFT_ORANGE,
bindingText: Colors.PURE_ORANGE,
},
lineHeights: [0, 14, 18, 22, 24, 28, 36, 48, 64, 80],
fonts: [

View File

@ -0,0 +1,92 @@
export const HelpMap = {
CONTAINER_WIDGET: {
path: "/widget-reference/container",
searchKey: "Container",
},
CHECKBOX_WIDGET: {
path: "/widget-reference/checkbox",
searchKey: "Checkbox",
},
BUTTON_WIDGET: {
path: "/widget-reference/button",
searchKey: "Button",
},
TEXT_WIDGET: {
path: "/widget-reference/text",
searchKey: "Text",
},
IMAGE_WIDGET: {
path: "/widget-reference/image",
searchKey: "Image",
},
INPUT_WIDGET: {
path: "/widget-reference/input",
searchKey: "Input",
},
DATE_PICKER_WIDGET: {
path: "/widget-reference/datepicker",
searchKey: "DatePicker",
},
TABLE_WIDGET: {
path: "/widget-reference/table",
searchKey: "Table",
},
DROP_DOWN_WIDGET: {
path: "/widget-reference/dropdown",
searchKey: "Dropdown",
},
RADIO_GROUP_WIDGET: {
path: "/widget-reference/radio",
searchKey: "Radio",
},
RICH_TEXT_EDITOR_WIDGET: {
path: "",
searchKey: "Rich Text Editor",
},
CHART_WIDGET: {
path: "/widget-reference/chart",
searchKey: "Chart",
},
FORM_WIDGET: {
path: "/widget-reference/form",
searchKey: "Form",
},
FILE_PICKER_WIDGET: {
path: "/widget-reference/filepicker",
searchKey: "File picker",
},
FORM_BUTTON_WIDGET: {
path: "",
searchKey: "",
},
CANVAS_WIDGET: {
path: "",
searchKey: "",
},
ICON_WIDGET: {
path: "",
searchKey: "",
},
TABS_WIDGET: {
path: "",
searchKey: "Tabs",
},
MODAL_WIDGET: {
path: "",
searchKey: "",
},
MAP_WIDGET: {
path: "",
searchKey: "Map",
},
API_MAIN: {
path: "/core-concepts/apis",
searchKey: "Apis",
},
API_BINDING: {
path: "/core-concepts/apis/taking-inputs-from-widgets",
searchKey: "Taking Inputs from Widgets",
},
};
export const HelpBaseURL = "https://docs.appsmith.com";

View File

@ -0,0 +1,25 @@
import React from "react";
enum Indices {
Layer0,
Layer1,
Layer2,
Layer3,
Layer4,
Layer5,
Layer6,
Layer7,
LayerMax = 99999,
}
export const Layers = {
dropZone: Indices.Layer0,
dragPreview: Indices.Layer1,
widgetName: Indices.Layer2,
apiPane: Indices.Layer3,
help: Indices.Layer4,
dynamicAutoComplete: Indices.Layer5,
max: Indices.LayerMax,
};
export const LayersContext = React.createContext(Layers);

View File

@ -213,6 +213,8 @@ export const ReduxActionTypes: { [key: string]: string } = {
FETCH_PROVIDER_DETAILS_BY_PROVIDER_ID_SUCCESS:
"FETCH_PROVIDER_DETAILS_BY_PROVIDER_ID_SUCCESS",
SET_PROVIDERS_LENGTH: "SET_PROVIDERS_LENGTH",
SET_DEFAULT_REFINEMENT: "SET_DEFAULT_REFINEMENT",
SET_HELP_MODAL_OPEN: "SET_HELP_MODAL_OPEN",
};
export type ReduxActionType = typeof ReduxActionTypes[keyof typeof ReduxActionTypes];

View File

@ -1,5 +1,6 @@
import { MenuIcons } from "icons/MenuIcons";
import { FeatureFlagEnum } from "utils/featureFlags";
import FeatureFlag from "utils/featureFlags";
import { FeatureFlagsEnum } from "configs/types";
export const BASE_URL = "/";
export const ORG_URL = "/org";
@ -174,7 +175,7 @@ export const EDITOR_ROUTES = [
path: QUERIES_EDITOR_URL,
title: "Queries",
exact: false,
flag: FeatureFlagEnum.QueryPane,
allowed: FeatureFlag.check(FeatureFlagsEnum.QueryPane),
},
{
icon: MenuIcons.DATASOURCES_ICON,
@ -182,7 +183,7 @@ export const EDITOR_ROUTES = [
path: DATA_SOURCES_EDITOR_URL,
title: "Datasources",
exact: false,
flag: FeatureFlagEnum.DatasourcePane,
allowed: FeatureFlag.check(FeatureFlagsEnum.DatasourcePane),
},
{
icon: MenuIcons.PAGES_ICON,

View File

@ -12,6 +12,8 @@ import { ReactComponent as DecreaseIcon } from "assets/icons/control/decrease.sv
import { ReactComponent as DraggableIcon } from "assets/icons/control/draggable.svg";
import { ReactComponent as CloseIcon } from "assets/icons/control/close.svg";
import { ReactComponent as HelpIcon } from "assets/icons/control/help.svg";
import { ReactComponent as PickMyLocationSelectedIcon } from "assets/icons/control/pick-location-selected.svg";
/* eslint-disable react/display-name */
@ -78,6 +80,11 @@ export const ControlIcons: {
<PickMyLocationSelectedIcon />
</IconWrapper>
),
HELP_CONTROL: (props: IconProps) => (
<IconWrapper {...props}>
<HelpIcon />
</IconWrapper>
),
};
export type ControlIconName = keyof typeof ControlIcons;

View File

@ -0,0 +1,17 @@
import React, { JSXElementConstructor } from "react";
import { IconProps, IconWrapper } from "constants/IconConstants";
import { ReactComponent as OpenLinkIcon } from "assets/icons/help/openlink.svg";
/* eslint-disable react/display-name */
export const HelpIcons: {
[id: string]: JSXElementConstructor<IconProps>;
} = {
OPEN_LINK: (props: IconProps) => (
<IconWrapper {...props}>
<OpenLinkIcon />
</IconWrapper>
),
};
export type HelpIconName = keyof typeof HelpIcons;

View File

@ -7,6 +7,7 @@ import { ReactComponent as PagesIcon } from "assets/icons/menu/pages.svg";
import { ReactComponent as DataSourcesIcon } from "assets/icons/menu/data-sources.svg";
import { ReactComponent as QueriesIcon } from "assets/icons/menu/queries.svg";
import { ReactComponent as HomepageIcon } from "assets/icons/menu/homepage.svg";
import { Icon } from "@blueprintjs/core";
/* eslint-disable react/display-name */
export const MenuIcons: {
@ -47,4 +48,9 @@ export const MenuIcons: {
<HomepageIcon />
</IconWrapper>
),
DOCS_ICON: (props: IconProps) => (
<IconWrapper {...props}>
<Icon icon="help"></Icon>
</IconWrapper>
),
};

View File

@ -24,6 +24,8 @@ import {
BASE_SIGNUP_URL,
USERS_URL,
} from "constants/routes";
import { HelpModal } from "components/designSystems/appsmith/help/HelpModal";
import { LayersContext, Layers } from "constants/Layers";
const loadingIndicator = <Loader />;
const App = lazy(() =>
@ -56,73 +58,75 @@ appInitializer();
ReactDOM.render(
<Provider store={store}>
<ThemeProvider theme={theme}>
<ToastContainer
hideProgressBar
draggable={false}
transition={Slide}
autoClose={5000}
closeButton={false}
/>
<Helmet>
<meta charSet="utf-8" />
<link rel="shortcut icon" href="/favicon-orange.ico" />
</Helmet>
<Router history={history}>
<Suspense fallback={loadingIndicator}>
<Switch>
<AppRoute
exact
path={BASE_URL}
component={App}
name={"App"}
routeProtected
/>
<AppRoute
path={ORG_URL}
component={Organization}
name={"Organisation"}
routeProtected
/>
<AppRoute
exact
path={USERS_URL}
component={Users}
name={"Users"}
routeProtected
/>
<AppRoute
path={USER_AUTH_URL}
component={UserAuth}
name={"UserAuth"}
/>
<Redirect exact from={BASE_LOGIN_URL} to={AUTH_LOGIN_URL} />
<Redirect exact from={BASE_SIGNUP_URL} to={SIGN_UP_URL} />
<AppRoute
exact
path={APPLICATIONS_URL}
component={Applications}
name={"Home"}
routeProtected
/>
<AppRoute
path={BUILDER_URL}
component={Editor}
name={"Editor"}
routeProtected
/>
<AppRoute
path={APP_VIEW_URL}
component={AppViewer}
name={"AppViewer"}
routeProtected
logDisable
/>
<AppRoute component={PageNotFound} name={"PageNotFound"} />
</Switch>
</Suspense>
</Router>
</ThemeProvider>
<LayersContext.Provider value={Layers}>
<ThemeProvider theme={theme}>
<ToastContainer
hideProgressBar
draggable={false}
transition={Slide}
autoClose={5000}
closeButton={false}
/>
<Helmet>
<meta charSet="utf-8" />
<link rel="shortcut icon" href="/favicon-orange.ico" />
</Helmet>
<Router history={history}>
<Suspense fallback={loadingIndicator}>
<Switch>
<AppRoute
exact
path={BASE_URL}
component={App}
name={"App"}
routeProtected
/>
<AppRoute
path={ORG_URL}
component={Organization}
name={"Organisation"}
routeProtected
/>
<AppRoute
exact
path={USERS_URL}
component={Users}
name={"Users"}
routeProtected
/>
<AppRoute
path={USER_AUTH_URL}
component={UserAuth}
name={"UserAuth"}
/>
<Redirect exact from={BASE_LOGIN_URL} to={AUTH_LOGIN_URL} />
<Redirect exact from={BASE_SIGNUP_URL} to={SIGN_UP_URL} />
<AppRoute
exact
path={APPLICATIONS_URL}
component={Applications}
name={"Home"}
routeProtected
/>
<AppRoute
path={BUILDER_URL}
component={Editor}
name={"Editor"}
routeProtected
/>
<AppRoute
path={APP_VIEW_URL}
component={AppViewer}
name={"AppViewer"}
routeProtected
logDisable
/>
<AppRoute component={PageNotFound} name={"PageNotFound"} />
</Switch>
</Suspense>
</Router>
</ThemeProvider>
</LayersContext.Provider>
</Provider>,
document.getElementById("root"),
);

View File

@ -29,6 +29,9 @@ import LoadingOverlayScreen from "components/editorComponents/LoadingOverlayScre
import { FormIcons } from "icons/FormIcons";
import { BaseTabbedView } from "components/designSystems/appsmith/TabbedView";
import Pagination, { PaginationType } from "./Pagination";
import { Icon } from "@blueprintjs/core";
import { HelpMap, HelpBaseURL } from "constants/HelpConstants";
import CollapsibleHelp from "components/designSystems/appsmith/help/CollapsibleHelp";
const Form = styled.form`
display: flex;
@ -99,6 +102,18 @@ const TabbedViewContainer = styled.div`
padding-top: 12px;
`;
export const BindingText = styled.span`
color: ${props => props.theme.colors.bindingTextDark};
font-weight: 700;
`;
const StyledOpenDocsIcon = styled(Icon)`
svg {
width: 12px;
height: 18px;
}
`;
interface APIFormProps {
pluginId: string;
allowSave: boolean;
@ -229,6 +244,17 @@ const ApiEditorForm: React.FC<Props> = (props: Props) => {
title: "API Input",
panelComponent: (
<RequestParamsWrapper>
<CollapsibleHelp>
<span>{`Having trouble taking inputs from widget?`}</span>
<a
href={`${HelpBaseURL}${HelpMap["API_BINDING"].path}`}
target="_blank"
rel="noopener noreferrer"
>
{" Learn How "}
<StyledOpenDocsIcon icon="document-open"></StyledOpenDocsIcon>
</a>
</CollapsibleHelp>
<HeadersSection>
<KeyValueFieldArray
name="actionConfiguration.headers"

View File

@ -115,6 +115,9 @@ const PostBodyData = (props: Props) => {
showLineNumbers
allowTabIndent
singleLine={false}
placeholder={
'Please enter this POST request\'s JSON body.\n\n\nDid you know?\n\tIn Appsmith, we can use a widget\'s or API\'s property dynamically, using {{ }} templates.\n\n\tFor example: If we have an input widget named Input1 in which the user would provide their name \n\tand this post body structure should be { "name": "<text from Input1>" } \n\tWe can access it in this post body using { "name": "{{Input1.text}}" }'
}
/>
</JSONEditorFieldWrapper>
</React.Fragment>

View File

@ -25,8 +25,9 @@ import { UserApplication } from "constants/userConstants";
import AnalyticsUtil from "utils/AnalyticsUtil";
import { getActionById, getCurrentPageName } from "selectors/editorSelectors";
import { Plugin } from "api/PluginApi";
import { checkForFlag, FeatureFlagEnum } from "utils/featureFlags";
import styled from "styled-components";
import FeatureFlag from "utils/featureFlags";
import { FeatureFlagsEnum } from "configs/types";
const EmptyStateContainer = styled.div`
display: flex;
@ -163,10 +164,14 @@ class ApiEditor extends React.Component<Props> {
{"Create / Select an API from the list"}
</EmptyStateContainer>
);
const v2Flag = checkForFlag(FeatureFlagEnum.ApiPaneV2);
const v2Flag = FeatureFlag.check(FeatureFlagsEnum.ApiPaneV2);
const homeScreen = v2Flag ? apiHomeScreen : defaultHomeScreen;
return (
<React.Fragment>
<div
style={{
position: "relative",
}}
>
{apiId ? (
<>
{formUiComponent === "ApiEditorForm" && (
@ -213,7 +218,7 @@ class ApiEditor extends React.Component<Props> {
) : (
homeScreen
)}
</React.Fragment>
</div>
);
}
}

View File

@ -24,7 +24,8 @@ import EditorSidebar from "pages/Editor/EditorSidebar";
import { getNextEntityName } from "utils/AppsmithUtils";
import AnalyticsUtil from "utils/AnalyticsUtil";
import { Page } from "constants/ReduxActionConstants";
import { checkForFlag, FeatureFlagEnum } from "utils/featureFlags";
import { FeatureFlagsEnum } from "configs/types";
import FeatureFlag from "utils/featureFlags";
const HTTPMethod = styled.span<{ method?: string }>`
flex: 1;
@ -185,7 +186,7 @@ class ApiSidebar extends React.Component<Props> {
handleCreateNewApiClick = (selectedPageId: string) => {
const { history, createNewApiAction } = this.props;
const { pageId, applicationId } = this.props.match.params;
const v2Flag = checkForFlag(FeatureFlagEnum.ApiPaneV2);
const v2Flag = FeatureFlag.check(FeatureFlagsEnum.ApiPaneV2);
if (v2Flag) {
history.push(
API_EDITOR_URL_WITH_SELECTED_PAGE_ID(

View File

@ -20,6 +20,9 @@ import {
getOnSelectAction,
} from "pages/common/CustomizedDropdown/dropdownHelpers";
import AnalyticsUtil from "utils/AnalyticsUtil";
import { HelpModal } from "components/designSystems/appsmith/help/HelpModal";
import FeatureFlag from "utils/featureFlags";
import { FeatureFlagsEnum } from "configs/types";
const LoadingContainer = styled.div`
display: flex;
@ -137,7 +140,6 @@ export const EditorHeader = (props: EditorHeaderProps) => {
<StyledHeader>
<StretchedBreadCrumb items={navigation} minVisibleItems={3} />
<CustomizedDropdown {...pageSelectorData} />
<LoadingContainer>{saveStatusMessage}</LoadingContainer>
<PreviewPublishSection>
<Button
@ -150,6 +152,9 @@ export const EditorHeader = (props: EditorHeaderProps) => {
className="t--application-publish-btn"
/>
</PreviewPublishSection>
{FeatureFlag.check(FeatureFlagsEnum.documentationV2) && (
<HelpModal></HelpModal>
)}
</StyledHeader>
);
};

View File

@ -21,6 +21,7 @@ import TreeDropdown from "components/editorComponents/actioncreator/TreeDropdown
import { theme } from "constants/DefaultTheme";
import { Colors } from "constants/Colors";
import { ControlIcons } from "icons/ControlIcons";
import NotificationIcon from "components/designSystems/appsmith/NotificationIcon";
const LoadingContainer = styled(CenteredWrapper)`
height: 50%;
@ -164,11 +165,7 @@ const ItemContainer = styled.div<{
}
`;
const DraftIconIndicator = styled.span<{ isHidden: boolean }>`
width: 8px;
height: 8px;
border-radius: 8px;
background-color: #f2994a;
const DraftIconIndicator = styled(NotificationIcon)<{ isHidden: boolean }>`
margin: 0 5px;
opacity: ${({ isHidden }) => (isHidden ? 0 : 1)};
`;

View File

@ -14,7 +14,7 @@ import {
getIsPropertyPaneVisible,
getWidgetPropsForPropertyPane,
} from "selectors/propertyPaneSelectors";
import { Divider } from "@blueprintjs/core";
import { Divider, Icon, Tooltip, Position } from "@blueprintjs/core";
import Popper from "pages/Editor/Popper";
import { ControlProps } from "components/propertyControls/BaseControl";
@ -28,6 +28,7 @@ import PropertyPaneTitle from "pages/Editor/PropertyPaneTitle";
import PropertyControl from "pages/Editor/PropertyPane/PropertyControl";
import AnalyticsUtil from "utils/AnalyticsUtil";
import * as log from "loglevel";
import { BindingText } from "pages/Editor/APIEditor/Form";
const PropertySectionLabel = styled.div`
text-transform: uppercase;
@ -44,6 +45,11 @@ const PropertyPaneWrapper = styled.div`
width: 100%;
`;
const StyledToolTip = styled(Tooltip)`
position: absolute;
top: 0;
right: 35px;
`;
class PropertyPane extends Component<
PropertyPaneProps & PropertyPaneFunctions
> {
@ -79,6 +85,27 @@ class PropertyPane extends Component<
title={widgetProperties.widgetName}
widgetId={this.props.widgetId}
/>
<StyledToolTip
content={
<div>
<span>You can connect data from your API by adding </span>
<BindingText>{`{{apiName.data}}`}</BindingText>
<span> to a widget property</span>
</div>
}
position={Position.TOP}
hoverOpenDelay={200}
>
<Icon
style={{
// position: "absolute",
// right: 35,
padding: 7,
}}
color={theme.colors.paneSectionLabel}
icon="help"
/>
</StyledToolTip>
<CloseButton
onClick={(e: any) => {

View File

@ -1,10 +1,9 @@
import React from "react";
import React, { useState } from "react";
import { useParams } from "react-router-dom";
import styled from "styled-components";
import SidebarComponent from "components/editorComponents/Sidebar";
import NavBarItem from "components/editorComponents/NavBarItem";
import { EDITOR_ROUTES, BuilderRouteParams } from "constants/routes";
import { checkForFlag } from "utils/featureFlags";
const Wrapper = styled.div`
display: grid;
@ -17,6 +16,8 @@ const Wrapper = styled.div`
const NavBar = styled.div`
background-color: ${props => props.theme.colors.navBG};
color: ${props => props.theme.colors.textOnDarkBG};
display: flex;
flex-direction: column;
`;
const EditorSidebar = styled(SidebarComponent)`
@ -24,22 +25,60 @@ const EditorSidebar = styled(SidebarComponent)`
`;
const allowedRoutes = EDITOR_ROUTES.filter(route => {
if (route.flag) return checkForFlag(route.flag);
return true;
return route.allowed !== undefined ? route.allowed : true;
});
const TopBar = styled.div`
border-bottom: 1px solid #4e5d78;
`;
const BottomBar = styled.div`
display: flex;
padding-bottom: 118px;
height: 100%;
align-items: flex-end;
`;
const Sidebar = () => {
const params = useParams<BuilderRouteParams>();
// const docsNavConfig = {
// icon: MenuIcons.DOCS_ICON,
// className: "t--nav-link-docs",
// title: "Docs",
// exact: true,
// };
// const [highlightDocs, setHighlightDocs] = useState(
// !localStorage.getItem("hasSeenDocs"),
// );
// const [hasSeenDocs, setHasSeenDocs] = useLocalStorage("hasSeenDocs", false);
return (
<Wrapper>
<NavBar>
{allowedRoutes.map(config => (
<NavBarItem
key={config.title}
{...config}
path={config.path(params.applicationId, params.pageId)}
/>
))}
<TopBar>
{allowedRoutes.map(config => (
<NavBarItem
key={config.title}
{...config}
width={32}
height={32}
path={config.path(params.applicationId, params.pageId)}
/>
))}
</TopBar>
<BottomBar>
{/* <NavBarItem
width={20}
height={20}
key={docsNavConfig.title}
onClick={() => {
setHighlightDocs(false);
localStorage.setItem("hasSeenDocs", "true");
}}
{...docsNavConfig}
external
highlight={highlightDocs}
path={HelpBaseURL}
></NavBarItem> */}
</BottomBar>
</NavBar>
<EditorSidebar />
</Wrapper>

View File

@ -27,6 +27,7 @@ import { ImportedCollectionsReduxState } from "reducers/uiReducers/importedColle
import { ProvidersReduxState } from "reducers/uiReducers/providerReducer";
import { MetaState } from "./entityReducers/metaReducer";
import { ImportReduxState } from "reducers/uiReducers/importReducer";
import { HelpReduxState } from "./uiReducers/helpReducer";
const appReducer = combineReducers({
entities: entityReducer,
@ -54,6 +55,7 @@ export interface AppState {
imports: ImportReduxState;
queryPane: QueryPaneReduxState;
datasourcePane: DatasourcePaneReduxState;
help: HelpReduxState;
};
entities: {
canvasWidgets: CanvasWidgetsReduxState;

View File

@ -0,0 +1,35 @@
import { createReducer } from "utils/AppsmithUtils";
import { ReduxAction, ReduxActionTypes } from "constants/ReduxActionConstants";
const initialState: HelpReduxState = {
url: "",
modalOpen: false,
height: 442,
width: 352,
defaultRefinement: "",
};
const helpReducer = createReducer(initialState, {
[ReduxActionTypes.SET_DEFAULT_REFINEMENT]: (
state: HelpReduxState,
action: ReduxAction<string>,
) => {
return { ...state, defaultRefinement: action.payload };
},
[ReduxActionTypes.SET_HELP_MODAL_OPEN]: (
state: HelpReduxState,
action: ReduxAction<boolean>,
) => {
return { ...state, modalOpen: action.payload };
},
});
export interface HelpReduxState {
url: string;
modalOpen: boolean;
height: number;
width: number;
defaultRefinement: string;
}
export default helpReducer;

View File

@ -15,6 +15,7 @@ import importedCollectionsReducer from "./importedCollectionsReducer";
import providersReducer from "./providerReducer";
import importReducer from "./importReducer";
import queryPaneReducer from "./queryPaneReducer";
import helpReducer from "./helpReducer";
const uiReducer = combineReducers({
widgetSidebar: widgetSidebarReducer,
@ -33,5 +34,6 @@ const uiReducer = combineReducers({
imports: importReducer,
queryPane: queryPaneReducer,
datasourcePane: datasourcePaneReducer,
help: helpReducer,
});
export default uiReducer;

View File

@ -0,0 +1,18 @@
import { AppState } from "reducers";
export const getHelpUrl = (state: AppState): string => state.ui.help.url;
export const getHelpModalOpen = (state: AppState): boolean =>
state.ui.help.modalOpen;
export const getHelpModalDimensions = (
state: AppState,
): { height: number; width: number } => {
return {
height: state.ui.help.height,
width: state.ui.help.width,
};
};
export const getDefaultRefinement = (state: AppState): string => {
return state.ui.help.defaultRefinement || "";
};

View File

@ -1,5 +1,6 @@
// Events
import * as log from "loglevel";
import FeatureFlag from "./featureFlags";
export type EventName =
| "LOGIN_CLICK"
@ -191,6 +192,7 @@ class AnalyticsUtil {
static identifyUser(userId: string, userData: User) {
const windowDoc: any = window;
AnalyticsUtil.user = userData;
FeatureFlag.identify(userData);
if (windowDoc.analytics) {
windowDoc.analytics.identify(userId, userData);
}

View File

@ -10,7 +10,7 @@ import { ActionDataState } from "reducers/entityReducers/actionsReducer";
import * as log from "loglevel";
import { LogLevelDesc } from "loglevel";
import { providerBackgroundColors } from "constants/providerConstants";
import { FeatureFlagEnum } from "utils/featureFlags";
import FeatureFlag from "utils/featureFlags";
export const createReducer = (
initialState: any,
@ -28,6 +28,8 @@ export const createReducer = (
export const appInitializer = () => {
FormControlRegistry.registerFormControlBuilders();
const appsmithConfigs = getAppsmithConfigs();
FeatureFlag.initialize(appsmithConfigs.featureFlag);
if (appsmithConfigs.sentry.enabled && appsmithConfigs.sentry.config) {
Sentry.init(appsmithConfigs.sentry.config);
}
@ -38,8 +40,9 @@ export const appInitializer = () => {
if (appsmithConfigs.segment.enabled) {
AnalyticsUtil.initializeSegment(appsmithConfigs.segment.key);
}
log.setLevel(getEnvLogLevel(appsmithConfigs.logLevel));
setConfigFeatureFlags(appsmithConfigs.featureFlags);
// setConfigFeatureFlags(appsmithConfigs.featureFlags);
const textFont = new FontFaceObserver("DM Sans");
textFont
@ -133,11 +136,11 @@ const getEnvLogLevel = (configLevel: LogLevelDesc): LogLevelDesc => {
return logLevel;
};
const setConfigFeatureFlags = (flags: Array<FeatureFlagEnum>) => {
flags.forEach(flag => {
localStorage.setItem(flag, "true");
});
};
// const setConfigFeatureFlags = (flags: Array<FeatureFlagEnum>) => {
// flags.forEach(flag => {
// localStorage.setItem(flag, "true");
// });
// };
export const getInitialsAndColorCode = (fullName: any): string[] => {
let inits = "";
@ -166,3 +169,24 @@ const getColorCode = (initials: string): string => {
}
return providerBackgroundColors[asciiSum % providerBackgroundColors.length];
};
export function hexToRgb(
hex: string,
): {
r: number;
g: number;
b: number;
} {
const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
return result
? {
r: parseInt(result[1], 16),
g: parseInt(result[2], 16),
b: parseInt(result[3], 16),
}
: {
r: -1,
g: -1,
b: -1,
};
}

View File

@ -1,9 +1,99 @@
export enum FeatureFlagEnum {
ApiPaneV2 = "ApiPaneV2",
DatasourcePane = "DatasourcePane",
QueryPane = "QueryPane",
import { FeatureFlagConfig, FeatureFlagsEnum } from "configs/types";
const optimizelySDK = require("@optimizely/optimizely-sdk");
class FeatureFlag {
static isInitialized = false;
static remote = undefined;
static initialize(featureFlagConfig: FeatureFlagConfig) {
Object.keys(featureFlagConfig.default).forEach((flag: any) => {
// This is required because otherwise it will reset the values
// every time the application is loaded. We need the application to load
// remote values the second time.
if (localStorage.getItem(flag) === null) {
localStorage.setItem(
flag,
featureFlagConfig.default[flag as FeatureFlagsEnum].toString(),
);
}
});
if (featureFlagConfig.remoteConfig) {
FeatureFlag.remote = optimizelySDK.createInstance({
sdkKey: featureFlagConfig.remoteConfig.optimizely,
});
(FeatureFlag.remote as any).onReady().then(onInit);
}
}
static identify(userData: any) {
if (FeatureFlag.remote) {
if (FeatureFlag.isInitialized) {
updateFlagsInLocalStorage(userData);
} else {
(FeatureFlag.remote as any).onReady().then(() => {
onInit();
updateFlagsInLocalStorage(userData);
});
}
}
}
static check(flagName: string) {
return localStorage.getItem(flagName) === "true";
}
}
export const checkForFlag = (flagName: FeatureFlagEnum) => {
return localStorage.getItem(flagName);
};
function onInit() {
FeatureFlag.isInitialized = true;
}
function updateFlagsInLocalStorage(userData: any) {
const userId = userData.id;
const email = userData.email;
const optimizelyClientInstance = FeatureFlag.remote as any;
localStorage.setItem(
FeatureFlagsEnum.DatasourcePane,
optimizelyClientInstance.isFeatureEnabled(
FeatureFlagsEnum.DatasourcePane,
userId,
{
email: email,
},
),
);
localStorage.setItem(
FeatureFlagsEnum.ApiPaneV2,
optimizelyClientInstance.isFeatureEnabled(
FeatureFlagsEnum.ApiPaneV2,
userId,
{
email: email,
},
),
);
localStorage.setItem(
FeatureFlagsEnum.documentationV2,
optimizelyClientInstance.isFeatureEnabled(
FeatureFlagsEnum.documentationV2,
userId,
{
email: email,
},
),
);
localStorage.setItem(
FeatureFlagsEnum.QueryPane,
optimizelyClientInstance.isFeatureEnabled(
FeatureFlagsEnum.QueryPane,
userId,
{
email: email,
},
),
);
}
export default FeatureFlag;

View File

@ -2,6 +2,110 @@
# yarn lockfile v1
"@algolia/cache-browser-local-storage@4.2.0":
version "4.2.0"
resolved "https://registry.yarnpkg.com/@algolia/cache-browser-local-storage/-/cache-browser-local-storage-4.2.0.tgz#45cc4be4c8fcd69cb98ebaa2e78a459a1cf6ba64"
integrity sha512-uji5zxBxwNu8qKtyqghg9lUsN0OOZ58NfRKk0Il4IZCcCo78E0KfT3Uxr7XiYCJMRnqIsvbKWf0xA67tYNBSbA==
dependencies:
"@algolia/cache-common" "4.2.0"
"@algolia/cache-common@4.2.0":
version "4.2.0"
resolved "https://registry.yarnpkg.com/@algolia/cache-common/-/cache-common-4.2.0.tgz#ada18e559f205a63eaf60c21a035b3d41f0f8d7d"
integrity sha512-ATBQCBBLt4hPNKIKn06y5zqZPWQmI+PBF0287rFVj8BGmEr82BzoKMa5XIkvgpjtxwx6c5nSKxZaYkEFqtrxtQ==
"@algolia/cache-in-memory@4.2.0":
version "4.2.0"
resolved "https://registry.yarnpkg.com/@algolia/cache-in-memory/-/cache-in-memory-4.2.0.tgz#82f07cc99aee9e20a96bdd69c635bdd2dc4288f1"
integrity sha512-NsVOR6ixK6jvurLW+1+h80/9N18QjU/AXdAZJoVeu4JXb2NPuej4Ld1zXFYvz/ypCFQE+dU8haaQnJIuTbD4vg==
dependencies:
"@algolia/cache-common" "4.2.0"
"@algolia/client-account@4.2.0":
version "4.2.0"
resolved "https://registry.yarnpkg.com/@algolia/client-account/-/client-account-4.2.0.tgz#7abf3dd8922fde1735b1e0d19e8b0bdbf64a1435"
integrity sha512-xz5OXU9DQ9pegABAgmTPV23f9tXmbUPO3w5J/b2QcP6jzfNnNfW3CkTwywgNLr16jIKLxmmClN5yqyJp6XmHBA==
dependencies:
"@algolia/client-common" "4.2.0"
"@algolia/client-search" "4.2.0"
"@algolia/transporter" "4.2.0"
"@algolia/client-analytics@4.2.0":
version "4.2.0"
resolved "https://registry.yarnpkg.com/@algolia/client-analytics/-/client-analytics-4.2.0.tgz#11e9331fed5bbaa6668d71c890dff60c4af1c741"
integrity sha512-UNuZQOYuKPYl5fCgm1HZzoZ6Ewxtqrc4Cv5Dhdy5VatIV6lYEWOtdn+g+5qvWFGb6fv6688dg5EVJnXZNvVVZQ==
dependencies:
"@algolia/client-common" "4.2.0"
"@algolia/client-search" "4.2.0"
"@algolia/requester-common" "4.2.0"
"@algolia/transporter" "4.2.0"
"@algolia/client-common@4.2.0":
version "4.2.0"
resolved "https://registry.yarnpkg.com/@algolia/client-common/-/client-common-4.2.0.tgz#bf8a550dc51927bb103de9aab7e6ac4d90a9cf0d"
integrity sha512-KxZTWXf9FSl188iTAz9rhTMeBtbF/uaJcxw99jbWHxyK9KR87obZzTlTFYnIWLEBaTG1MmlgPSsDogAE4CHLOQ==
dependencies:
"@algolia/requester-common" "4.2.0"
"@algolia/transporter" "4.2.0"
"@algolia/client-recommendation@4.2.0":
version "4.2.0"
resolved "https://registry.yarnpkg.com/@algolia/client-recommendation/-/client-recommendation-4.2.0.tgz#bd49b5b9601fe4220ba6db0fc397d816584ee4ec"
integrity sha512-5QwvUJ5hpZVDz99o+EPgMg+z7maLWOZGUrUt5z8s+esl+taTb2h1PtyLpikAvC2d/BjYCEKyObTiRDYdzhqcoA==
dependencies:
"@algolia/client-common" "4.2.0"
"@algolia/requester-common" "4.2.0"
"@algolia/transporter" "4.2.0"
"@algolia/client-search@4.2.0":
version "4.2.0"
resolved "https://registry.yarnpkg.com/@algolia/client-search/-/client-search-4.2.0.tgz#4917499cac66a5cca7f2ca9d1334bffc96a79b17"
integrity sha512-2SAz1/undr+RM7FNj3G0taWFG+8QEMQcYHxUhoOJKMIY9sPQN7UNCJRHYsulM+/g45oF67tXX09NSt14ewen0Q==
dependencies:
"@algolia/client-common" "4.2.0"
"@algolia/requester-common" "4.2.0"
"@algolia/transporter" "4.2.0"
"@algolia/logger-common@4.2.0":
version "4.2.0"
resolved "https://registry.yarnpkg.com/@algolia/logger-common/-/logger-common-4.2.0.tgz#dd373b267594656d72a1563f6621ab7f727c4373"
integrity sha512-VQcJE5lr78oc+lbcGfPonCDTRwLNSxwtPrUP6Tj+CoDedsVHZhODAlHzLHhxc4vuyrU7xomvKJLqTUgfDNxzXQ==
"@algolia/logger-console@4.2.0":
version "4.2.0"
resolved "https://registry.yarnpkg.com/@algolia/logger-console/-/logger-console-4.2.0.tgz#10e18ab75f60fd0f2e2b16cb9a1b0bcc947087f2"
integrity sha512-/1GE43jY0xKfJUi5ZGtEqq+oTyOzs+EgGKj7/zEHIpUc5NyxokIPWTqt3q6pzGSWFEkNbaA1gAVgXM1zCMVWYw==
dependencies:
"@algolia/logger-common" "4.2.0"
"@algolia/requester-browser-xhr@4.2.0":
version "4.2.0"
resolved "https://registry.yarnpkg.com/@algolia/requester-browser-xhr/-/requester-browser-xhr-4.2.0.tgz#c2a7982bef940e1749f2ba2aa04e3f8a971b6a78"
integrity sha512-+PZKOe+UBdZYQg/h/8AbKQ2Ha4uDeoLnpZFv00IMr/elym0m2hl76xAeIBiIqGYsLCmGybGBFUF9n1imsKJUJQ==
dependencies:
"@algolia/requester-common" "4.2.0"
"@algolia/requester-common@4.2.0":
version "4.2.0"
resolved "https://registry.yarnpkg.com/@algolia/requester-common/-/requester-common-4.2.0.tgz#df67a940516d5a313bbf79bcbceddadfff9f8ce2"
integrity sha512-SSKPRM/7UP54/dxyK6EYt4p6nTeJxYb1P6xVh/Ic6noBTCfqg5vBEKDa1DZD5MBtCvABoODd97UOfAo3ECG/jg==
"@algolia/requester-node-http@4.2.0":
version "4.2.0"
resolved "https://registry.yarnpkg.com/@algolia/requester-node-http/-/requester-node-http-4.2.0.tgz#e26efd3d630b7c988bcc9cda3a8ee68ab4a168dd"
integrity sha512-mRQgSM8qrMfjXaBnMjTmymR0NKwbr82Qwh1a5TgYyzMOBuRO5nRikawvTVgpNaEnQS0uesIiwd2ohOJ2gNu6oA==
dependencies:
"@algolia/requester-common" "4.2.0"
"@algolia/transporter@4.2.0":
version "4.2.0"
resolved "https://registry.yarnpkg.com/@algolia/transporter/-/transporter-4.2.0.tgz#9e6bea3304f1e6f4a64a3d7c1f9de047ba89056f"
integrity sha512-7CiwMYsEhrHySA8q70euIYOyhGtz/wz+MEC3nwGONBC82nGI6ntVqTFhCkpLIJqqbGbNlFgnCpwnLmSqLhRP3A==
dependencies:
"@algolia/cache-common" "4.2.0"
"@algolia/logger-common" "4.2.0"
"@algolia/requester-common" "4.2.0"
"@babel/code-frame@7.5.5":
version "7.5.5"
resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.5.5.tgz#bc0782f6d69f7b7d49531219699b988f669a8f9d"
@ -1717,6 +1821,57 @@
"@nodelib/fs.scandir" "2.1.3"
fastq "^1.6.0"
"@optimizely/js-sdk-datafile-manager@^0.5.0":
version "0.5.0"
resolved "https://registry.yarnpkg.com/@optimizely/js-sdk-datafile-manager/-/js-sdk-datafile-manager-0.5.0.tgz#d6283ca3f8d2a60f30a6c300aaadf6a99cd9255e"
integrity sha512-ZDov8jphA+Ez+fA0anioA8ooJrraCFbeGm7GejzPTCZPMisNGtchrpdHr9TMd+hld+TOMBZ5NbqfMvvYhbB34A==
dependencies:
"@optimizely/js-sdk-logging" "^0.1.0"
"@optimizely/js-sdk-utils" "^0.2.0"
decompress-response "^4.2.1"
"@optimizely/js-sdk-event-processor@^0.4.0":
version "0.4.0"
resolved "https://registry.yarnpkg.com/@optimizely/js-sdk-event-processor/-/js-sdk-event-processor-0.4.0.tgz#51e06cfda2eedf6a7f3829f8e0132fb5c0b640a8"
integrity sha512-5fqBG9N66O+9KWktUTH/OmMiQ4SKi42gP7qqWNKe0Ciu5PlBMTREKmo8+EixcDvDW8yQBvIPBj6GWzKz0RVAxg==
dependencies:
"@optimizely/js-sdk-logging" "^0.1.0"
"@optimizely/js-sdk-utils" "^0.2.0"
"@optimizely/js-sdk-logging@^0.1.0":
version "0.1.0"
resolved "https://registry.yarnpkg.com/@optimizely/js-sdk-logging/-/js-sdk-logging-0.1.0.tgz#e5950c3d9a708fbd5931a043130469c5df7f64e8"
integrity sha512-Bs2zHvsdNIk2QSg05P6mKIlROHoBIRNStbrVwlePm603CucojKRPlFJG4rt7sFZQOo8xS8I7z1BmE4QI3/ZE9A==
dependencies:
"@optimizely/js-sdk-utils" "^0.1.0"
"@optimizely/js-sdk-utils@^0.1.0":
version "0.1.0"
resolved "https://registry.yarnpkg.com/@optimizely/js-sdk-utils/-/js-sdk-utils-0.1.0.tgz#e3ac1fef81f11c15774f4743c3fa7c65d9c3352a"
integrity sha512-p7499GgVaX94YmkrwOiEtLgxgjXTPbUQsvETaAil5J7zg1TOA4Wl8ClalLSvCh+AKWkxGdkL4/uM/zfbxPSNNw==
dependencies:
uuid "^3.3.2"
"@optimizely/js-sdk-utils@^0.2.0":
version "0.2.0"
resolved "https://registry.yarnpkg.com/@optimizely/js-sdk-utils/-/js-sdk-utils-0.2.0.tgz#f24c971f09c3c63f7a4b9eb4da6ba9642bf61cd0"
integrity sha512-aHEccRVc5YjWAdIVtniKfUE3tuzHriIWZTS4sLEq/lXkNTITSL1jrBEJD91CVY5BahWu/aG/aOafrA7XGH3sDQ==
dependencies:
uuid "^3.3.2"
"@optimizely/optimizely-sdk@^4.0.0":
version "4.0.0"
resolved "https://registry.yarnpkg.com/@optimizely/optimizely-sdk/-/optimizely-sdk-4.0.0.tgz#0e63fb3fdd70e95481029025b2c633e9bd93f88d"
integrity sha512-ufwndTjg6wPXnJmbW/3SK2F3Dt7E1S1VQZ5oCoYrsLZ2oFrhES/urbWWTzC1t83gAokbqzSEZDuc/OBdZ6c9SA==
dependencies:
"@optimizely/js-sdk-datafile-manager" "^0.5.0"
"@optimizely/js-sdk-event-processor" "^0.4.0"
"@optimizely/js-sdk-logging" "^0.1.0"
"@optimizely/js-sdk-utils" "^0.2.0"
json-schema "^0.2.3"
murmurhash "0.0.2"
uuid "^3.3.2"
"@reach/router@^1.2.1":
version "1.3.1"
resolved "https://registry.yarnpkg.com/@reach/router/-/router-1.3.1.tgz#0a49f75fa9621323d6e21c803447bcfcde1713b2"
@ -2531,6 +2686,18 @@
dependencies:
prop-types "^15.6.2"
"@types/algoliasearch-helper@*":
version "2.26.1"
resolved "https://registry.yarnpkg.com/@types/algoliasearch-helper/-/algoliasearch-helper-2.26.1.tgz#60cf377e7cb4bd9a55f7eba35182792763230a24"
integrity sha512-JN1wq/yLxxBcc6MeSe57F9Aqv8wL964L0nBOUTSQ5OECzWxaECuGYV06VnGKn/c+9AGB97RAgqx2PUbYflZNqA==
dependencies:
"@types/algoliasearch" "*"
"@types/algoliasearch@*":
version "3.34.10"
resolved "https://registry.yarnpkg.com/@types/algoliasearch/-/algoliasearch-3.34.10.tgz#08cd8f7018451197d7a51c21e1305794aca187b9"
integrity sha512-P6OKrRClvlVIF645zmRdGt3pK/IlBeFMAqB/OqM5Z/iYVFp8mSYMFR+uAdADsv0X/8AC6bIPAfj2x+mjslBuFg==
"@types/anymatch@*":
version "1.3.1"
resolved "https://registry.yarnpkg.com/@types/anymatch/-/anymatch-1.3.1.tgz#336badc1beecb9dacc38bea2cf32adf627a8421a"
@ -2751,6 +2918,22 @@
dependencies:
"@types/react" "*"
"@types/react-instantsearch-core@*":
version "6.3.0"
resolved "https://registry.yarnpkg.com/@types/react-instantsearch-core/-/react-instantsearch-core-6.3.0.tgz#74acc99250ce416a96a0b1896e127a283a9f6b76"
integrity sha512-EZVOXs9CBxTwGbIdYX/JUk2hB9/lkaGK0rSnbnJ9C1MXe73xEpV7THrlgaFg6BO+5yrEPAf2NazCALR1WpaVwA==
dependencies:
"@types/algoliasearch-helper" "*"
"@types/react" "*"
"@types/react-instantsearch-dom@^6.3.0":
version "6.3.0"
resolved "https://registry.yarnpkg.com/@types/react-instantsearch-dom/-/react-instantsearch-dom-6.3.0.tgz#5543a2fbe85d5c8a7658d61fdb92fcba1cf2e616"
integrity sha512-sq4WXWSVVhH8NV7s6xcc/c+SkiyMewRefCPleXK3p9676rIFyKwotRkh8x7IoXOBV3V2avfU3Xr65Y9scRZlZQ==
dependencies:
"@types/react" "*"
"@types/react-instantsearch-core" "*"
"@types/react-native@*":
version "0.61.10"
resolved "https://registry.yarnpkg.com/@types/react-native/-/react-native-0.61.10.tgz#d010b9093322bc781151638f74124f58fc87cc90"
@ -3394,6 +3577,33 @@ ajv@^6.1.0, ajv@^6.10.0, ajv@^6.10.2, ajv@^6.5.5:
json-schema-traverse "^0.4.1"
uri-js "^4.2.2"
algoliasearch-helper@^3.1.0, algoliasearch-helper@^3.1.1:
version "3.1.1"
resolved "https://registry.yarnpkg.com/algoliasearch-helper/-/algoliasearch-helper-3.1.1.tgz#4cdfbaed6670d82626ac1fae001ccbf53192f497"
integrity sha512-Jkqlp8jezQRixf7sbQ2zFXHpdaT41g9sHBqT6pztv5nfDmg94K+pwesAy6UbxRY78IL54LIaV1FLttMtT+IzzA==
dependencies:
events "^1.1.1"
algoliasearch@^4.2.0:
version "4.2.0"
resolved "https://registry.yarnpkg.com/algoliasearch/-/algoliasearch-4.2.0.tgz#dd81a1a0c57eb9f74af6db70b0c11f256692d1e6"
integrity sha512-CgbyDBGMSzNISBFezPt68xAseknork+wNe/Oour1Hluk4OwbtobysRawFf93ZbLSQw/KbeGlVmVAvujeVIVdnQ==
dependencies:
"@algolia/cache-browser-local-storage" "4.2.0"
"@algolia/cache-common" "4.2.0"
"@algolia/cache-in-memory" "4.2.0"
"@algolia/client-account" "4.2.0"
"@algolia/client-analytics" "4.2.0"
"@algolia/client-common" "4.2.0"
"@algolia/client-recommendation" "4.2.0"
"@algolia/client-search" "4.2.0"
"@algolia/logger-common" "4.2.0"
"@algolia/logger-console" "4.2.0"
"@algolia/requester-browser-xhr" "4.2.0"
"@algolia/requester-common" "4.2.0"
"@algolia/requester-node-http" "4.2.0"
"@algolia/transporter" "4.2.0"
align-text@^0.1.1, align-text@^0.1.3:
version "0.1.4"
resolved "https://registry.yarnpkg.com/align-text/-/align-text-0.1.4.tgz#0cd90a561093f35d0a99256c22b7069433fad117"
@ -5551,6 +5761,13 @@ decode-uri-component@^0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545"
decompress-response@^4.2.1:
version "4.2.1"
resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-4.2.1.tgz#414023cc7a302da25ce2ec82d0d5238ccafd8986"
integrity sha512-jOSne2qbyE+/r8G1VU+G/82LBs2Fs4LAsTiLSHOCOMZQl2OKZ6i8i4IyHemTe+/yIXOtTcRQMzPcgyhoFlqPkw==
dependencies:
mimic-response "^2.0.0"
dedent@^0.7.0:
version "0.7.0"
resolved "https://registry.yarnpkg.com/dedent/-/dedent-0.7.0.tgz#2495ddbaf6eb874abb0e1be9df22d2e5a544326c"
@ -6358,6 +6575,11 @@ eventemitter3@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.0.tgz#d65176163887ee59f386d64c82610b696a4a74eb"
events@^1.1.0, events@^1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/events/-/events-1.1.1.tgz#9ebdb7635ad099c70dcc4c2a1f5004288e8bd924"
integrity sha1-nr23Y1rQmccNzEwqH1AEKI6L2SQ=
events@^3.0.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/events/-/events-3.1.0.tgz#84279af1b34cb75aa88bf5ff291f6d0bd9b31a59"
@ -7476,6 +7698,14 @@ hmac-drbg@^1.0.0:
minimalistic-assert "^1.0.0"
minimalistic-crypto-utils "^1.0.1"
hogan.js@^3.0.2:
version "3.0.2"
resolved "https://registry.yarnpkg.com/hogan.js/-/hogan.js-3.0.2.tgz#4cd9e1abd4294146e7679e41d7898732b02c7bfd"
integrity sha1-TNnhq9QpQUbnZ55B14mHMrAse/0=
dependencies:
mkdirp "0.3.0"
nopt "1.0.10"
hoist-non-react-statics@^2.3.1:
version "2.5.5"
resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-2.5.5.tgz#c5903cf409c0dfd908f388e619d86b9c1174cb47"
@ -7832,6 +8062,24 @@ inquirer@7.0.4, inquirer@^7.0.0:
strip-ansi "^5.1.0"
through "^2.3.6"
instantsearch.css@^7.4.2:
version "7.4.2"
resolved "https://registry.yarnpkg.com/instantsearch.css/-/instantsearch.css-7.4.2.tgz#2b02db07c865ce2c946ec20c1eb4556377cad90c"
integrity sha512-CaOdFWCpHOWGAkJRpwC4+8ROU3Upp3xrUuc0Mg92UucJ84MWMJWkVZDDyRwubgJe4HXQM2rV6b+bJaDeeZGunw==
instantsearch.js@^4.4.1:
version "4.4.1"
resolved "https://registry.yarnpkg.com/instantsearch.js/-/instantsearch.js-4.4.1.tgz#debbc77131bba35b6920fe0bfbcc65eb75484fd0"
integrity sha512-CphyvXNHYCkPYCUTPtjYA//AJ3yn29gX09KrcahxVfXbgxZDMUMcNnF0BnCAYjjVB9U49NXKOrZf6VZ8Z57EwA==
dependencies:
algoliasearch-helper "^3.1.1"
classnames "^2.2.5"
events "^1.1.0"
hogan.js "^3.0.2"
preact "^10.0.0"
prop-types "^15.5.10"
qs "^6.5.1"
internal-ip@^4.3.0:
version "4.3.0"
resolved "https://registry.yarnpkg.com/internal-ip/-/internal-ip-4.3.0.tgz#845452baad9d2ca3b69c635a137acb9a0dad0907"
@ -8864,6 +9112,11 @@ json-schema@0.2.3:
version "0.2.3"
resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13"
json-schema@^0.2.3:
version "0.2.5"
resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.5.tgz#97997f50972dd0500214e208c407efa4b5d7063b"
integrity sha512-gWJOWYFrhQ8j7pVm0EM8Slr+EPVq1Phf6lvzvD/WCeqkrx/f2xBI0xOsRRS9xCn3I4vKtP519dvs3TP09r24wQ==
json-stable-stringify-without-jsonify@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651"
@ -9649,6 +9902,11 @@ mimic-fn@^2.0.0, mimic-fn@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b"
mimic-response@^2.0.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-2.1.0.tgz#d13763d35f613d09ec37ebb30bac0469c0ee8f43"
integrity sha512-wXqjST+SLt7R009ySCglWBCFpjUygmCIfD790/kVbiGmUgfYGuB14PiTd5DwVxSV4NcYHjzMkoj5LjQZwTQLEA==
min-document@^2.19.0:
version "2.19.0"
resolved "https://registry.yarnpkg.com/min-document/-/min-document-2.19.0.tgz#7bd282e3f5842ed295bb748cdd9f1ffa2c824685"
@ -9756,6 +10014,11 @@ mixin-object@^2.0.1:
for-in "^0.1.3"
is-extendable "^0.1.1"
mkdirp@0.3.0:
version "0.3.0"
resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.3.0.tgz#1bbf5ab1ba827af23575143490426455f481fe1e"
integrity sha1-G79asbqCevI1dRQ0kEJkVfSB/h4=
mkdirp@0.5.1, "mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.1:
version "0.5.1"
resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903"
@ -9885,6 +10148,11 @@ multicast-dns@^6.0.1:
dns-packet "^1.3.1"
thunky "^1.0.2"
murmurhash@0.0.2:
version "0.0.2"
resolved "https://registry.yarnpkg.com/murmurhash/-/murmurhash-0.0.2.tgz#6f07bd8a1105e709c26fc89420cb5930c24585fe"
integrity sha1-bwe9ihEF5wnCb8iUIMtZMMJFhf4=
mutationobserver-shim@^0.3.3:
version "0.3.3"
resolved "https://registry.yarnpkg.com/mutationobserver-shim/-/mutationobserver-shim-0.3.3.tgz#65869630bc89d7bf8c9cd9cb82188cd955aacd2b"
@ -10080,6 +10348,13 @@ node-sass@^4.11.0:
stdout-stream "^1.4.0"
"true-case-path" "^1.0.2"
nopt@1.0.10:
version "1.0.10"
resolved "https://registry.yarnpkg.com/nopt/-/nopt-1.0.10.tgz#6ddd21bd2a31417b92727dd585f8a6f37608ebee"
integrity sha1-bd0hvSoxQXuScn3Vhfim83YI6+4=
dependencies:
abbrev "1"
"nopt@2 || 3":
version "3.0.6"
resolved "https://registry.yarnpkg.com/nopt/-/nopt-3.0.6.tgz#c6465dbf08abcd4db359317f79ac68a646b28ff9"
@ -11379,6 +11654,11 @@ preact@8.2.9:
version "8.2.9"
resolved "https://registry.yarnpkg.com/preact/-/preact-8.2.9.tgz#813ba9dd45e5d97c5ea0d6c86d375b3be711cc40"
preact@^10.0.0:
version "10.4.1"
resolved "https://registry.yarnpkg.com/preact/-/preact-10.4.1.tgz#9b3ba020547673a231c6cf16f0fbaef0e8863431"
integrity sha512-WKrRpCSwL2t3tpOOGhf2WfTpcmbpxaWtDbdJdKdjd0aEiTkvOmS4NBkG6kzlaAHI9AkQ3iVqbFWM3Ei7mZ4o1Q==
prelude-ls@~1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54"
@ -11687,6 +11967,11 @@ qs@6.7.0:
version "6.7.0"
resolved "https://registry.yarnpkg.com/qs/-/qs-6.7.0.tgz#41dc1a015e3d581f1621776be31afb2876a9b1bc"
qs@^6.5.1:
version "6.9.4"
resolved "https://registry.yarnpkg.com/qs/-/qs-6.9.4.tgz#9090b290d1f91728d3c22e54843ca44aea5ab687"
integrity sha512-A1kFqHekCTM7cz0udomYUoYNWjBebHm/5wzU/XqrBRBNWectVH0QIiN+NEcZ0Dte5hvzHwbr8+XQmguPhJ6WdQ==
qs@^6.6.0:
version "6.9.1"
resolved "https://registry.yarnpkg.com/qs/-/qs-6.9.1.tgz#20082c65cb78223635ab1a9eaca8875a29bf8ec9"
@ -11988,6 +12273,11 @@ react-fast-compare@^2.0.2, react-fast-compare@^2.0.4:
version "2.0.4"
resolved "https://registry.yarnpkg.com/react-fast-compare/-/react-fast-compare-2.0.4.tgz#e84b4d455b0fec113e0402c329352715196f81f9"
react-fast-compare@^3.0.0:
version "3.0.2"
resolved "https://registry.yarnpkg.com/react-fast-compare/-/react-fast-compare-3.0.2.tgz#8b0bfa93a049ec1eef9d54ab5e5c6036c317144d"
integrity sha512-1fBw8Efm6fb1blbRorZcO3OqzWgxYWxXzlaNeqEVXcrDdyFzeqygrPVU6qrPuqnqYMpUJVkQBdDgDJQTmCXp+Q==
react-focus-lock@^2.1.0:
version "2.2.1"
resolved "https://registry.yarnpkg.com/react-focus-lock/-/react-focus-lock-2.2.1.tgz#1d12887416925dc53481914b7cedd39494a3b24a"
@ -12053,6 +12343,27 @@ react-input-autosize@^2.2.2:
dependencies:
prop-types "^15.5.8"
react-instantsearch-core@^6.4.0:
version "6.4.0"
resolved "https://registry.yarnpkg.com/react-instantsearch-core/-/react-instantsearch-core-6.4.0.tgz#12dd37163b3f3297d7ab6d1ee78b649df5e06d5f"
integrity sha512-iJ33uxpo9suc9p8LTH3v5by5BXzhuttBvSaoePZheuLLG8dnbpiUt+m0iC4oeyr1cgubKJ1OhGCL8AQN2fR11A==
dependencies:
"@babel/runtime" "^7.1.2"
algoliasearch-helper "^3.1.0"
prop-types "^15.5.10"
react-fast-compare "^3.0.0"
react-instantsearch-dom@^6.4.0:
version "6.4.0"
resolved "https://registry.yarnpkg.com/react-instantsearch-dom/-/react-instantsearch-dom-6.4.0.tgz#61c7e453652136ebc549e6427e2dab7d57519f07"
integrity sha512-FyJaD+jVNt59KOd8Nt6nQrmueEEJNH0VmS9IlSwWbQz2NrkQniaCFm+k8G13LsAASOCq4vQ8ULG2up+WpJeS8w==
dependencies:
"@babel/runtime" "^7.1.2"
algoliasearch-helper "^3.1.0"
classnames "^2.2.5"
prop-types "^15.5.10"
react-instantsearch-core "^6.4.0"
react-is@^16.12.0, react-is@^16.6.0, react-is@^16.7.0, react-is@^16.8.1, react-is@^16.8.4, react-is@^16.8.6, react-is@^16.9.0:
version "16.12.0"
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.12.0.tgz#2cc0fe0fba742d97fd527c42a13bec4eeb06241c"