Api Sidebar and Api dropdown fixes
This commit is contained in:
parent
3010ec3296
commit
fadb2cae6b
|
|
@ -36,6 +36,7 @@
|
||||||
"eslint": "^6.4.0",
|
"eslint": "^6.4.0",
|
||||||
"flow-bin": "^0.91.0",
|
"flow-bin": "^0.91.0",
|
||||||
"fontfaceobserver": "^2.1.0",
|
"fontfaceobserver": "^2.1.0",
|
||||||
|
"fuse.js": "^3.4.5",
|
||||||
"history": "^4.10.1",
|
"history": "^4.10.1",
|
||||||
"husky": "^3.0.5",
|
"husky": "^3.0.5",
|
||||||
"jsonpath-plus": "^1.0.0",
|
"jsonpath-plus": "^1.0.0",
|
||||||
|
|
|
||||||
|
|
@ -33,18 +33,29 @@ const selectStyles = {
|
||||||
...provided,
|
...provided,
|
||||||
backgroundColor: "rgba(104,113,239,0.1)",
|
backgroundColor: "rgba(104,113,239,0.1)",
|
||||||
border: "1px solid rgba(104, 113, 239, 0.5)",
|
border: "1px solid rgba(104, 113, 239, 0.5)",
|
||||||
borderRadius: `${theme.radii[3]}px`,
|
borderRadius: `${theme.radii[1]}px`,
|
||||||
padding: "2px 5px",
|
padding: "2px 5px",
|
||||||
fontSize: "14px",
|
fontSize: "14px",
|
||||||
maxWidth: "95%",
|
maxWidth: "95%",
|
||||||
|
position: "relative",
|
||||||
|
display: "inline-block",
|
||||||
|
transform: "none",
|
||||||
}),
|
}),
|
||||||
container: (styles: any) => ({
|
container: (styles: any) => ({
|
||||||
...styles,
|
...styles,
|
||||||
flex: 1,
|
flex: 1,
|
||||||
}),
|
}),
|
||||||
control: (styles: any) => ({
|
control: (styles: any, state: any) => ({
|
||||||
...styles,
|
...styles,
|
||||||
|
width: 370,
|
||||||
minHeight: "32px",
|
minHeight: "32px",
|
||||||
|
border: state.isFocused
|
||||||
|
? `${theme.colors.secondary} solid 1px`
|
||||||
|
: `${theme.colors.inputInactiveBorders} solid 1px`,
|
||||||
|
boxShadow: state.isFocused ? 0 : 0,
|
||||||
|
"&:hover": {
|
||||||
|
border: `${theme.colors.secondary} solid 1px`,
|
||||||
|
},
|
||||||
}),
|
}),
|
||||||
indicatorsContainer: (provided: any) => ({
|
indicatorsContainer: (provided: any) => ({
|
||||||
...provided,
|
...provided,
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import Select from "react-select";
|
import Select from "react-select";
|
||||||
import { WrappedFieldInputProps } from "redux-form";
|
import { WrappedFieldInputProps } from "redux-form";
|
||||||
|
import { theme } from "../../../constants/DefaultTheme";
|
||||||
|
|
||||||
type DropdownProps = {
|
type DropdownProps = {
|
||||||
options: Array<{
|
options: Array<{
|
||||||
|
|
@ -12,10 +13,17 @@ type DropdownProps = {
|
||||||
};
|
};
|
||||||
|
|
||||||
const selectStyles = {
|
const selectStyles = {
|
||||||
control: (styles: any) => ({
|
control: (styles: any, state: any) => ({
|
||||||
...styles,
|
...styles,
|
||||||
width: 100,
|
width: 100,
|
||||||
minHeight: "32px",
|
minHeight: "32px",
|
||||||
|
border: state.isFocused
|
||||||
|
? `${theme.colors.secondary} solid 1px`
|
||||||
|
: `${theme.colors.inputInactiveBorders} solid 1px`,
|
||||||
|
boxShadow: state.isFocused ? 0 : 0,
|
||||||
|
"&:hover": {
|
||||||
|
border: `${theme.colors.secondary} solid 1px`,
|
||||||
|
},
|
||||||
}),
|
}),
|
||||||
indicatorsContainer: (provided: any) => ({
|
indicatorsContainer: (provided: any) => ({
|
||||||
...provided,
|
...provided,
|
||||||
|
|
|
||||||
|
|
@ -4,9 +4,9 @@ import { WrappedFieldInputProps, WrappedFieldMetaProps } from "redux-form";
|
||||||
import { IconName, InputGroup, MaybeElement } from "@blueprintjs/core";
|
import { IconName, InputGroup, MaybeElement } from "@blueprintjs/core";
|
||||||
import { ComponentProps } from "./BaseComponent";
|
import { ComponentProps } from "./BaseComponent";
|
||||||
|
|
||||||
const TextInput = styled(InputGroup)`
|
export const TextInput = styled(InputGroup)`
|
||||||
flex: 1;
|
flex: 1;
|
||||||
&&& input {
|
& input {
|
||||||
border: 1px solid ${props => props.theme.colors.inputInactiveBorders};
|
border: 1px solid ${props => props.theme.colors.inputInactiveBorders};
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
box-shadow: none;
|
box-shadow: none;
|
||||||
|
|
@ -18,7 +18,7 @@ const TextInput = styled(InputGroup)`
|
||||||
outline: 0;
|
outline: 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
&&&&.bp3-input-group .bp3-input:not(:first-child) {
|
&.bp3-input-group .bp3-input:not(:first-child) {
|
||||||
padding-left: 35px;
|
padding-left: 35px;
|
||||||
}
|
}
|
||||||
.bp3-icon {
|
.bp3-icon {
|
||||||
|
|
@ -59,12 +59,13 @@ export interface TextInputProps {
|
||||||
meta?: WrappedFieldMetaProps;
|
meta?: WrappedFieldMetaProps;
|
||||||
icon?: IconName | MaybeElement;
|
icon?: IconName | MaybeElement;
|
||||||
showError?: boolean;
|
showError?: boolean;
|
||||||
|
className?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const BaseTextInput = (props: TextInputProps) => {
|
export const BaseTextInput = (props: TextInputProps) => {
|
||||||
const { placeholderMessage, input, meta, icon, showError } = props;
|
const { placeholderMessage, input, meta, icon, showError, className } = props;
|
||||||
return (
|
return (
|
||||||
<InputContainer>
|
<InputContainer className={className}>
|
||||||
<TextInput {...input} placeholder={placeholderMessage} leftIcon={icon} />
|
<TextInput {...input} placeholder={placeholderMessage} leftIcon={icon} />
|
||||||
{showError && <ErrorText>{meta && meta.touched && meta.error}</ErrorText>}
|
{showError && <ErrorText>{meta && meta.touched && meta.error}</ErrorText>}
|
||||||
</InputContainer>
|
</InputContainer>
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,8 @@ const ButtonWrapper = styled(AnchorButton)<ButtonStyleProps>`
|
||||||
? props.theme.colors[props.styleName]
|
? props.theme.colors[props.styleName]
|
||||||
: props.theme.colors.secondary};
|
: props.theme.colors.secondary};
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
font-weight: ${props => props.theme.fontWeights[1]};
|
font-weight: ${props => props.theme.fontWeights[2]};
|
||||||
|
font-family: "DM Sans";
|
||||||
outline: none;
|
outline: none;
|
||||||
&&:hover,
|
&&:hover,
|
||||||
&&:focus {
|
&&:focus {
|
||||||
|
|
|
||||||
|
|
@ -40,6 +40,7 @@ const DatasourcesField = (
|
||||||
onCreateOption={props.createDatasource}
|
onCreateOption={props.createDatasource}
|
||||||
format={(value: string) => _.find(options, { value })}
|
format={(value: string) => _.find(options, { value })}
|
||||||
parse={(option: { value: string }) => (option ? option.value : null)}
|
parse={(option: { value: string }) => (option ? option.value : null)}
|
||||||
|
formatCreateLabel={(value: string) => `Create data source "${value}"`}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@ import { ApiPaneReduxState } from "../../reducers/uiReducers/apiPaneReducer";
|
||||||
import { BaseTextInput } from "../../components/designSystems/appsmith/TextInputComponent";
|
import { BaseTextInput } from "../../components/designSystems/appsmith/TextInputComponent";
|
||||||
import { TICK } from "@blueprintjs/icons/lib/esm/generated/iconNames";
|
import { TICK } from "@blueprintjs/icons/lib/esm/generated/iconNames";
|
||||||
import { createActionRequest } from "../../actions/actionActions";
|
import { createActionRequest } from "../../actions/actionActions";
|
||||||
|
import Fuse from "fuse.js";
|
||||||
|
|
||||||
const LoadingContainer = styled.div`
|
const LoadingContainer = styled.div`
|
||||||
height: 50%;
|
height: 50%;
|
||||||
|
|
@ -27,6 +28,22 @@ const ApiSidebarWrapper = styled.div`
|
||||||
width: 100%;
|
width: 100%;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
const SearchBar = styled(BaseTextInput)`
|
||||||
|
margin-bottom: 10px;
|
||||||
|
input {
|
||||||
|
background-color: #23292e;
|
||||||
|
border: none;
|
||||||
|
color: ${props => props.theme.colors.textOnDarkBG}
|
||||||
|
:focus {
|
||||||
|
background-color: #23292e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.bp3-icon {
|
||||||
|
background-color: #23292e;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
const ApiItemsWrapper = styled.div`
|
const ApiItemsWrapper = styled.div`
|
||||||
flex: 1;
|
flex: 1;
|
||||||
margin-bottom: 15px;
|
margin-bottom: 15px;
|
||||||
|
|
@ -49,7 +66,7 @@ const ApiItem = styled.div<{ isSelected: boolean }>`
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const HTTPMethod = styled.span<{ method: string | undefined }>`
|
const HTTPMethod = styled.span<{ method?: string }>`
|
||||||
flex: 1;
|
flex: 1;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
color: ${props => {
|
color: ${props => {
|
||||||
|
|
@ -121,6 +138,15 @@ type Props = ReduxStateProps &
|
||||||
type State = {
|
type State = {
|
||||||
isCreating: boolean;
|
isCreating: boolean;
|
||||||
name: string;
|
name: string;
|
||||||
|
search: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
const fuseOptions = {
|
||||||
|
shouldSort: true,
|
||||||
|
threshold: 0.1,
|
||||||
|
location: 0,
|
||||||
|
minMatchCharLength: 3,
|
||||||
|
keys: ["name"],
|
||||||
};
|
};
|
||||||
|
|
||||||
class ApiSidebar extends React.Component<Props, State> {
|
class ApiSidebar extends React.Component<Props, State> {
|
||||||
|
|
@ -129,6 +155,7 @@ class ApiSidebar extends React.Component<Props, State> {
|
||||||
this.state = {
|
this.state = {
|
||||||
isCreating: false,
|
isCreating: false,
|
||||||
name: "",
|
name: "",
|
||||||
|
search: "",
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -167,10 +194,24 @@ class ApiSidebar extends React.Component<Props, State> {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
handleSearchChange = (e: React.ChangeEvent<{ value: string }>) => {
|
||||||
|
const value = e.target.value;
|
||||||
|
this.setState({
|
||||||
|
search: value,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { actions, apiPane, history, match } = this.props;
|
const {
|
||||||
const { isCreating } = this.state;
|
apiPane,
|
||||||
|
history,
|
||||||
|
match,
|
||||||
|
actions: { data },
|
||||||
|
} = this.props;
|
||||||
|
const { isCreating, search, name } = this.state;
|
||||||
const activeActionId = match.params.id;
|
const activeActionId = match.params.id;
|
||||||
|
const fuse = new Fuse(data, fuseOptions);
|
||||||
|
const actions = search ? fuse.search(search) : data;
|
||||||
return (
|
return (
|
||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
{apiPane.isFetching ? (
|
{apiPane.isFetching ? (
|
||||||
|
|
@ -180,15 +221,27 @@ class ApiSidebar extends React.Component<Props, State> {
|
||||||
) : (
|
) : (
|
||||||
<ApiSidebarWrapper>
|
<ApiSidebarWrapper>
|
||||||
<ApiItemsWrapper>
|
<ApiItemsWrapper>
|
||||||
{actions.data.map(action => (
|
<SearchBar
|
||||||
|
icon="search"
|
||||||
|
input={{
|
||||||
|
value: search,
|
||||||
|
onChange: this.handleSearchChange,
|
||||||
|
}}
|
||||||
|
placeholderMessage="Search"
|
||||||
|
/>
|
||||||
|
{actions.map(action => (
|
||||||
<ApiItem
|
<ApiItem
|
||||||
key={action.id}
|
key={action.id}
|
||||||
onClick={() => history.push(API_EDITOR_ID_URL(action.id))}
|
onClick={() => history.push(API_EDITOR_ID_URL(action.id))}
|
||||||
isSelected={activeActionId === action.id}
|
isSelected={activeActionId === action.id}
|
||||||
>
|
>
|
||||||
<HTTPMethod method={action.actionConfiguration.httpMethod}>
|
{action.actionConfiguration ? (
|
||||||
{action.actionConfiguration.httpMethod}
|
<HTTPMethod method={action.actionConfiguration.httpMethod}>
|
||||||
</HTTPMethod>
|
{action.actionConfiguration.httpMethod}
|
||||||
|
</HTTPMethod>
|
||||||
|
) : (
|
||||||
|
<HTTPMethod />
|
||||||
|
)}
|
||||||
<ActionName>{action.name}</ActionName>
|
<ActionName>{action.name}</ActionName>
|
||||||
</ApiItem>
|
</ApiItem>
|
||||||
))}
|
))}
|
||||||
|
|
@ -198,7 +251,7 @@ class ApiSidebar extends React.Component<Props, State> {
|
||||||
<BaseTextInput
|
<BaseTextInput
|
||||||
placeholderMessage="API name"
|
placeholderMessage="API name"
|
||||||
input={{
|
input={{
|
||||||
value: this.state.name,
|
value: name,
|
||||||
onChange: this.handleNameChange,
|
onChange: this.handleNameChange,
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|
@ -208,6 +261,7 @@ class ApiSidebar extends React.Component<Props, State> {
|
||||||
text=""
|
text=""
|
||||||
onClick={this.saveAction}
|
onClick={this.saveAction}
|
||||||
filled
|
filled
|
||||||
|
loading={apiPane.isSaving}
|
||||||
/>
|
/>
|
||||||
</CreateApiWrapper>
|
</CreateApiWrapper>
|
||||||
) : (
|
) : (
|
||||||
|
|
|
||||||
|
|
@ -5429,6 +5429,11 @@ functional-red-black-tree@^1.0.1:
|
||||||
resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327"
|
resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327"
|
||||||
integrity sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=
|
integrity sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=
|
||||||
|
|
||||||
|
fuse.js@^3.4.5:
|
||||||
|
version "3.4.5"
|
||||||
|
resolved "https://registry.yarnpkg.com/fuse.js/-/fuse.js-3.4.5.tgz#8954fb43f9729bd5dbcb8c08f251db552595a7a6"
|
||||||
|
integrity sha512-s9PGTaQIkT69HaeoTVjwGsLfb8V8ScJLx5XGFcKHg0MqLUH/UZ4EKOtqtXX9k7AFqCGxD1aJmYb8Q5VYDibVRQ==
|
||||||
|
|
||||||
gauge@~2.7.3:
|
gauge@~2.7.3:
|
||||||
version "2.7.4"
|
version "2.7.4"
|
||||||
resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7"
|
resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7"
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user