Feature: New create app flow (#1375)
* EditableTextWrapper component implemented * create new app flow implemented * test cases for new create new app flow fixed * role update element fixed * before-all hooks fixed * createOrg test cases fixed * loading state test added * editableText input unique identifier added in test-cases * updateApplication API alias name corrected * removed the second className prop on same component * PR feedback implemented
This commit is contained in:
parent
5c26ef5d07
commit
7d6a70d3ce
|
|
@ -29,7 +29,9 @@ describe("Create new org and share with a user", function() {
|
||||||
cy.wait(2000);
|
cy.wait(2000);
|
||||||
cy.get(homePage.appsContainer).contains(orgid);
|
cy.get(homePage.appsContainer).contains(orgid);
|
||||||
cy.xpath(homePage.ShareBtn).should("not.exist");
|
cy.xpath(homePage.ShareBtn).should("not.exist");
|
||||||
cy.get(homePage.applicationCard).trigger("mouseover");
|
cy.get(homePage.applicationCard)
|
||||||
|
.first()
|
||||||
|
.trigger("mouseover");
|
||||||
cy.get(homePage.appEditIcon).should("not.exist");
|
cy.get(homePage.appEditIcon).should("not.exist");
|
||||||
cy.launchApp(appid);
|
cy.launchApp(appid);
|
||||||
cy.LogOut();
|
cy.LogOut();
|
||||||
|
|
@ -62,7 +64,9 @@ describe("Create new org and share with a user", function() {
|
||||||
cy.xpath(homePage.ShareBtn)
|
cy.xpath(homePage.ShareBtn)
|
||||||
.first()
|
.first()
|
||||||
.should("be.visible");
|
.should("be.visible");
|
||||||
cy.get(homePage.applicationCard).trigger("mouseover");
|
cy.get(homePage.applicationCard)
|
||||||
|
.first()
|
||||||
|
.trigger("mouseover");
|
||||||
cy.get(homePage.appEditIcon)
|
cy.get(homePage.appEditIcon)
|
||||||
.first()
|
.first()
|
||||||
.click({ force: true });
|
.click({ force: true });
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@
|
||||||
"createBlankApiCard": ".t--createBlankApiCard",
|
"createBlankApiCard": ".t--createBlankApiCard",
|
||||||
"eachProviderCard": ".t--eachProviderCard",
|
"eachProviderCard": ".t--eachProviderCard",
|
||||||
"nameOfApi": ".t--nameOfApi",
|
"nameOfApi": ".t--nameOfApi",
|
||||||
"ApiNameField": ".bp3-editable-text",
|
"ApiNameField": ".t--action-name-edit-field",
|
||||||
"addToPageBtn": ".t--addToPageBtn",
|
"addToPageBtn": ".t--addToPageBtn",
|
||||||
"ApiDeleteBtn": ".t--apiFormDeleteBtn",
|
"ApiDeleteBtn": ".t--apiFormDeleteBtn",
|
||||||
"ApiRunBtn": ".t--apiFormRunBtn",
|
"ApiRunBtn": ".t--apiFormRunBtn",
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@
|
||||||
"viewWidgets": ".t--page-sidebar-ViewWidgets",
|
"viewWidgets": ".t--page-sidebar-ViewWidgets",
|
||||||
"widgetsEditor": ".t--nav-link-widgets-editor",
|
"widgetsEditor": ".t--nav-link-widgets-editor",
|
||||||
"AddPage": ".pages .t--entity-add-btn",
|
"AddPage": ".pages .t--entity-add-btn",
|
||||||
"editInput": "input.bp3-editable-text-input",
|
"editInput": ".t--entity-name.editing",
|
||||||
"Menuaction": ".bp3-overlay-open>.bp3-transition-container",
|
"Menuaction": ".bp3-overlay-open>.bp3-transition-container",
|
||||||
"Delete": ":nth-child(2) > .bp3-menu-item",
|
"Delete": ":nth-child(2) > .bp3-menu-item",
|
||||||
"apiEditorIcon": ".t--nav-link-api-editor",
|
"apiEditorIcon": ".t--nav-link-api-editor",
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,7 @@
|
||||||
"labelTextStyle": ".bp3-ui-text span",
|
"labelTextStyle": ".bp3-ui-text span",
|
||||||
"bodyTextStyle": ".bp3-running-text span",
|
"bodyTextStyle": ".bp3-running-text span",
|
||||||
"headingTextStyle": ".bp3-heading span",
|
"headingTextStyle": ".bp3-heading span",
|
||||||
"editWidgetName": ".bp3-editable-text",
|
"editWidgetName": ".t--propery-page-title",
|
||||||
"dropDownIcon": ".t--property-control-textstyle span.bp3-icon-chevron-down",
|
"dropDownIcon": ".t--property-control-textstyle span.bp3-icon-chevron-down",
|
||||||
"onDateSelectedField": ".t--property-control-ondateselected",
|
"onDateSelectedField": ".t--property-control-ondateselected",
|
||||||
"TableRow": ".t--draggable-tablewidget .tbody",
|
"TableRow": ".t--draggable-tablewidget .tbody",
|
||||||
|
|
|
||||||
|
|
@ -214,28 +214,37 @@ Cypress.Commands.add("CreateAppForOrg", (orgName, appname) => {
|
||||||
.scrollIntoView()
|
.scrollIntoView()
|
||||||
.should("be.visible")
|
.should("be.visible")
|
||||||
.click();
|
.click();
|
||||||
cy.get(homePage.inputAppName).type(appname);
|
cy.wait("@createNewApplication").should(
|
||||||
cy.get(homePage.CreateApp)
|
"have.nested.property",
|
||||||
.contains("Submit")
|
"response.body.responseMeta.status",
|
||||||
.click({ force: true });
|
201,
|
||||||
cy.get("#loading").should("not.exist");
|
);
|
||||||
|
cy.wait(1000);
|
||||||
|
cy.get(homePage.applicationName).type(appname + "{enter}");
|
||||||
|
cy.wait("@updateApplication").should(
|
||||||
|
"have.nested.property",
|
||||||
|
"response.body.responseMeta.status",
|
||||||
|
200,
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
Cypress.Commands.add("CreateApp", appname => {
|
Cypress.Commands.add("CreateApp", appname => {
|
||||||
cy.get(homePage.createNew)
|
cy.get(homePage.createNew)
|
||||||
.first()
|
.first()
|
||||||
.click({ force: true });
|
.click({ force: true });
|
||||||
cy.get(homePage.inputAppName).type(appname);
|
cy.wait("@createNewApplication").should(
|
||||||
cy.get(homePage.CreateApp)
|
"have.nested.property",
|
||||||
.contains("Submit")
|
"response.body.responseMeta.status",
|
||||||
.click({ force: true });
|
201,
|
||||||
|
);
|
||||||
cy.get("#loading").should("not.exist");
|
cy.get("#loading").should("not.exist");
|
||||||
cy.wait("@getPagesForCreateApp").should(
|
cy.wait(1000);
|
||||||
|
cy.get(homePage.applicationName).type(appname + "{enter}");
|
||||||
|
cy.wait("@updateApplication").should(
|
||||||
"have.nested.property",
|
"have.nested.property",
|
||||||
"response.body.responseMeta.status",
|
"response.body.responseMeta.status",
|
||||||
200,
|
200,
|
||||||
);
|
);
|
||||||
cy.get("h2").contains("Drag and drop a widget here");
|
|
||||||
});
|
});
|
||||||
|
|
||||||
Cypress.Commands.add("DeleteApp", appName => {
|
Cypress.Commands.add("DeleteApp", appName => {
|
||||||
|
|
@ -301,7 +310,9 @@ Cypress.Commands.add("DeleteApp", appName => {
|
||||||
cy.get(commonlocators.homeIcon).click({ force: true });
|
cy.get(commonlocators.homeIcon).click({ force: true });
|
||||||
cy.get(homePage.searchInput).type(appName);
|
cy.get(homePage.searchInput).type(appName);
|
||||||
cy.wait(2000);
|
cy.wait(2000);
|
||||||
cy.get(homePage.applicationCard).trigger("mouseover");
|
cy.get(homePage.applicationCard)
|
||||||
|
.first()
|
||||||
|
.trigger("mouseover");
|
||||||
cy.get(homePage.appMoreIcon)
|
cy.get(homePage.appMoreIcon)
|
||||||
.first()
|
.first()
|
||||||
.click({ force: true });
|
.click({ force: true });
|
||||||
|
|
@ -1787,15 +1798,3 @@ Cypress.Commands.add("callApi", apiname => {
|
||||||
Cypress.Commands.add("assertPageSave", () => {
|
Cypress.Commands.add("assertPageSave", () => {
|
||||||
cy.get(commonlocators.saveStatusSuccess);
|
cy.get(commonlocators.saveStatusSuccess);
|
||||||
});
|
});
|
||||||
|
|
||||||
Cypress.Commands.add("EditApp", appName => {
|
|
||||||
cy.get(homePage.searchInput).type(appName);
|
|
||||||
cy.wait(2000);
|
|
||||||
cy.get(homePage.applicationCard)
|
|
||||||
.first()
|
|
||||||
.trigger("mouseover");
|
|
||||||
cy.get(homePage.appEditIcon)
|
|
||||||
.first()
|
|
||||||
.click({ force: true });
|
|
||||||
cy.get("#loading").should("not.exist");
|
|
||||||
});
|
|
||||||
|
|
|
||||||
|
|
@ -21,28 +21,28 @@ export enum SavingState {
|
||||||
ERROR = "ERROR",
|
ERROR = "ERROR",
|
||||||
}
|
}
|
||||||
|
|
||||||
type EditableTextProps = CommonComponentProps & {
|
export type EditableTextProps = CommonComponentProps & {
|
||||||
defaultValue: string;
|
defaultValue: string;
|
||||||
onTextChanged: (value: string) => void;
|
placeholder?: string;
|
||||||
placeholder: string;
|
editInteractionKind: EditInteractionKind;
|
||||||
|
savingState: SavingState;
|
||||||
|
onBlur: (value: string) => void;
|
||||||
|
onTextChanged?: (value: string) => void;
|
||||||
className?: string;
|
className?: string;
|
||||||
valueTransform?: (value: string) => string;
|
valueTransform?: (value: string) => string;
|
||||||
isEditingDefault?: boolean;
|
isEditingDefault?: boolean;
|
||||||
forceDefault?: boolean;
|
forceDefault?: boolean;
|
||||||
updating?: boolean;
|
updating?: boolean;
|
||||||
isInvalid?: (value: string) => string | boolean;
|
isInvalid?: (value: string) => string | boolean;
|
||||||
editInteractionKind: EditInteractionKind;
|
|
||||||
hideEditIcon?: boolean;
|
hideEditIcon?: boolean;
|
||||||
fill?: boolean;
|
fill?: boolean;
|
||||||
savingState: SavingState;
|
|
||||||
onBlur: (value: string) => void;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const EditableTextWrapper = styled.div<{
|
const EditableTextWrapper = styled.div<{
|
||||||
fill?: boolean;
|
fill?: boolean;
|
||||||
}>`
|
}>`
|
||||||
width: ${props => (!props.fill ? "234px" : "100%")};
|
width: ${props => (!props.fill ? "234px" : "100%")};
|
||||||
.${Classes.TEXT} {
|
.error-message {
|
||||||
margin-left: ${props => props.theme.spaces[5]}px;
|
margin-left: ${props => props.theme.spaces[5]}px;
|
||||||
color: ${props => props.theme.colors.danger.main};
|
color: ${props => props.theme.colors.danger.main};
|
||||||
}
|
}
|
||||||
|
|
@ -70,10 +70,6 @@ const TextContainer = styled.div<{
|
||||||
}>`
|
}>`
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
${props =>
|
|
||||||
props.isEditing && props.isInvalid
|
|
||||||
? `margin-bottom: ${props.theme.spaces[2]}px`
|
|
||||||
: null};
|
|
||||||
.bp3-editable-text.bp3-editable-text-editing::before,
|
.bp3-editable-text.bp3-editable-text-editing::before,
|
||||||
.bp3-editable-text.bp3-disabled::before {
|
.bp3-editable-text.bp3-disabled::before {
|
||||||
display: none;
|
display: none;
|
||||||
|
|
@ -143,7 +139,6 @@ export const EditableText = (props: EditableTextProps) => {
|
||||||
const [savingState, setSavingState] = useState<SavingState>(
|
const [savingState, setSavingState] = useState<SavingState>(
|
||||||
SavingState.NOT_STARTED,
|
SavingState.NOT_STARTED,
|
||||||
);
|
);
|
||||||
const valueRef = React.useRef(defaultValue);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setSavingState(props.savingState);
|
setSavingState(props.savingState);
|
||||||
|
|
@ -178,14 +173,14 @@ export const EditableText = (props: EditableTextProps) => {
|
||||||
|
|
||||||
const onConfirm = useCallback(
|
const onConfirm = useCallback(
|
||||||
(_value: string) => {
|
(_value: string) => {
|
||||||
if (savingState === SavingState.ERROR || isInvalid) {
|
if (savingState === SavingState.ERROR || isInvalid || _value === "") {
|
||||||
setValue(lastValidValue);
|
setValue(lastValidValue);
|
||||||
onBlur(lastValidValue);
|
onBlur(lastValidValue);
|
||||||
setSavingState(SavingState.NOT_STARTED);
|
setSavingState(SavingState.NOT_STARTED);
|
||||||
} else if (changeStarted) {
|
} else if (changeStarted) {
|
||||||
onTextChanged(_value);
|
onTextChanged && onTextChanged(_value);
|
||||||
onBlur(_value);
|
|
||||||
}
|
}
|
||||||
|
onBlur(_value);
|
||||||
setIsEditing(false);
|
setIsEditing(false);
|
||||||
setChangeStarted(false);
|
setChangeStarted(false);
|
||||||
},
|
},
|
||||||
|
|
@ -204,10 +199,9 @@ export const EditableText = (props: EditableTextProps) => {
|
||||||
const finalVal: string = _value;
|
const finalVal: string = _value;
|
||||||
const errorMessage = inputValidation && inputValidation(finalVal);
|
const errorMessage = inputValidation && inputValidation(finalVal);
|
||||||
const error = errorMessage ? errorMessage : false;
|
const error = errorMessage ? errorMessage : false;
|
||||||
if (!error) {
|
if (!error && _value !== "") {
|
||||||
setLastValidValue(finalVal);
|
setLastValidValue(finalVal);
|
||||||
valueRef.current = finalVal;
|
onTextChanged && onTextChanged(finalVal);
|
||||||
onTextChanged(finalVal);
|
|
||||||
}
|
}
|
||||||
setValue(finalVal);
|
setValue(finalVal);
|
||||||
setIsInvalid(error);
|
setIsInvalid(error);
|
||||||
|
|
@ -258,8 +252,8 @@ export const EditableText = (props: EditableTextProps) => {
|
||||||
onChange={onInputchange}
|
onChange={onInputchange}
|
||||||
onConfirm={onConfirm}
|
onConfirm={onConfirm}
|
||||||
value={value}
|
value={value}
|
||||||
selectAllOnFocus
|
selectAllOnFocus={true}
|
||||||
placeholder={props.placeholder}
|
placeholder={props.placeholder || defaultValue}
|
||||||
className={props.className}
|
className={props.className}
|
||||||
onCancel={onConfirm}
|
onCancel={onConfirm}
|
||||||
/>
|
/>
|
||||||
|
|
@ -267,13 +261,15 @@ export const EditableText = (props: EditableTextProps) => {
|
||||||
<IconWrapper className="icon-wrapper">
|
<IconWrapper className="icon-wrapper">
|
||||||
{savingState === SavingState.STARTED ? (
|
{savingState === SavingState.STARTED ? (
|
||||||
<Spinner size={IconSize.XL} />
|
<Spinner size={IconSize.XL} />
|
||||||
) : (
|
) : value ? (
|
||||||
<Icon name={iconName} size={IconSize.XL} />
|
<Icon name={iconName} size={IconSize.XL} />
|
||||||
)}
|
) : null}
|
||||||
</IconWrapper>
|
</IconWrapper>
|
||||||
</TextContainer>
|
</TextContainer>
|
||||||
{isEditing && !!isInvalid ? (
|
{isEditing && !!isInvalid ? (
|
||||||
<Text type={TextType.P2}>{isInvalid}</Text>
|
<Text className="error-message" type={TextType.P2}>
|
||||||
|
{isInvalid}
|
||||||
|
</Text>
|
||||||
) : null}
|
) : null}
|
||||||
</EditableTextWrapper>
|
</EditableTextWrapper>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
82
app/client/src/components/ads/EditableTextWrapper.tsx
Normal file
82
app/client/src/components/ads/EditableTextWrapper.tsx
Normal file
|
|
@ -0,0 +1,82 @@
|
||||||
|
import EditableText, { EditableTextProps, SavingState } from "./EditableText";
|
||||||
|
import React, { useEffect, useState } from "react";
|
||||||
|
import styled from "styled-components";
|
||||||
|
import { Classes } from "@blueprintjs/core";
|
||||||
|
|
||||||
|
type EditableTextWrapperProps = EditableTextProps & {
|
||||||
|
variant: "UNDERLINE" | "ICON";
|
||||||
|
isNewApp: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
const Container = styled.div<{
|
||||||
|
isEditing?: boolean;
|
||||||
|
savingState: SavingState;
|
||||||
|
isInvalid: boolean;
|
||||||
|
}>`
|
||||||
|
&&& .${Classes.EDITABLE_TEXT}, .icon-wrapper {
|
||||||
|
padding: 5px 10px;
|
||||||
|
height: 25px;
|
||||||
|
text-decoration: ${props => (props.isEditing ? "unset" : "underline")};
|
||||||
|
text-decoration-style: dotted;
|
||||||
|
background-color: ${props =>
|
||||||
|
(props.isInvalid && props.isEditing) ||
|
||||||
|
props.savingState === SavingState.ERROR
|
||||||
|
? props.theme.colors.editableText.dangerBg
|
||||||
|
: "transparent"};
|
||||||
|
}
|
||||||
|
|
||||||
|
&&& .${Classes.EDITABLE_TEXT_CONTENT}, &&& .${Classes.EDITABLE_TEXT_INPUT} {
|
||||||
|
text-align: center;
|
||||||
|
color: #d4d4d4;
|
||||||
|
font-size: ${props => props.theme.typography.h4.fontSize}px;
|
||||||
|
line-height: ${props => props.theme.typography.h4.lineHeight}px;
|
||||||
|
letter-spacing: ${props => props.theme.typography.h4.letterSpacing}px;
|
||||||
|
font-weight: ${props => props.theme.typography.h4.fontWeight}px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.error-message {
|
||||||
|
margin-top: 2px;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
export default function EditableTextWrapper(props: EditableTextWrapperProps) {
|
||||||
|
const [isEditing, setIsEditing] = useState(props.isNewApp);
|
||||||
|
const [isValid, setIsValid] = useState(false);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setIsEditing(props.isNewApp);
|
||||||
|
}, [props.isNewApp]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Container
|
||||||
|
isEditing={isEditing}
|
||||||
|
savingState={props.savingState}
|
||||||
|
isInvalid={isValid}
|
||||||
|
>
|
||||||
|
<EditableText
|
||||||
|
defaultValue={props.defaultValue}
|
||||||
|
editInteractionKind={props.editInteractionKind}
|
||||||
|
placeholder={props.placeholder}
|
||||||
|
hideEditIcon={props.hideEditIcon}
|
||||||
|
isEditingDefault={props.isNewApp}
|
||||||
|
savingState={props.savingState}
|
||||||
|
fill={props.fill}
|
||||||
|
onBlur={value => {
|
||||||
|
setIsEditing(false);
|
||||||
|
props.onBlur(value);
|
||||||
|
}}
|
||||||
|
className={props.className}
|
||||||
|
onTextChanged={(value: string) => setIsEditing(true)}
|
||||||
|
isInvalid={(value: string) => {
|
||||||
|
setIsEditing(true);
|
||||||
|
if (props.isInvalid) {
|
||||||
|
setIsValid(Boolean(props.isInvalid(value)));
|
||||||
|
return props.isInvalid(value);
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Container>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
@ -204,7 +204,6 @@ const AppNameWrapper = styled.div<{ isFetching: boolean }>`
|
||||||
: null};
|
: null};
|
||||||
`;
|
`;
|
||||||
type ApplicationCardProps = {
|
type ApplicationCardProps = {
|
||||||
activeAppCard?: boolean;
|
|
||||||
application: ApplicationPayload;
|
application: ApplicationPayload;
|
||||||
duplicate?: (applicationId: string) => void;
|
duplicate?: (applicationId: string) => void;
|
||||||
share?: (applicationId: string) => void;
|
share?: (applicationId: string) => void;
|
||||||
|
|
@ -275,11 +274,6 @@ export const ApplicationCard = (props: ApplicationCardProps) => {
|
||||||
addDeleteOption();
|
addDeleteOption();
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, []);
|
}, []);
|
||||||
useEffect(() => {
|
|
||||||
if (props.activeAppCard) {
|
|
||||||
setShowOverlay(true);
|
|
||||||
}
|
|
||||||
}, [props.activeAppCard]);
|
|
||||||
|
|
||||||
const appIcon = (props.application?.icon ||
|
const appIcon = (props.application?.icon ||
|
||||||
getApplicationIcon(props.application.id)) as AppIconName;
|
getApplicationIcon(props.application.id)) as AppIconName;
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import React, { Component, useState } from "react";
|
import React, { Component, Fragment, useState } from "react";
|
||||||
import styled from "styled-components";
|
import styled from "styled-components";
|
||||||
import { connect, useSelector, useDispatch } from "react-redux";
|
import { connect, useSelector, useDispatch } from "react-redux";
|
||||||
import { AppState } from "reducers";
|
import { AppState } from "reducers";
|
||||||
|
|
@ -53,11 +53,11 @@ import PerformanceTracker, {
|
||||||
PerformanceTransactionName,
|
PerformanceTransactionName,
|
||||||
} from "utils/PerformanceTracker";
|
} from "utils/PerformanceTracker";
|
||||||
import { loadingUserOrgs } from "./ApplicationLoaders";
|
import { loadingUserOrgs } from "./ApplicationLoaders";
|
||||||
import CreateApplicationForm from "./CreateApplicationForm";
|
|
||||||
import { creatingApplicationMap } from "reducers/uiReducers/applicationsReducer";
|
import { creatingApplicationMap } from "reducers/uiReducers/applicationsReducer";
|
||||||
import CenteredWrapper from "../../components/designSystems/appsmith/CenteredWrapper";
|
import CenteredWrapper from "../../components/designSystems/appsmith/CenteredWrapper";
|
||||||
import NoSearchImage from "../../assets/images/NoSearchResult.svg";
|
import NoSearchImage from "../../assets/images/NoSearchResult.svg";
|
||||||
import organizationList from "../../mockResponses/OrganisationListResponse";
|
import { getNextEntityName } from "utils/AppsmithUtils";
|
||||||
|
import Spinner from "components/ads/Spinner";
|
||||||
|
|
||||||
const OrgDropDown = styled.div`
|
const OrgDropDown = styled.div`
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|
@ -348,7 +348,7 @@ function LeftPane() {
|
||||||
isFetchingApplications ? BlueprintClasses.SKELETON : ""
|
isFetchingApplications ? BlueprintClasses.SKELETON : ""
|
||||||
}
|
}
|
||||||
icon="workspace"
|
icon="workspace"
|
||||||
key={org.organization.name}
|
key={org.organization.id}
|
||||||
href={`${window.location.pathname}#${org.organization.name}`}
|
href={`${window.location.pathname}#${org.organization.name}`}
|
||||||
text={org.organization.name}
|
text={org.organization.name}
|
||||||
ellipsize={20}
|
ellipsize={20}
|
||||||
|
|
@ -405,18 +405,6 @@ ${props => {
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const AddApplicationCard = (
|
|
||||||
<ApplicationAddCardWrapper>
|
|
||||||
<Icon
|
|
||||||
className="t--create-app-popup"
|
|
||||||
name={"plus"}
|
|
||||||
size={IconSize.LARGE}
|
|
||||||
></Icon>
|
|
||||||
<CreateNewLabel type={TextType.H4} className="createnew">
|
|
||||||
Create New
|
|
||||||
</CreateNewLabel>
|
|
||||||
</ApplicationAddCardWrapper>
|
|
||||||
);
|
|
||||||
const NoSearchResultImg = styled.img`
|
const NoSearchResultImg = styled.img`
|
||||||
margin: 1em;
|
margin: 1em;
|
||||||
`;
|
`;
|
||||||
|
|
@ -513,6 +501,7 @@ const ApplicationsSection = (props: any) => {
|
||||||
};
|
};
|
||||||
|
|
||||||
const createNewApplication = (applicationName: string, orgId: string) => {
|
const createNewApplication = (applicationName: string, orgId: string) => {
|
||||||
|
console.log(applicationName, orgId);
|
||||||
return dispatch({
|
return dispatch({
|
||||||
type: ReduxActionTypes.CREATE_APPLICATION_INIT,
|
type: ReduxActionTypes.CREATE_APPLICATION_INIT,
|
||||||
payload: {
|
payload: {
|
||||||
|
|
@ -601,14 +590,40 @@ const ApplicationsSection = (props: any) => {
|
||||||
) &&
|
) &&
|
||||||
!isFetchingApplications && (
|
!isFetchingApplications && (
|
||||||
<PaddingWrapper>
|
<PaddingWrapper>
|
||||||
<FormDialogComponent
|
<ApplicationAddCardWrapper
|
||||||
permissions={organization.userPermissions}
|
onClick={() => {
|
||||||
permissionRequired={PERMISSION_TYPE.CREATE_APPLICATION}
|
if (
|
||||||
trigger={AddApplicationCard}
|
Object.entries(creatingApplicationMap).length === 0
|
||||||
Form={CreateApplicationForm}
|
) {
|
||||||
orgId={organization.id}
|
createNewApplication(
|
||||||
title={CREATE_APPLICATION_FORM_NAME}
|
getNextEntityName(
|
||||||
/>
|
"Untitled application ",
|
||||||
|
applications.map((el: any) => el.name),
|
||||||
|
),
|
||||||
|
organization.id,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{creatingApplicationMap &&
|
||||||
|
creatingApplicationMap[organization.id] ? (
|
||||||
|
<Spinner size={IconSize.XXXL} />
|
||||||
|
) : (
|
||||||
|
<Fragment>
|
||||||
|
<Icon
|
||||||
|
className="t--create-app-popup"
|
||||||
|
name={"plus"}
|
||||||
|
size={IconSize.LARGE}
|
||||||
|
></Icon>
|
||||||
|
<CreateNewLabel
|
||||||
|
type={TextType.H4}
|
||||||
|
className="createnew"
|
||||||
|
>
|
||||||
|
Create New
|
||||||
|
</CreateNewLabel>
|
||||||
|
</Fragment>
|
||||||
|
)}
|
||||||
|
</ApplicationAddCardWrapper>
|
||||||
</PaddingWrapper>
|
</PaddingWrapper>
|
||||||
)}
|
)}
|
||||||
{applications.map((application: any) => {
|
{applications.map((application: any) => {
|
||||||
|
|
@ -619,11 +634,6 @@ const ApplicationsSection = (props: any) => {
|
||||||
key={application.id}
|
key={application.id}
|
||||||
application={application}
|
application={application}
|
||||||
orgId={organization.id}
|
orgId={organization.id}
|
||||||
activeAppCard={
|
|
||||||
props.newApplicationList[
|
|
||||||
props.newApplicationList.length - 1
|
|
||||||
] === application.id
|
|
||||||
}
|
|
||||||
delete={deleteApplication}
|
delete={deleteApplication}
|
||||||
update={updateApplicationDispatch}
|
update={updateApplicationDispatch}
|
||||||
duplicate={duplicateApplicationDispatch}
|
duplicate={duplicateApplicationDispatch}
|
||||||
|
|
@ -664,14 +674,13 @@ type ApplicationProps = {
|
||||||
};
|
};
|
||||||
class Applications extends Component<
|
class Applications extends Component<
|
||||||
ApplicationProps,
|
ApplicationProps,
|
||||||
{ selectedOrgId: string; newApplicationList: any }
|
{ selectedOrgId: string }
|
||||||
> {
|
> {
|
||||||
constructor(props: ApplicationProps) {
|
constructor(props: ApplicationProps) {
|
||||||
super(props);
|
super(props);
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
selectedOrgId: "",
|
selectedOrgId: "",
|
||||||
newApplicationList: [],
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -679,22 +688,6 @@ class Applications extends Component<
|
||||||
PerformanceTracker.stopTracking(PerformanceTransactionName.LOGIN_CLICK);
|
PerformanceTracker.stopTracking(PerformanceTransactionName.LOGIN_CLICK);
|
||||||
PerformanceTracker.stopTracking(PerformanceTransactionName.SIGN_UP);
|
PerformanceTracker.stopTracking(PerformanceTransactionName.SIGN_UP);
|
||||||
this.props.getAllApplication();
|
this.props.getAllApplication();
|
||||||
if (this.props.applicationList.length > 0) {
|
|
||||||
this.setState({
|
|
||||||
newApplicationList: this.props.applicationList.map(el => el.id),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
componentDidUpdate() {
|
|
||||||
if (
|
|
||||||
this.props.applicationList.length > 0 &&
|
|
||||||
this.props.applicationList.length !== this.state.newApplicationList.length
|
|
||||||
) {
|
|
||||||
this.setState({
|
|
||||||
newApplicationList: this.props.applicationList.map(el => el.id),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public render() {
|
public render() {
|
||||||
|
|
@ -708,7 +701,6 @@ class Applications extends Component<
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<ApplicationsSection
|
<ApplicationsSection
|
||||||
newApplicationList={this.state.newApplicationList}
|
|
||||||
searchKeyword={this.props.searchKeyword}
|
searchKeyword={this.props.searchKeyword}
|
||||||
></ApplicationsSection>
|
></ApplicationsSection>
|
||||||
</PageWrapper>
|
</PageWrapper>
|
||||||
|
|
|
||||||
|
|
@ -25,10 +25,17 @@ import {
|
||||||
getIsPublishingApplication,
|
getIsPublishingApplication,
|
||||||
} from "selectors/editorSelectors";
|
} from "selectors/editorSelectors";
|
||||||
import { getCurrentOrgId } from "selectors/organizationSelectors";
|
import { getCurrentOrgId } from "selectors/organizationSelectors";
|
||||||
import { connect } from "react-redux";
|
import { connect, useDispatch, useSelector } from "react-redux";
|
||||||
import { HeaderIcons } from "icons/HeaderIcons";
|
import { HeaderIcons } from "icons/HeaderIcons";
|
||||||
import ThreeDotLoading from "components/designSystems/appsmith/header/ThreeDotsLoading";
|
import ThreeDotLoading from "components/designSystems/appsmith/header/ThreeDotsLoading";
|
||||||
import DeployLinkButtonDialog from "components/designSystems/appsmith/header/DeployLinkButton";
|
import DeployLinkButtonDialog from "components/designSystems/appsmith/header/DeployLinkButton";
|
||||||
|
import { EditInteractionKind, SavingState } from "components/ads/EditableText";
|
||||||
|
import { updateApplication } from "actions/applicationActions";
|
||||||
|
import {
|
||||||
|
getApplicationList,
|
||||||
|
getIsSavingAppName,
|
||||||
|
} from "selectors/applicationSelectors";
|
||||||
|
import EditableTextWrapper from "components/ads/EditableTextWrapper";
|
||||||
|
|
||||||
const HeaderWrapper = styled(StyledHeader)`
|
const HeaderWrapper = styled(StyledHeader)`
|
||||||
background: ${Colors.BALTIC_SEA};
|
background: ${Colors.BALTIC_SEA};
|
||||||
|
|
@ -143,6 +150,10 @@ export const EditorHeader = (props: EditorHeaderProps) => {
|
||||||
publishApplication,
|
publishApplication,
|
||||||
} = props;
|
} = props;
|
||||||
|
|
||||||
|
const dispatch = useDispatch();
|
||||||
|
const isSavingName = useSelector(getIsSavingAppName);
|
||||||
|
const applicationList = useSelector(getApplicationList);
|
||||||
|
|
||||||
const handlePublish = () => {
|
const handlePublish = () => {
|
||||||
if (applicationId) {
|
if (applicationId) {
|
||||||
publishApplication(applicationId);
|
publishApplication(applicationId);
|
||||||
|
|
@ -180,6 +191,10 @@ export const EditorHeader = (props: EditorHeaderProps) => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const updateApplicationDispatch = (id: string, data: { name: string }) => {
|
||||||
|
dispatch(updateApplication(id, data));
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<HeaderWrapper>
|
<HeaderWrapper>
|
||||||
<HeaderSection>
|
<HeaderSection>
|
||||||
|
|
@ -192,8 +207,26 @@ export const EditorHeader = (props: EditorHeaderProps) => {
|
||||||
</Link>
|
</Link>
|
||||||
</HeaderSection>
|
</HeaderSection>
|
||||||
<HeaderSection flex-direction={"row"}>
|
<HeaderSection flex-direction={"row"}>
|
||||||
<ApplicationName>{currentApplication?.name} </ApplicationName>
|
{currentApplication ? (
|
||||||
<PageName>{pageName} </PageName>
|
<EditableTextWrapper
|
||||||
|
variant="UNDERLINE"
|
||||||
|
defaultValue={currentApplication?.name || ""}
|
||||||
|
editInteractionKind={EditInteractionKind.SINGLE}
|
||||||
|
hideEditIcon={true}
|
||||||
|
className="t--application-name"
|
||||||
|
fill={false}
|
||||||
|
savingState={
|
||||||
|
isSavingName ? SavingState.STARTED : SavingState.NOT_STARTED
|
||||||
|
}
|
||||||
|
isNewApp={
|
||||||
|
applicationList.filter(el => el.id === applicationId).length > 0
|
||||||
|
}
|
||||||
|
onBlur={(value: string) =>
|
||||||
|
updateApplicationDispatch(applicationId || "", { name: value })
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
) : null}
|
||||||
|
{/* <PageName>{pageName} </PageName> */}
|
||||||
</HeaderSection>
|
</HeaderSection>
|
||||||
<HeaderSection>
|
<HeaderSection>
|
||||||
<SaveStatusContainer className={"t--save-status-container"}>
|
<SaveStatusContainer className={"t--save-status-container"}>
|
||||||
|
|
|
||||||
|
|
@ -100,6 +100,7 @@ const PageListItem = withTheme((props: PageListItemProps) => {
|
||||||
editInteractionKind={EditInteractionKind.DOUBLE}
|
editInteractionKind={EditInteractionKind.DOUBLE}
|
||||||
onTextChanged={onEditPageName}
|
onTextChanged={onEditPageName}
|
||||||
hideEditIcon
|
hideEditIcon
|
||||||
|
className="t--page-list-item"
|
||||||
/>
|
/>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -116,6 +116,7 @@ const PropertyPaneTitle = memo((props: PropertyPaneTitleProps) => {
|
||||||
onBlur={exitEditMode}
|
onBlur={exitEditMode}
|
||||||
hideEditIcon
|
hideEditIcon
|
||||||
minimal
|
minimal
|
||||||
|
className="t--propery-page-title"
|
||||||
/>
|
/>
|
||||||
{updating && <Spinner size={16} />}
|
{updating && <Spinner size={16} />}
|
||||||
</NameWrapper>
|
</NameWrapper>
|
||||||
|
|
|
||||||
|
|
@ -222,7 +222,7 @@ const applicationsReducer = createReducer(initialState, {
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
userOrgs: _organizations,
|
userOrgs: _organizations,
|
||||||
isSavingAppName: isSavingAppName,
|
isSavingAppName: true,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
[ReduxActionTypes.UPDATE_APPLICATION_SUCCESS]: (
|
[ReduxActionTypes.UPDATE_APPLICATION_SUCCESS]: (
|
||||||
|
|
|
||||||
|
|
@ -212,6 +212,10 @@ export function* updateApplicationSaga(
|
||||||
type: ReduxActionTypes.UPDATE_APPLICATION_SUCCESS,
|
type: ReduxActionTypes.UPDATE_APPLICATION_SUCCESS,
|
||||||
payload: response.data,
|
payload: response.data,
|
||||||
});
|
});
|
||||||
|
AppToaster.show({
|
||||||
|
message: `Application updated`,
|
||||||
|
type: "success",
|
||||||
|
});
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
yield put({
|
yield put({
|
||||||
|
|
@ -220,6 +224,10 @@ export function* updateApplicationSaga(
|
||||||
error,
|
error,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
AppToaster.show({
|
||||||
|
message: error,
|
||||||
|
type: "error",
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user