From 955e9a2f2b4bce1edc0d003c5dac92edaf806391 Mon Sep 17 00:00:00 2001 From: Hetu Nandu Date: Fri, 7 Aug 2020 12:26:47 +0530 Subject: [PATCH] App Edit top bar (#232) --- .../FormWidgets/Button_spec.js | 2 +- app/client/cypress/locators/HomePage.json | 4 +- .../cypress/locators/commonlocators.json | 10 +- app/client/cypress/support/commands.js | 18 +- app/client/src/assets/icons/header/deploy.svg | 4 + .../src/assets/icons/header/feedback.svg | 3 + .../src/assets/icons/header/save-failure.svg | 3 + .../src/assets/icons/header/save-loading.gif | Bin 0 -> 14505 bytes .../src/assets/icons/header/save-success.svg | 3 + .../appsmith/header/DeployLinkButton.tsx | 85 +++++ .../appsmith/header/ThreeDotsLoading.tsx | 69 ++++ .../components/editorComponents/Button.tsx | 2 + .../form/FormDialogComponent.tsx | 3 +- app/client/src/icons/HeaderIcons.tsx | 24 ++ .../AppViewer/viewer/AppViewerHeader.tsx | 2 +- app/client/src/pages/Editor/EditorHeader.tsx | 350 +++++++++++------- app/client/src/pages/Editor/index.tsx | 108 +----- app/client/src/pages/common/AppHeader.tsx | 11 +- app/client/src/selectors/editorSelectors.tsx | 2 +- 19 files changed, 447 insertions(+), 256 deletions(-) create mode 100644 app/client/src/assets/icons/header/deploy.svg create mode 100644 app/client/src/assets/icons/header/feedback.svg create mode 100644 app/client/src/assets/icons/header/save-failure.svg create mode 100644 app/client/src/assets/icons/header/save-loading.gif create mode 100644 app/client/src/assets/icons/header/save-success.svg create mode 100644 app/client/src/components/designSystems/appsmith/header/DeployLinkButton.tsx create mode 100644 app/client/src/components/designSystems/appsmith/header/ThreeDotsLoading.tsx diff --git a/app/client/cypress/integration/Smoke_TestSuite/FormWidgets/Button_spec.js b/app/client/cypress/integration/Smoke_TestSuite/FormWidgets/Button_spec.js index 5880c1992f..341bbd6cde 100644 --- a/app/client/cypress/integration/Smoke_TestSuite/FormWidgets/Button_spec.js +++ b/app/client/cypress/integration/Smoke_TestSuite/FormWidgets/Button_spec.js @@ -29,7 +29,7 @@ describe("Button Widget Functionality", function() { cy.EvaluateDataType("string"); cy.EvaluateCurrentValue(this.data.ButtonLabel); - cy.xpath(homePage.homePageID).contains("All changes saved"); + cy.assertPageSave(); //Verify the Button name and label cy.get(widgetsPage.buttonWidget).trigger("mouseover"); diff --git a/app/client/cypress/locators/HomePage.json b/app/client/cypress/locators/HomePage.json index d586905e72..d2f07624c5 100644 --- a/app/client/cypress/locators/HomePage.json +++ b/app/client/cypress/locators/HomePage.json @@ -10,7 +10,7 @@ "deleteButton":".bp3-menu-item.bp3-popover-dismiss", "selectAction":"#Base", "deleteApp":".bp3-menu-item", - "homeIcon": ".bp3-icon-home", + "homeIcon": ".t--appsmith-logo", "inputAppName": "input[name=applicationName]", "createNew": ".createnew", "createOrg": "button:contains('Create Organization')", @@ -39,4 +39,4 @@ "shareOrg": ") .bp3-button-text:contains('Share')", "orgSection": ".bp3-button-text:contains(", "createAppFrOrg": ") .t--create-app-popup" -} \ No newline at end of file +} diff --git a/app/client/cypress/locators/commonlocators.json b/app/client/cypress/locators/commonlocators.json index 3170dd0efc..96d18d397e 100644 --- a/app/client/cypress/locators/commonlocators.json +++ b/app/client/cypress/locators/commonlocators.json @@ -22,7 +22,7 @@ "scrollView": ".t--property-control-scrollcontents input", "InputforText": ".t--property-control-text .CodeMirror-code", "TextInside": ".bp3-ui-text span", - "homeIcon": ".bp3-icon.bp3-icon-home", + "homeIcon": ".t--appsmith-logo", "typeWidgetName": ".bp3-editable-text-editing>input", "requiredCheckbox": ".t--property-control-required input[type='checkbox']", "visibleCheckbox": ".t--property-control-visible input[type='checkbox']", @@ -57,5 +57,9 @@ "singleSelectMenuItem": ".bp3-menu-item.single-select div", "selectMenuItem": ".bp3-menu li>a>div", "evaluatedType": ".t--CodeEditor-evaluatedValue>pre", - "evaluatedCurrentValue": ".t--CodeEditor-evaluatedValue div pre" -} \ No newline at end of file + "evaluatedCurrentValue": ".t--CodeEditor-evaluatedValue div pre", + "saveStatusContainer": ".t--save-status-container", + "saveStatusIsSaving": "t--save-status-is-saving", + "saveStatusSuccess": ".t--save-status-success", + "saveStatusError": ".t--save-status-error" +} diff --git a/app/client/cypress/support/commands.js b/app/client/cypress/support/commands.js index 8a8b8c49f9..27719e7e90 100644 --- a/app/client/cypress/support/commands.js +++ b/app/client/cypress/support/commands.js @@ -629,7 +629,7 @@ Cypress.Commands.add("createModal", (modalType, ModalName) => { .children() .contains(modalType) .click(); - cy.xpath(homePage.homePageID).contains("All changes saved"); + cy.assertPageSave(); // changing the model name verify cy.widgetText( @@ -650,21 +650,21 @@ Cypress.Commands.add("createModal", (modalType, ModalName) => { cy.get(widgetsPage.textAlign + " .bp3-menu-item") .contains("Center") .click(); - cy.xpath(homePage.homePageID).contains("All changes saved"); + cy.assertPageSave(); }); Cypress.Commands.add("CheckWidgetProperties", checkboxCss => { cy.get(checkboxCss).check({ force: true, }); - cy.xpath(homePage.homePageID).contains("All changes saved"); + cy.assertPageSave(); }); Cypress.Commands.add("UncheckWidgetProperties", checkboxCss => { cy.get(checkboxCss).uncheck({ force: true, }); - cy.xpath(homePage.homePageID).contains("All changes saved"); + cy.assertPageSave(); }); Cypress.Commands.add( @@ -708,7 +708,7 @@ Cypress.Commands.add("PublishtheApp", () => { cy.route("POST", "/api/v1/applications/publish/*").as("publishApp"); // Wait before publish cy.wait(2000); - cy.xpath(homePage.homePageID).contains("All changes saved"); + cy.assertPageSave(); cy.get(homePage.publishButton).click(); cy.wait("@publishApp"); cy.get('a[class="bp3-button"]') @@ -781,14 +781,14 @@ Cypress.Commands.add("SetDateToToday", () => { cy.get(formWidgetsPage.datepickerFooter) .contains("Today") .click(); - cy.xpath(homePage.homePageID).contains("All changes saved"); + cy.assertPageSave(); }); Cypress.Commands.add("ClearDate", () => { cy.get(formWidgetsPage.datepickerFooter) .contains("Clear") .click(); - cy.xpath(homePage.homePageID).contains("All changes saved"); + cy.assertPageSave(); }); Cypress.Commands.add("DeleteModal", () => { @@ -1453,3 +1453,7 @@ Cypress.Commands.add("callApi", apiname => { .contains(apiname) .click(); }); + +Cypress.Commands.add("assertPageSave", () => { + cy.get(commonlocators.saveStatusSuccess); +}); diff --git a/app/client/src/assets/icons/header/deploy.svg b/app/client/src/assets/icons/header/deploy.svg new file mode 100644 index 0000000000..faa203e316 --- /dev/null +++ b/app/client/src/assets/icons/header/deploy.svg @@ -0,0 +1,4 @@ + + + + diff --git a/app/client/src/assets/icons/header/feedback.svg b/app/client/src/assets/icons/header/feedback.svg new file mode 100644 index 0000000000..4eba24b0c4 --- /dev/null +++ b/app/client/src/assets/icons/header/feedback.svg @@ -0,0 +1,3 @@ + + + diff --git a/app/client/src/assets/icons/header/save-failure.svg b/app/client/src/assets/icons/header/save-failure.svg new file mode 100644 index 0000000000..d1d8ba1915 --- /dev/null +++ b/app/client/src/assets/icons/header/save-failure.svg @@ -0,0 +1,3 @@ + + + diff --git a/app/client/src/assets/icons/header/save-loading.gif b/app/client/src/assets/icons/header/save-loading.gif new file mode 100644 index 0000000000000000000000000000000000000000..b7cfcf3cabe69d86363e4ae862ca13f3500b00b0 GIT binary patch literal 14505 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 + + diff --git a/app/client/src/components/designSystems/appsmith/header/DeployLinkButton.tsx b/app/client/src/components/designSystems/appsmith/header/DeployLinkButton.tsx new file mode 100644 index 0000000000..a08bc3a470 --- /dev/null +++ b/app/client/src/components/designSystems/appsmith/header/DeployLinkButton.tsx @@ -0,0 +1,85 @@ +import React, { ReactNode, useState } from "react"; +import styled from "styled-components"; +import { Icon, Popover, PopoverPosition } from "@blueprintjs/core"; + +const IconContainer = styled.div` + margin: 0 10px; + border: 1px solid #bcccd9; + border-radius: 50%; + min-width: 32px; + width: 32px; + height: 32px; + display: flex; + align-items: center; + justify-content: center; + flex-grow: 1; +`; + +const DeployLinkDialog = styled.a` + display: flex; + align-items: center; + background-color: #fff; + padding: 10px; + width: 336px; + height: 60px; + cursor: pointer; + text-decoration: none; + color: #2e3d49; + :hover { + text-decoration: none; + color: #2e3d49; + } +`; + +const DeployUrl = styled.div` + font-size: 12px; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +`; + +type Props = { + trigger: ReactNode; + link: string; +}; + +export const DeployLinkButton = (props: Props) => { + const [isOpen, setIsOpen] = useState(false); + + const onClose = () => { + setIsOpen(false); + }; + + return ( + + + + + + + {window.location.origin} + {props.link} + + + + } + canEscapeKeyClose={false} + onClose={onClose} + isOpen={isOpen} + position={PopoverPosition.BOTTOM} + > +
setIsOpen(true)}>{props.trigger}
+
+
+ ); +}; + +export default DeployLinkButton; diff --git a/app/client/src/components/designSystems/appsmith/header/ThreeDotsLoading.tsx b/app/client/src/components/designSystems/appsmith/header/ThreeDotsLoading.tsx new file mode 100644 index 0000000000..6705113b6e --- /dev/null +++ b/app/client/src/components/designSystems/appsmith/header/ThreeDotsLoading.tsx @@ -0,0 +1,69 @@ +/*Huge thanks to @tobiasahlin at http://tobiasahlin.com/spinkit/ */ + +import React from "react"; +import styled from "styled-components"; + +const Spinner = styled.div` + width: 30px; + text-align: center; + && > div { + width: 4px; + height: 4px; + background-color: #fff; + + border-radius: 100%; + display: inline-block; + -webkit-animation: sk-bouncedelay 1.4s infinite ease-in-out both; + animation: sk-bouncedelay 1.4s infinite ease-in-out both; + } + + && .bounce1 { + -webkit-animation-delay: -0.32s; + animation-delay: -0.32s; + } + + && .bounce2 { + -webkit-animation-delay: -0.16s; + animation-delay: -0.16s; + } + + @-webkit-keyframes sk-bouncedelay { + 0%, + 80%, + 100% { + -webkit-transform: scale(0); + } + 40% { + -webkit-transform: scale(1); + } + } + + @keyframes sk-bouncedelay { + 0%, + 80%, + 100% { + -webkit-transform: scale(0); + transform: scale(0); + } + 40% { + -webkit-transform: scale(1); + transform: scale(1); + } + } +`; + +type Props = { + className?: string; +}; + +const ThreeDotLoading = (props: Props) => { + return ( + +
+
+
+ + ); +}; + +export default ThreeDotLoading; diff --git a/app/client/src/components/editorComponents/Button.tsx b/app/client/src/components/editorComponents/Button.tsx index 4c5481842f..243abfe7e3 100644 --- a/app/client/src/components/editorComponents/Button.tsx +++ b/app/client/src/components/editorComponents/Button.tsx @@ -96,6 +96,7 @@ export type ButtonProps = { className?: string; fluid?: boolean; skin?: Skin; + target?: string; }; export const Button = (props: ButtonProps) => { @@ -133,6 +134,7 @@ export const Button = (props: ButtonProps) => { rightIcon={rightIcon} {...baseProps} href={props.href} + target={props.target} /> ); } else diff --git a/app/client/src/components/editorComponents/form/FormDialogComponent.tsx b/app/client/src/components/editorComponents/form/FormDialogComponent.tsx index d992f87dec..7a7eb67024 100644 --- a/app/client/src/components/editorComponents/form/FormDialogComponent.tsx +++ b/app/client/src/components/editorComponents/form/FormDialogComponent.tsx @@ -1,6 +1,5 @@ import React, { ReactNode, useState } from "react"; import styled from "styled-components"; -import { connect } from "react-redux"; import { Dialog, Classes } from "@blueprintjs/core"; import { isPermitted } from "pages/Applications/permissionHelpers"; @@ -75,4 +74,4 @@ export const FormDialogComponent = (props: FormDialogComponentProps) => { ); }; -export default connect()(FormDialogComponent); +export default FormDialogComponent; diff --git a/app/client/src/icons/HeaderIcons.tsx b/app/client/src/icons/HeaderIcons.tsx index 435df70e70..e6f36a3d63 100644 --- a/app/client/src/icons/HeaderIcons.tsx +++ b/app/client/src/icons/HeaderIcons.tsx @@ -1,6 +1,10 @@ import React, { JSXElementConstructor } from "react"; import { IconProps, IconWrapper } from "constants/IconConstants"; import { ReactComponent as ShareIcon } from "assets/icons/header/share-white.svg"; +import { ReactComponent as DeployIcon } from "assets/icons/header/deploy.svg"; +import { ReactComponent as FeedbackIcon } from "assets/icons/header/feedback.svg"; +import { ReactComponent as SaveFailureIcon } from "assets/icons/header/save-failure.svg"; +import { ReactComponent as SaveSuccessIcon } from "assets/icons/header/save-success.svg"; /* eslint-disable react/display-name */ export const HeaderIcons: { @@ -11,6 +15,26 @@ export const HeaderIcons: { ), + DEPLOY: (props: IconProps) => ( + + + + ), + FEEDBACK: (props: IconProps) => ( + + + + ), + SAVE_FAILURE: (props: IconProps) => ( + + + + ), + SAVE_SUCCESS: (props: IconProps) => ( + + + + ), }; export type HeaderIconName = keyof typeof HeaderIcons; diff --git a/app/client/src/pages/AppViewer/viewer/AppViewerHeader.tsx b/app/client/src/pages/AppViewer/viewer/AppViewerHeader.tsx index 1b83635b11..963eff4c04 100644 --- a/app/client/src/pages/AppViewer/viewer/AppViewerHeader.tsx +++ b/app/client/src/pages/AppViewer/viewer/AppViewerHeader.tsx @@ -150,7 +150,7 @@ export const AppViewerHeader = (props: AppViewerHeaderProps) => { intent="none" outline size="small" - className="t--application-share-btn share-button" + className="t--application-share-btn" icon={ props.theme.fonts[0]}; - font-size: ${props => props.theme.fontSizes[2]}px; - } + :nth-child(1) { + justify-content: flex-start; + } + :nth-child(2) { + justify-content: center; + flex-direction: column; + } + :nth-child(3) { + justify-content: flex-end; } `; -const ShareButton = styled.div` +const AppsmithLogoImg = styled.img` + max-width: 110px; +`; + +const ApplicationName = styled.span` + font-weight: 500; + font-size: 14px; + line-height: 14px; + color: #fff; + margin-bottom: 6px; +`; + +const PageName = styled.span` display: flex; - flex-grow: 1; - justify-content: flex-end; + flex: 1; + font-size: 12px; + line-height: 12px; + letter-spacing: 0.04em; + color: #ffffff; + opacity: 0.5; +`; + +const SaveStatusContainer = styled.div` + margin: 0 10px; + border: 1px solid rgb(95, 105, 116); + border-radius: 50%; + width: 32px; + height: 32px; + display: flex; + align-items: center; + justify-content: center; +`; +const DeploySection = styled.div` + display: flex; +`; + +const DeployButton = styled(Button)` + height: 32px; + margin: 5px 10px; + margin-right: 0; + border-top-right-radius: 0; + border-bottom-right-radius: 0; +`; + +const DeployLinkButton = styled(Button)` + height: 32px; + margin: 5px 10px; + margin-left: 0; + border-top-left-radius: 0; + border-bottom-left-radius: 0; + min-width: 20px !important; + width: 20px !important; + background-color: rgb(42, 195, 157) !important; + border: none !important; +`; + +const ShareButton = styled(Button)` + height: 32px; + margin: 5px 10px; + color: white !important; + border-color: rgb(95, 105, 116) !important; `; type EditorHeaderProps = { @@ -64,143 +126,173 @@ type EditorHeaderProps = { isSaving?: boolean; pageSaveError?: boolean; pageName?: string; - onPublish: () => void; - onCreatePage: (name: string) => void; - pages?: PageListPayload; - currentPageId?: string; + pageId?: string; isPublishing: boolean; publishedTime?: string; orgId: string; - currentApplicationId?: string; - createModal: () => void; + applicationId?: string; + publishApplication: (appId: string) => void; }; -const navigation: IBreadcrumbProps[] = [ - { href: APPLICATIONS_URL, icon: "home", text: "Home" }, - { href: APPLICATIONS_URL, icon: "folder-close", text: "Applications" }, - { icon: "page-layout", text: "", current: true }, -]; + export const EditorHeader = (props: EditorHeaderProps) => { const { currentApplication, isSaving, pageSaveError, - onPublish, - pages, - currentPageId, + pageId, isPublishing, orgId, - currentApplicationId, + applicationId, + pageName, + publishApplication, } = props; - const selectedPageName = pages?.find(page => page.pageId === currentPageId) - ?.pageName; + const handlePublish = () => { + if (applicationId) { + publishApplication(applicationId); - const pageSelectorData: CustomizedDropdownProps = { - sections: [ - { - isSticky: true, - options: [ - { - content: ( -