Merge branch 'master' into 'release'
Backmerge master to release. See merge request theappsmith/internal-tools-client!754
This commit is contained in:
commit
e2a30da1c3
|
|
@ -158,11 +158,6 @@ export const executeApiActionSuccess = (payload: {
|
||||||
payload: payload,
|
payload: payload,
|
||||||
});
|
});
|
||||||
|
|
||||||
export const editApiName = (payload: { id: string; value: string }) => ({
|
|
||||||
type: ReduxActionTypes.EDIT_API_NAME,
|
|
||||||
payload: payload,
|
|
||||||
});
|
|
||||||
|
|
||||||
export const saveApiName = (payload: { id: string; name: string }) => ({
|
export const saveApiName = (payload: { id: string; name: string }) => ({
|
||||||
type: ReduxActionTypes.SAVE_API_NAME,
|
type: ReduxActionTypes.SAVE_API_NAME,
|
||||||
payload: payload,
|
payload: payload,
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,7 @@ import { Colors } from "constants/Colors";
|
||||||
import AnalyticsUtil from "utils/AnalyticsUtil";
|
import AnalyticsUtil from "utils/AnalyticsUtil";
|
||||||
import TernServer from "utils/autocomplete/TernServer";
|
import TernServer from "utils/autocomplete/TernServer";
|
||||||
import KeyboardShortcuts from "constants/KeyboardShortcuts";
|
import KeyboardShortcuts from "constants/KeyboardShortcuts";
|
||||||
|
import { dataTreeTypeDefCreator } from "utils/autocomplete/dataTreeTypeDefCreator";
|
||||||
const LightningMenu = lazy(() =>
|
const LightningMenu = lazy(() =>
|
||||||
import("components/editorComponents/LightningMenu"),
|
import("components/editorComponents/LightningMenu"),
|
||||||
);
|
);
|
||||||
|
|
@ -166,7 +167,7 @@ const EditorWrapper = styled.div<{
|
||||||
position: absolute;
|
position: absolute;
|
||||||
right: 0;
|
right: 0;
|
||||||
left: 0;
|
left: 0;
|
||||||
top: 0;
|
top: 0;
|
||||||
`
|
`
|
||||||
: `z-index: 0; position: relative;`}
|
: `z-index: 0; position: relative;`}
|
||||||
background-color: ${props =>
|
background-color: ${props =>
|
||||||
|
|
@ -180,7 +181,7 @@ const EditorWrapper = styled.div<{
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
text-transform: none;
|
text-transform: none;
|
||||||
min-height: 32px;
|
min-height: 32px;
|
||||||
|
|
||||||
height: auto;
|
height: auto;
|
||||||
${props =>
|
${props =>
|
||||||
props.setMaxHeight &&
|
props.setMaxHeight &&
|
||||||
|
|
@ -459,8 +460,8 @@ class DynamicAutocompleteInput extends Component<Props, State> {
|
||||||
// Update the dynamic bindings for autocomplete
|
// Update the dynamic bindings for autocomplete
|
||||||
if (prevProps.dynamicData !== this.props.dynamicData) {
|
if (prevProps.dynamicData !== this.props.dynamicData) {
|
||||||
if (this.ternServer) {
|
if (this.ternServer) {
|
||||||
// const dataTreeDef = dataTreeTypeDefCreator(this.props.dynamicData);
|
const dataTreeDef = dataTreeTypeDefCreator(this.props.dynamicData);
|
||||||
// this.ternServer.updateDef("dataTree", dataTreeDef);
|
this.ternServer.updateDef("dataTree", dataTreeDef);
|
||||||
} else {
|
} else {
|
||||||
this.editor.setOption("hintOptions", {
|
this.editor.setOption("hintOptions", {
|
||||||
completeSingle: false,
|
completeSingle: false,
|
||||||
|
|
|
||||||
|
|
@ -234,7 +234,6 @@ export const ReduxActionTypes: { [key: string]: string } = {
|
||||||
CHANGE_ORG_USER_ROLE_ERROR: "CHANGE_ORG_USER_ROLE_ERROR",
|
CHANGE_ORG_USER_ROLE_ERROR: "CHANGE_ORG_USER_ROLE_ERROR",
|
||||||
SET_DEFAULT_REFINEMENT: "SET_DEFAULT_REFINEMENT",
|
SET_DEFAULT_REFINEMENT: "SET_DEFAULT_REFINEMENT",
|
||||||
SET_HELP_MODAL_OPEN: "SET_HELP_MODAL_OPEN",
|
SET_HELP_MODAL_OPEN: "SET_HELP_MODAL_OPEN",
|
||||||
EDIT_API_NAME: "EDIT_API_NAME",
|
|
||||||
SAVE_API_NAME: "SAVE_API_NAME",
|
SAVE_API_NAME: "SAVE_API_NAME",
|
||||||
SAVE_API_NAME_SUCCESS: "SAVE_API_NAME_SUCCESS",
|
SAVE_API_NAME_SUCCESS: "SAVE_API_NAME_SUCCESS",
|
||||||
UPDATE_API_NAME_DRAFT: "UPDATE_API_NAME_DRAFT",
|
UPDATE_API_NAME_DRAFT: "UPDATE_API_NAME_DRAFT",
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,6 @@ import CollapsibleHelp from "components/designSystems/appsmith/help/CollapsibleH
|
||||||
import KeyValueFieldArray from "components/editorComponents/form/fields/KeyValueFieldArray";
|
import KeyValueFieldArray from "components/editorComponents/form/fields/KeyValueFieldArray";
|
||||||
import PostBodyData from "./PostBodyData";
|
import PostBodyData from "./PostBodyData";
|
||||||
import ApiResponseView from "components/editorComponents/ApiResponseView";
|
import ApiResponseView from "components/editorComponents/ApiResponseView";
|
||||||
import { ApiNameValidation } from "reducers/uiReducers/apiPaneReducer";
|
|
||||||
import { AppState } from "reducers";
|
import { AppState } from "reducers";
|
||||||
import { getApiName } from "selectors/formSelectors";
|
import { getApiName } from "selectors/formSelectors";
|
||||||
import ActionNameEditor from "components/editorComponents/ActionNameEditor";
|
import ActionNameEditor from "components/editorComponents/ActionNameEditor";
|
||||||
|
|
@ -132,7 +131,6 @@ interface APIFormProps {
|
||||||
dispatch: any;
|
dispatch: any;
|
||||||
datasourceFieldText: string;
|
datasourceFieldText: string;
|
||||||
apiName: string;
|
apiName: string;
|
||||||
apiNameValidation: ApiNameValidation;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type Props = APIFormProps & InjectedFormProps<RestAction, APIFormProps>;
|
type Props = APIFormProps & InjectedFormProps<RestAction, APIFormProps>;
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,6 @@ import { FormIcons } from "icons/FormIcons";
|
||||||
import { BaseTabbedView } from "components/designSystems/appsmith/TabbedView";
|
import { BaseTabbedView } from "components/designSystems/appsmith/TabbedView";
|
||||||
import Pagination from "./Pagination";
|
import Pagination from "./Pagination";
|
||||||
import { PaginationType, RestAction } from "entities/Action";
|
import { PaginationType, RestAction } from "entities/Action";
|
||||||
import { ApiNameValidation } from "reducers/uiReducers/apiPaneReducer";
|
|
||||||
import ActionNameEditor from "components/editorComponents/ActionNameEditor";
|
import ActionNameEditor from "components/editorComponents/ActionNameEditor";
|
||||||
import { NameWrapper } from "./Form";
|
import { NameWrapper } from "./Form";
|
||||||
const Form = styled.form`
|
const Form = styled.form`
|
||||||
|
|
@ -118,7 +117,6 @@ interface APIFormProps {
|
||||||
};
|
};
|
||||||
apiName: string;
|
apiName: string;
|
||||||
apiId: string;
|
apiId: string;
|
||||||
apiNameValidation: ApiNameValidation;
|
|
||||||
dispatch: any;
|
dispatch: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -33,10 +33,6 @@ interface ReduxStateProps {
|
||||||
isDeleting: Record<string, boolean>;
|
isDeleting: Record<string, boolean>;
|
||||||
allowSave: boolean;
|
allowSave: boolean;
|
||||||
apiName: string;
|
apiName: string;
|
||||||
apiNameValidation: {
|
|
||||||
isValid: boolean;
|
|
||||||
validationMessage: string;
|
|
||||||
};
|
|
||||||
currentApplication: UserApplication;
|
currentApplication: UserApplication;
|
||||||
currentPageName: string | undefined;
|
currentPageName: string | undefined;
|
||||||
pages: any;
|
pages: any;
|
||||||
|
|
@ -197,7 +193,6 @@ class ApiEditor extends React.Component<Props> {
|
||||||
: ""
|
: ""
|
||||||
}
|
}
|
||||||
apiName={this.props.apiName}
|
apiName={this.props.apiName}
|
||||||
apiNameValidation={this.props.apiNameValidation}
|
|
||||||
onChange={this.onChangeHandler}
|
onChange={this.onChangeHandler}
|
||||||
location={this.props.location}
|
location={this.props.location}
|
||||||
/>
|
/>
|
||||||
|
|
@ -206,7 +201,6 @@ class ApiEditor extends React.Component<Props> {
|
||||||
{formUiComponent === "RapidApiEditorForm" && (
|
{formUiComponent === "RapidApiEditorForm" && (
|
||||||
<RapidApiEditorForm
|
<RapidApiEditorForm
|
||||||
apiName={this.props.apiName}
|
apiName={this.props.apiName}
|
||||||
apiNameValidation={this.props.apiNameValidation}
|
|
||||||
apiId={this.props.match.params.apiId}
|
apiId={this.props.match.params.apiId}
|
||||||
paginationType={paginationType}
|
paginationType={paginationType}
|
||||||
isRunning={isRunning[apiId]}
|
isRunning={isRunning[apiId]}
|
||||||
|
|
@ -236,27 +230,10 @@ const mapStateToProps = (state: AppState, props: any): ReduxStateProps => {
|
||||||
const formData = getFormValues(API_EDITOR_FORM_NAME)(state) as RestAction;
|
const formData = getFormValues(API_EDITOR_FORM_NAME)(state) as RestAction;
|
||||||
const apiAction = getActionById(state, props);
|
const apiAction = getActionById(state, props);
|
||||||
const apiName = getApiName(state, props.match.params.apiId);
|
const apiName = getApiName(state, props.match.params.apiId);
|
||||||
const apiNameDraft =
|
|
||||||
state.ui.apiPane.apiName.drafts[props.match.params.apiId];
|
|
||||||
let apiNameValidation = {
|
|
||||||
isValid: true,
|
|
||||||
validationMessage: "",
|
|
||||||
};
|
|
||||||
|
|
||||||
if (apiNameDraft && apiNameDraft.validation) {
|
const { isDeleting, isRunning } = state.ui.apiPane;
|
||||||
apiNameValidation = apiNameDraft.validation;
|
const actionDrafts = state.entities.actionDrafts;
|
||||||
}
|
const allowSave = !!(apiAction && apiAction.id in actionDrafts);
|
||||||
|
|
||||||
const { drafts, isDeleting, isRunning } = state.ui.apiPane;
|
|
||||||
let data: RestAction | ActionData | RapidApiAction | undefined;
|
|
||||||
let allowSave;
|
|
||||||
if (apiAction && apiAction.id in drafts) {
|
|
||||||
data = drafts[apiAction.id];
|
|
||||||
allowSave = true;
|
|
||||||
} else {
|
|
||||||
data = apiAction;
|
|
||||||
allowSave = false;
|
|
||||||
}
|
|
||||||
const datasourceFieldText =
|
const datasourceFieldText =
|
||||||
state.ui.apiPane.datasourceFieldText[formData?.id ?? ""] || "";
|
state.ui.apiPane.datasourceFieldText[formData?.id ?? ""] || "";
|
||||||
|
|
||||||
|
|
@ -267,10 +244,9 @@ const mapStateToProps = (state: AppState, props: any): ReduxStateProps => {
|
||||||
currentPageName: getCurrentPageName(state),
|
currentPageName: getCurrentPageName(state),
|
||||||
pages: state.entities.pageList.pages,
|
pages: state.entities.pageList.pages,
|
||||||
apiName: apiName || "",
|
apiName: apiName || "",
|
||||||
apiNameValidation: apiNameValidation,
|
|
||||||
plugins: state.entities.plugins.list,
|
plugins: state.entities.plugins.list,
|
||||||
pluginId: _.get(data, "pluginId"),
|
pluginId: _.get(apiAction, "pluginId"),
|
||||||
paginationType: _.get(data, "actionConfiguration.paginationType"),
|
paginationType: _.get(apiAction, "actionConfiguration.paginationType"),
|
||||||
apiAction,
|
apiAction,
|
||||||
isRunning,
|
isRunning,
|
||||||
isDeleting,
|
isDeleting,
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,7 @@ import { getNextEntityName } from "utils/AppsmithUtils";
|
||||||
import AnalyticsUtil from "utils/AnalyticsUtil";
|
import AnalyticsUtil from "utils/AnalyticsUtil";
|
||||||
import { Page } from "constants/ReduxActionConstants";
|
import { Page } from "constants/ReduxActionConstants";
|
||||||
import { RestAction } from "entities/Action";
|
import { RestAction } from "entities/Action";
|
||||||
|
import { ActionDraftsState } from "reducers/entityReducers/actionDraftsReducer";
|
||||||
|
|
||||||
const HTTPMethod = styled.span<{ method?: string }>`
|
const HTTPMethod = styled.span<{ method?: string }>`
|
||||||
flex: 1;
|
flex: 1;
|
||||||
|
|
@ -63,6 +64,7 @@ const ActionName = styled.span`
|
||||||
|
|
||||||
interface ReduxStateProps {
|
interface ReduxStateProps {
|
||||||
actions: ActionDataState;
|
actions: ActionDataState;
|
||||||
|
actionDrafts: ActionDraftsState;
|
||||||
apiPane: ApiPaneReduxState;
|
apiPane: ApiPaneReduxState;
|
||||||
pages: Page[];
|
pages: Page[];
|
||||||
}
|
}
|
||||||
|
|
@ -92,8 +94,8 @@ class ApiSidebar extends React.Component<Props> {
|
||||||
|
|
||||||
shouldComponentUpdate(nextProps: Readonly<Props>): boolean {
|
shouldComponentUpdate(nextProps: Readonly<Props>): boolean {
|
||||||
if (
|
if (
|
||||||
Object.keys(nextProps.apiPane.drafts) !==
|
Object.keys(nextProps.actionDrafts) !==
|
||||||
Object.keys(this.props.apiPane.drafts)
|
Object.keys(this.props.actionDrafts)
|
||||||
) {
|
) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
@ -195,7 +197,8 @@ class ApiSidebar extends React.Component<Props> {
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const {
|
const {
|
||||||
apiPane: { isFetching, drafts },
|
actionDrafts,
|
||||||
|
apiPane: { isFetching },
|
||||||
match: {
|
match: {
|
||||||
params: { apiId },
|
params: { apiId },
|
||||||
},
|
},
|
||||||
|
|
@ -207,7 +210,7 @@ class ApiSidebar extends React.Component<Props> {
|
||||||
isLoading={isFetching}
|
isLoading={isFetching}
|
||||||
list={data}
|
list={data}
|
||||||
selectedItemId={apiId}
|
selectedItemId={apiId}
|
||||||
draftIds={Object.keys(drafts)}
|
draftIds={Object.keys(actionDrafts)}
|
||||||
itemRender={this.renderItem}
|
itemRender={this.renderItem}
|
||||||
onItemCreateClick={this.handleCreateNewApiClick}
|
onItemCreateClick={this.handleCreateNewApiClick}
|
||||||
onItemSelected={this.handleApiChange}
|
onItemSelected={this.handleApiChange}
|
||||||
|
|
@ -222,6 +225,7 @@ class ApiSidebar extends React.Component<Props> {
|
||||||
|
|
||||||
const mapStateToProps = (state: AppState): ReduxStateProps => ({
|
const mapStateToProps = (state: AppState): ReduxStateProps => ({
|
||||||
actions: state.entities.actions,
|
actions: state.entities.actions,
|
||||||
|
actionDrafts: state.entities.actionDrafts,
|
||||||
apiPane: state.ui.apiPane,
|
apiPane: state.ui.apiPane,
|
||||||
pages: state.entities.pageList.pages,
|
pages: state.entities.pageList.pages,
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,7 @@ import { getCurrentApplication } from "selectors/applicationSelectors";
|
||||||
import { ApiPaneReduxState } from "reducers/uiReducers/apiPaneReducer";
|
import { ApiPaneReduxState } from "reducers/uiReducers/apiPaneReducer";
|
||||||
import { QueryAction, RestAction } from "entities/Action";
|
import { QueryAction, RestAction } from "entities/Action";
|
||||||
import { getPluginImage } from "pages/Editor/QueryEditor/helpers";
|
import { getPluginImage } from "pages/Editor/QueryEditor/helpers";
|
||||||
|
import { ActionDraftsState } from "reducers/entityReducers/actionDraftsReducer";
|
||||||
|
|
||||||
const EmptyStateContainer = styled.div`
|
const EmptyStateContainer = styled.div`
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|
@ -46,7 +47,7 @@ type QueryPageProps = {
|
||||||
queryPane: QueryPaneReduxState;
|
queryPane: QueryPaneReduxState;
|
||||||
formData: RestAction;
|
formData: RestAction;
|
||||||
isCreating: boolean;
|
isCreating: boolean;
|
||||||
apiPane: ApiPaneReduxState;
|
actionDrafts: ActionDraftsState;
|
||||||
initialValues: RestAction;
|
initialValues: RestAction;
|
||||||
pluginIds: Array<string> | undefined;
|
pluginIds: Array<string> | undefined;
|
||||||
submitForm: (name: string) => void;
|
submitForm: (name: string) => void;
|
||||||
|
|
@ -97,7 +98,7 @@ class QueryEditor extends React.Component<Props> {
|
||||||
pluginIds,
|
pluginIds,
|
||||||
executedQueryData,
|
executedQueryData,
|
||||||
selectedPluginPackage,
|
selectedPluginPackage,
|
||||||
apiPane,
|
actionDrafts,
|
||||||
isCreating,
|
isCreating,
|
||||||
runErrorMessage,
|
runErrorMessage,
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
@ -108,7 +109,6 @@ class QueryEditor extends React.Component<Props> {
|
||||||
<EmptyStateContainer>{"Plugin is not installed"}</EmptyStateContainer>
|
<EmptyStateContainer>{"Plugin is not installed"}</EmptyStateContainer>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
const { drafts } = apiPane;
|
|
||||||
const { isSaving, isRunning, isDeleting } = queryPane;
|
const { isSaving, isRunning, isDeleting } = queryPane;
|
||||||
|
|
||||||
const validDataSources: Array<Datasource> = [];
|
const validDataSources: Array<Datasource> = [];
|
||||||
|
|
@ -132,7 +132,7 @@ class QueryEditor extends React.Component<Props> {
|
||||||
location={this.props.location}
|
location={this.props.location}
|
||||||
applicationId={applicationId}
|
applicationId={applicationId}
|
||||||
pageId={pageId}
|
pageId={pageId}
|
||||||
allowSave={queryId in drafts}
|
allowSave={queryId in actionDrafts}
|
||||||
isSaving={isSaving[queryId]}
|
isSaving={isSaving[queryId]}
|
||||||
isRunning={isRunning[queryId]}
|
isRunning={isRunning[queryId]}
|
||||||
isDeleting={isDeleting[queryId]}
|
isDeleting={isDeleting[queryId]}
|
||||||
|
|
@ -177,7 +177,7 @@ const mapStateToProps = (state: AppState): any => {
|
||||||
return {
|
return {
|
||||||
plugins: getPlugins(state),
|
plugins: getPlugins(state),
|
||||||
runErrorMessage,
|
runErrorMessage,
|
||||||
apiPane: state.ui.apiPane,
|
actionDrafts: state.entities.actionDrafts,
|
||||||
pluginIds: getPluginIdsOfPackageNames(state, PLUGIN_PACKAGE_DBS),
|
pluginIds: getPluginIdsOfPackageNames(state, PLUGIN_PACKAGE_DBS),
|
||||||
dataSources: getDataSources(state),
|
dataSources: getDataSources(state),
|
||||||
executedQueryData: state.ui.queryPane.runQuerySuccessData,
|
executedQueryData: state.ui.queryPane.runQuerySuccessData,
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,7 @@ import { getDataSources } from "selectors/editorSelectors";
|
||||||
import { QUERY_EDITOR_URL_WITH_SELECTED_PAGE_ID } from "constants/routes";
|
import { QUERY_EDITOR_URL_WITH_SELECTED_PAGE_ID } from "constants/routes";
|
||||||
import { RestAction } from "entities/Action";
|
import { RestAction } from "entities/Action";
|
||||||
import { Colors } from "constants/Colors";
|
import { Colors } from "constants/Colors";
|
||||||
|
import { ActionDraftsState } from "reducers/entityReducers/actionDraftsReducer";
|
||||||
|
|
||||||
const ActionItem = styled.div`
|
const ActionItem = styled.div`
|
||||||
flex: 1;
|
flex: 1;
|
||||||
|
|
@ -59,6 +60,7 @@ interface ReduxStateProps {
|
||||||
plugins: Plugin[];
|
plugins: Plugin[];
|
||||||
queries: ActionDataState;
|
queries: ActionDataState;
|
||||||
apiPane: ApiPaneReduxState;
|
apiPane: ApiPaneReduxState;
|
||||||
|
actionDrafts: ActionDraftsState;
|
||||||
actions: ActionDataState;
|
actions: ActionDataState;
|
||||||
dataSources: Datasource[];
|
dataSources: Datasource[];
|
||||||
}
|
}
|
||||||
|
|
@ -88,8 +90,8 @@ class QuerySidebar extends React.Component<Props> {
|
||||||
|
|
||||||
shouldComponentUpdate(nextProps: Readonly<Props>): boolean {
|
shouldComponentUpdate(nextProps: Readonly<Props>): boolean {
|
||||||
if (
|
if (
|
||||||
Object.keys(nextProps.apiPane.drafts) !==
|
Object.keys(nextProps.actionDrafts) !==
|
||||||
Object.keys(this.props.apiPane.drafts)
|
Object.keys(this.props.actionDrafts)
|
||||||
) {
|
) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
@ -180,29 +182,21 @@ class QuerySidebar extends React.Component<Props> {
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const {
|
const {
|
||||||
apiPane: { drafts },
|
actionDrafts,
|
||||||
apiPane: { isFetching },
|
apiPane: { isFetching },
|
||||||
match: {
|
match: {
|
||||||
params: { queryId },
|
params: { queryId },
|
||||||
},
|
},
|
||||||
queries,
|
queries,
|
||||||
dataSources,
|
|
||||||
} = this.props;
|
} = this.props;
|
||||||
const data = queries.map(a => a.config);
|
const data = queries.map(a => a.config);
|
||||||
|
|
||||||
const validDataSources: Array<Datasource> = [];
|
|
||||||
dataSources.forEach(dataSource => {
|
|
||||||
if (dataSource.isValid) {
|
|
||||||
validDataSources.push(dataSource);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<EditorSidebar
|
<EditorSidebar
|
||||||
isLoading={isFetching}
|
isLoading={isFetching}
|
||||||
list={data}
|
list={data}
|
||||||
selectedItemId={queryId}
|
selectedItemId={queryId}
|
||||||
draftIds={Object.keys(drafts)}
|
draftIds={Object.keys(actionDrafts)}
|
||||||
itemRender={this.renderItem}
|
itemRender={this.renderItem}
|
||||||
onItemCreateClick={this.handleCreateNewQueryClick}
|
onItemCreateClick={this.handleCreateNewQueryClick}
|
||||||
onItemSelected={this.handleQueryChange}
|
onItemSelected={this.handleQueryChange}
|
||||||
|
|
@ -218,6 +212,7 @@ class QuerySidebar extends React.Component<Props> {
|
||||||
const mapStateToProps = (state: AppState): ReduxStateProps => ({
|
const mapStateToProps = (state: AppState): ReduxStateProps => ({
|
||||||
plugins: getPlugins(state),
|
plugins: getPlugins(state),
|
||||||
queries: getQueryActions(state),
|
queries: getQueryActions(state),
|
||||||
|
actionDrafts: state.entities.actionDrafts,
|
||||||
apiPane: state.ui.apiPane,
|
apiPane: state.ui.apiPane,
|
||||||
actions: state.entities.actions,
|
actions: state.entities.actions,
|
||||||
dataSources: getDataSources(state),
|
dataSources: getDataSources(state),
|
||||||
|
|
|
||||||
|
|
@ -4,13 +4,11 @@ import {
|
||||||
ReduxActionErrorTypes,
|
ReduxActionErrorTypes,
|
||||||
ReduxAction,
|
ReduxAction,
|
||||||
} from "constants/ReduxActionConstants";
|
} from "constants/ReduxActionConstants";
|
||||||
import _ from "lodash";
|
|
||||||
import { RestAction } from "entities/Action";
|
import { RestAction } from "entities/Action";
|
||||||
|
|
||||||
const initialState: ApiPaneReduxState = {
|
const initialState: ApiPaneReduxState = {
|
||||||
lastUsed: "",
|
lastUsed: "",
|
||||||
isFetching: false,
|
isFetching: false,
|
||||||
drafts: {},
|
|
||||||
isRunning: {},
|
isRunning: {},
|
||||||
isSaving: {},
|
isSaving: {},
|
||||||
isDeleting: {},
|
isDeleting: {},
|
||||||
|
|
@ -19,19 +17,11 @@ const initialState: ApiPaneReduxState = {
|
||||||
lastSelectedPage: "",
|
lastSelectedPage: "",
|
||||||
extraformData: {},
|
extraformData: {},
|
||||||
datasourceFieldText: {},
|
datasourceFieldText: {},
|
||||||
apiName: {
|
|
||||||
drafts: {},
|
|
||||||
isSaving: {},
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
export interface ApiNameValidation {
|
|
||||||
isValid: boolean;
|
|
||||||
validationMessage: string;
|
|
||||||
}
|
|
||||||
export interface ApiPaneReduxState {
|
export interface ApiPaneReduxState {
|
||||||
lastUsed: string;
|
lastUsed: string;
|
||||||
isFetching: boolean;
|
isFetching: boolean;
|
||||||
drafts: Record<string, RestAction>;
|
|
||||||
isRunning: Record<string, boolean>;
|
isRunning: Record<string, boolean>;
|
||||||
isSaving: Record<string, boolean>;
|
isSaving: Record<string, boolean>;
|
||||||
isDeleting: Record<string, boolean>;
|
isDeleting: Record<string, boolean>;
|
||||||
|
|
@ -40,16 +30,6 @@ export interface ApiPaneReduxState {
|
||||||
datasourceFieldText: Record<string, string>;
|
datasourceFieldText: Record<string, string>;
|
||||||
lastSelectedPage: string;
|
lastSelectedPage: string;
|
||||||
extraformData: Record<string, any>;
|
extraformData: Record<string, any>;
|
||||||
apiName: {
|
|
||||||
drafts: Record<
|
|
||||||
string,
|
|
||||||
{
|
|
||||||
value: string;
|
|
||||||
validation: ApiNameValidation;
|
|
||||||
}
|
|
||||||
>;
|
|
||||||
isSaving: Record<string, boolean>;
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const apiPaneReducer = createReducer(initialState, {
|
const apiPaneReducer = createReducer(initialState, {
|
||||||
|
|
@ -158,23 +138,6 @@ const apiPaneReducer = createReducer(initialState, {
|
||||||
[action.payload.id]: false,
|
[action.payload.id]: false,
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
[ReduxActionTypes.UPDATE_API_DRAFT]: (
|
|
||||||
state: ApiPaneReduxState,
|
|
||||||
action: ReduxAction<{ id: string; draft: Partial<RestAction> }>,
|
|
||||||
) => ({
|
|
||||||
...state,
|
|
||||||
drafts: {
|
|
||||||
...state.drafts,
|
|
||||||
[action.payload.id]: action.payload.draft,
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
[ReduxActionTypes.DELETE_API_DRAFT]: (
|
|
||||||
state: ApiPaneReduxState,
|
|
||||||
action: ReduxAction<{ id: string }>,
|
|
||||||
) => ({
|
|
||||||
...state,
|
|
||||||
drafts: _.omit(state.drafts, action.payload.id),
|
|
||||||
}),
|
|
||||||
[ReduxActionTypes.API_PANE_CHANGE_API]: (
|
[ReduxActionTypes.API_PANE_CHANGE_API]: (
|
||||||
state: ApiPaneReduxState,
|
state: ApiPaneReduxState,
|
||||||
action: ReduxAction<{ id: string }>,
|
action: ReduxAction<{ id: string }>,
|
||||||
|
|
@ -233,35 +196,6 @@ const apiPaneReducer = createReducer(initialState, {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
[ReduxActionTypes.UPDATE_API_NAME_DRAFT]: (
|
|
||||||
state: ApiPaneReduxState,
|
|
||||||
action: ReduxAction<{
|
|
||||||
id: string;
|
|
||||||
draft?: {
|
|
||||||
value: string;
|
|
||||||
validation: {
|
|
||||||
isValid: boolean;
|
|
||||||
validationMessage: string;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}>,
|
|
||||||
) => {
|
|
||||||
const { id, draft } = action.payload;
|
|
||||||
let nameDrafts = {
|
|
||||||
...state.apiName.drafts,
|
|
||||||
[id]: draft,
|
|
||||||
};
|
|
||||||
if (!draft) {
|
|
||||||
nameDrafts = _.omit(nameDrafts, id);
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
...state,
|
|
||||||
apiName: {
|
|
||||||
drafts: nameDrafts,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
export default apiPaneReducer;
|
export default apiPaneReducer;
|
||||||
|
|
|
||||||
|
|
@ -754,30 +754,6 @@ function* copyActionSaga(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function* editApiNameSaga(action: ReduxAction<{ id: string; value: string }>) {
|
|
||||||
const actionNames = yield select(state =>
|
|
||||||
state.entities.actions.map((action: ActionData) => action.config.name),
|
|
||||||
);
|
|
||||||
const draftActionNames = yield select(state =>
|
|
||||||
Object.values(state.ui.apiPane.apiName.drafts),
|
|
||||||
);
|
|
||||||
//TODO: If an api is in saving state, then it should not use that name as well.
|
|
||||||
const validation = validateEntityName(action.payload.value, [
|
|
||||||
...actionNames,
|
|
||||||
...draftActionNames,
|
|
||||||
]);
|
|
||||||
|
|
||||||
yield put(
|
|
||||||
updateApiNameDraft({
|
|
||||||
id: action.payload.id,
|
|
||||||
draft: {
|
|
||||||
value: action.payload.value,
|
|
||||||
validation: validation,
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function* refactorActionName(
|
export function* refactorActionName(
|
||||||
id: string,
|
id: string,
|
||||||
pageId: string,
|
pageId: string,
|
||||||
|
|
@ -822,14 +798,13 @@ export function* refactorActionName(
|
||||||
|
|
||||||
function* saveApiNameSaga(action: ReduxAction<{ id: string; name: string }>) {
|
function* saveApiNameSaga(action: ReduxAction<{ id: string; name: string }>) {
|
||||||
// Takes from drafts, checks if the name isValid, saves
|
// Takes from drafts, checks if the name isValid, saves
|
||||||
|
const apiId = action.payload.id;
|
||||||
|
const api = yield select(state =>
|
||||||
|
state.entities.actions.find(
|
||||||
|
(action: ActionData) => action.config.id === apiId,
|
||||||
|
),
|
||||||
|
);
|
||||||
try {
|
try {
|
||||||
const apiId = action.payload.id;
|
|
||||||
const api = yield select(state =>
|
|
||||||
state.entities.actions.find(
|
|
||||||
(action: ActionData) => action.config.id === apiId,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
yield refactorActionName(
|
yield refactorActionName(
|
||||||
api.config.id,
|
api.config.id,
|
||||||
api.config.pageId,
|
api.config.pageId,
|
||||||
|
|
@ -841,6 +816,7 @@ function* saveApiNameSaga(action: ReduxAction<{ id: string; name: string }>) {
|
||||||
type: ReduxActionErrorTypes.SAVE_API_NAME_ERROR,
|
type: ReduxActionErrorTypes.SAVE_API_NAME_ERROR,
|
||||||
payload: {
|
payload: {
|
||||||
actionId: action.payload.id,
|
actionId: action.payload.id,
|
||||||
|
oldName: api.config.name,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
AppToaster.show({
|
AppToaster.show({
|
||||||
|
|
@ -859,7 +835,6 @@ export function* watchActionSagas() {
|
||||||
takeEvery(ReduxActionTypes.CREATE_ACTION_INIT, createActionSaga),
|
takeEvery(ReduxActionTypes.CREATE_ACTION_INIT, createActionSaga),
|
||||||
takeLatest(ReduxActionTypes.UPDATE_ACTION_INIT, updateActionSaga),
|
takeLatest(ReduxActionTypes.UPDATE_ACTION_INIT, updateActionSaga),
|
||||||
takeLatest(ReduxActionTypes.DELETE_ACTION_INIT, deleteActionSaga),
|
takeLatest(ReduxActionTypes.DELETE_ACTION_INIT, deleteActionSaga),
|
||||||
takeLatest(ReduxActionTypes.EDIT_API_NAME, editApiNameSaga),
|
|
||||||
takeLatest(ReduxActionTypes.SAVE_API_NAME, saveApiNameSaga),
|
takeLatest(ReduxActionTypes.SAVE_API_NAME, saveApiNameSaga),
|
||||||
takeLatest(
|
takeLatest(
|
||||||
ReduxActionTypes.EXECUTE_PAGE_LOAD_ACTIONS,
|
ReduxActionTypes.EXECUTE_PAGE_LOAD_ACTIONS,
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@ import {
|
||||||
import { getFormSyncErrors } from "redux-form";
|
import { getFormSyncErrors } from "redux-form";
|
||||||
import {
|
import {
|
||||||
ReduxAction,
|
ReduxAction,
|
||||||
|
ReduxActionErrorTypes,
|
||||||
ReduxActionTypes,
|
ReduxActionTypes,
|
||||||
ReduxActionWithMeta,
|
ReduxActionWithMeta,
|
||||||
ReduxFormActionTypes,
|
ReduxFormActionTypes,
|
||||||
|
|
@ -66,7 +67,7 @@ import { isDynamicValue } from "utils/DynamicBindingUtils";
|
||||||
import { getCurrentOrgId } from "selectors/organizationSelectors";
|
import { getCurrentOrgId } from "selectors/organizationSelectors";
|
||||||
|
|
||||||
const getApiDraft = (state: AppState, id: string) => {
|
const getApiDraft = (state: AppState, id: string) => {
|
||||||
const drafts = state.ui.apiPane.drafts;
|
const drafts = state.entities.actionDrafts;
|
||||||
if (id in drafts) return drafts[id];
|
if (id in drafts) return drafts[id];
|
||||||
return {};
|
return {};
|
||||||
};
|
};
|
||||||
|
|
@ -231,7 +232,7 @@ function* changeApiSaga(actionPayload: ReduxAction<{ id: string }>) {
|
||||||
data = draft;
|
data = draft;
|
||||||
}
|
}
|
||||||
|
|
||||||
yield put(initialize(API_EDITOR_FORM_NAME, _.omit(data, "name")));
|
yield put(initialize(API_EDITOR_FORM_NAME, data));
|
||||||
history.push(API_EDITOR_ID_URL(applicationId, pageId, id));
|
history.push(API_EDITOR_ID_URL(applicationId, pageId, id));
|
||||||
|
|
||||||
yield call(initializeExtraFormDataSaga);
|
yield call(initializeExtraFormDataSaga);
|
||||||
|
|
@ -249,6 +250,8 @@ function* changeApiSaga(actionPayload: ReduxAction<{ id: string }>) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function* updateDraftsSaga() {
|
function* updateDraftsSaga() {
|
||||||
|
// debounce
|
||||||
|
// TODO check for save
|
||||||
const result = yield race({
|
const result = yield race({
|
||||||
change: take(ReduxFormActionTypes.VALUE_CHANGE),
|
change: take(ReduxFormActionTypes.VALUE_CHANGE),
|
||||||
timeout: delay(300),
|
timeout: delay(300),
|
||||||
|
|
@ -543,6 +546,16 @@ function* handleCreateNewQueryActionSaga(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function* handleApiNameChangeSaga(action: ReduxAction<{ name: string }>) {
|
||||||
|
yield put(change(API_EDITOR_FORM_NAME, "name", action.payload.name));
|
||||||
|
}
|
||||||
|
|
||||||
|
function* handleApiNameChangeFailureSaga(
|
||||||
|
action: ReduxAction<{ oldName: string }>,
|
||||||
|
) {
|
||||||
|
yield put(change(API_EDITOR_FORM_NAME, "name", action.payload.oldName));
|
||||||
|
}
|
||||||
|
|
||||||
export default function* root() {
|
export default function* root() {
|
||||||
yield all([
|
yield all([
|
||||||
takeEvery(ReduxActionTypes.INIT_API_PANE, initApiPaneSaga),
|
takeEvery(ReduxActionTypes.INIT_API_PANE, initApiPaneSaga),
|
||||||
|
|
@ -552,6 +565,11 @@ export default function* root() {
|
||||||
takeEvery(ReduxActionTypes.DELETE_ACTION_SUCCESS, handleActionDeletedSaga),
|
takeEvery(ReduxActionTypes.DELETE_ACTION_SUCCESS, handleActionDeletedSaga),
|
||||||
takeEvery(ReduxActionTypes.MOVE_ACTION_SUCCESS, handleMoveOrCopySaga),
|
takeEvery(ReduxActionTypes.MOVE_ACTION_SUCCESS, handleMoveOrCopySaga),
|
||||||
takeEvery(ReduxActionTypes.COPY_ACTION_SUCCESS, handleMoveOrCopySaga),
|
takeEvery(ReduxActionTypes.COPY_ACTION_SUCCESS, handleMoveOrCopySaga),
|
||||||
|
takeEvery(ReduxActionTypes.SAVE_API_NAME, handleApiNameChangeSaga),
|
||||||
|
takeEvery(
|
||||||
|
ReduxActionErrorTypes.SAVE_API_NAME_ERROR,
|
||||||
|
handleApiNameChangeFailureSaga,
|
||||||
|
),
|
||||||
takeEvery(
|
takeEvery(
|
||||||
ReduxActionTypes.CREATE_NEW_API_ACTION,
|
ReduxActionTypes.CREATE_NEW_API_ACTION,
|
||||||
handleCreateNewApiActionSaga,
|
handleCreateNewApiActionSaga,
|
||||||
|
|
|
||||||
|
|
@ -48,7 +48,7 @@ import { getQueryName } from "selectors/entitiesSelector";
|
||||||
import { RestAction } from "entities/Action";
|
import { RestAction } from "entities/Action";
|
||||||
|
|
||||||
const getQueryDraft = (state: AppState, id: string) => {
|
const getQueryDraft = (state: AppState, id: string) => {
|
||||||
const drafts = state.ui.apiPane.drafts;
|
const drafts = state.entities.actionDrafts;
|
||||||
if (id in drafts) return drafts[id];
|
if (id in drafts) return drafts[id];
|
||||||
return {};
|
return {};
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -11,21 +11,14 @@ type GetFormData = (
|
||||||
export const getFormData: GetFormData = (state, formName) => {
|
export const getFormData: GetFormData = (state, formName) => {
|
||||||
const initialValues = getFormInitialValues(formName)(state) as RestAction;
|
const initialValues = getFormInitialValues(formName)(state) as RestAction;
|
||||||
const values = getFormValues(formName)(state) as RestAction;
|
const values = getFormValues(formName)(state) as RestAction;
|
||||||
const drafts = state.ui.apiPane.drafts;
|
const drafts = state.entities.actionDrafts;
|
||||||
const dirty = values.id in drafts;
|
const dirty = values.id in drafts;
|
||||||
const valid = isValid(formName)(state);
|
const valid = isValid(formName)(state);
|
||||||
return { initialValues, values, dirty, valid };
|
return { initialValues, values, dirty, valid };
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getApiName = (state: AppState, id: string) => {
|
export const getApiName = (state: AppState, id: string) => {
|
||||||
const apiNameDraft = state.ui.apiPane.apiName.drafts[id]?.value;
|
return state.entities.actions.find(
|
||||||
|
(action: ActionData) => action.config.id === id,
|
||||||
if (apiNameDraft === undefined) {
|
)?.config.name;
|
||||||
return state.entities.actions.find(
|
|
||||||
(action: ActionData) => action.config.id === id,
|
|
||||||
)?.config.name;
|
|
||||||
} else {
|
|
||||||
// If there is something in drafts, return draft value.
|
|
||||||
return apiNameDraft;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,8 @@ import {
|
||||||
import * as log from "loglevel";
|
import * as log from "loglevel";
|
||||||
import equal from "fast-deep-equal/es6";
|
import equal from "fast-deep-equal/es6";
|
||||||
import WidgetFactory from "utils/WidgetFactory";
|
import WidgetFactory from "utils/WidgetFactory";
|
||||||
|
import { AppToaster } from "components/editorComponents/ToastComponent";
|
||||||
|
import { ToastType } from "react-toastify";
|
||||||
|
|
||||||
export const removeBindingsFromObject = (obj: object) => {
|
export const removeBindingsFromObject = (obj: object) => {
|
||||||
const string = JSON.stringify(obj);
|
const string = JSON.stringify(obj);
|
||||||
|
|
@ -382,6 +384,10 @@ export const createDependencyTree = (
|
||||||
return { sortedDependencies, dependencyMap, dependencyTree };
|
return { sortedDependencies, dependencyMap, dependencyTree };
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e);
|
console.error(e);
|
||||||
|
AppToaster.show({
|
||||||
|
message: e.message,
|
||||||
|
type: ToastType.ERROR,
|
||||||
|
});
|
||||||
return { sortedDependencies: [], dependencyMap: {}, dependencyTree: [] };
|
return { sortedDependencies: [], dependencyMap: {}, dependencyTree: [] };
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -387,7 +387,7 @@ export const VALIDATORS: Record<ValidationType, Validator> = {
|
||||||
return { isValid, parsed };
|
return { isValid, parsed };
|
||||||
},
|
},
|
||||||
[VALIDATION_TYPES.DATE]: (
|
[VALIDATION_TYPES.DATE]: (
|
||||||
value: any,
|
value: string,
|
||||||
props: WidgetProps,
|
props: WidgetProps,
|
||||||
dataTree?: DataTree,
|
dataTree?: DataTree,
|
||||||
): ValidationResponse => {
|
): ValidationResponse => {
|
||||||
|
|
@ -401,15 +401,14 @@ export const VALIDATORS: Record<ValidationType, Validator> = {
|
||||||
return {
|
return {
|
||||||
isValid: false,
|
isValid: false,
|
||||||
parsed: "",
|
parsed: "",
|
||||||
message: `${WIDGET_TYPE_VALIDATION_ERROR}: Date`,
|
message:
|
||||||
|
`${WIDGET_TYPE_VALIDATION_ERROR}: Date ` + props.dateFormat
|
||||||
|
? props.dateFormat
|
||||||
|
: "",
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
const isValid = moment(value).isValid();
|
const isValid = moment(value, props.dateFormat).isValid();
|
||||||
const parsed = isValid
|
const parsed = isValid ? value : today;
|
||||||
? props.dateFormat
|
|
||||||
? moment(value).format(props.dateFormat)
|
|
||||||
: moment(value).toISOString(true)
|
|
||||||
: today;
|
|
||||||
return {
|
return {
|
||||||
isValid,
|
isValid,
|
||||||
parsed,
|
parsed,
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
/* eslint-disable @typescript-eslint/ban-ts-ignore */
|
/* eslint-disable @typescript-eslint/ban-ts-ignore */
|
||||||
// Heavily inspired from https://github.com/codemirror/CodeMirror/blob/master/addon/tern/tern.js
|
// Heavily inspired from https://github.com/codemirror/CodeMirror/blob/master/addon/tern/tern.js
|
||||||
import { DataTree } from "entities/DataTree/dataTreeFactory";
|
import { DataTree } from "entities/DataTree/dataTreeFactory";
|
||||||
import tern, { Server } from "tern";
|
import tern, { Server, Def } from "tern";
|
||||||
import ecma from "tern/defs/ecmascript.json";
|
import ecma from "tern/defs/ecmascript.json";
|
||||||
import lodash from "constants/defs/lodash.json";
|
import lodash from "constants/defs/lodash.json";
|
||||||
import { dataTreeTypeDefCreator } from "utils/autocomplete/dataTreeTypeDefCreator";
|
import { dataTreeTypeDefCreator } from "utils/autocomplete/dataTreeTypeDefCreator";
|
||||||
|
|
@ -64,6 +64,12 @@ class TernServer {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
updateDef(name: string, def: Def) {
|
||||||
|
this.server.deleteDefs(name);
|
||||||
|
// @ts-ignore
|
||||||
|
this.server.addDefs(def, true);
|
||||||
|
}
|
||||||
|
|
||||||
getHint(cm: CodeMirror.Editor) {
|
getHint(cm: CodeMirror.Editor) {
|
||||||
return new Promise(resolve => {
|
return new Promise(resolve => {
|
||||||
this.request(
|
this.request(
|
||||||
|
|
|
||||||
|
|
@ -100,13 +100,17 @@ class DropdownWidget extends BaseWidget<DropdownWidgetProps, WidgetState> {
|
||||||
const selectedIndex = _.findIndex(this.props.options, {
|
const selectedIndex = _.findIndex(this.props.options, {
|
||||||
value: this.props.selectedOptionValue,
|
value: this.props.selectedOptionValue,
|
||||||
});
|
});
|
||||||
const computedSelectedIndexArr = this.props.selectedOptionValueArr
|
const computedSelectedIndexArr = Array.isArray(
|
||||||
.map((opt: string) =>
|
this.props.selectedOptionValueArr,
|
||||||
_.findIndex(this.props.options, {
|
)
|
||||||
value: opt,
|
? this.props.selectedOptionValueArr
|
||||||
}),
|
.map((opt: string) =>
|
||||||
)
|
_.findIndex(this.props.options, {
|
||||||
.filter((i: number) => i > -1);
|
value: opt,
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
.filter((i: number) => i > -1)
|
||||||
|
: [];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DropDownComponent
|
<DropDownComponent
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user