Fix edit and fork buttons visible simultaneously on the viewer header (#3723)

This commit is contained in:
Rishabh Saxena 2021-04-08 14:12:13 +05:30 committed by GitHub
parent c37adc0a4d
commit d8f2211b70
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 228 additions and 59 deletions

View File

@ -4,7 +4,6 @@ import { Helmet } from "react-helmet";
import styled, { ThemeProvider } from "styled-components";
import StyledHeader from "components/designSystems/appsmith/StyledHeader";
import AppsmithLogo from "assets/images/appsmith_logo.png";
import { createMessage, EDIT_APP, FORK_APP, SIGN_IN } from "constants/messages";
import {
isPermitted,
PERMISSION_TYPE,
@ -33,7 +32,7 @@ import ProfileDropdown from "pages/common/ProfileDropdown";
import { Profile } from "pages/common/ProfileImage";
import PageTabsContainer from "./PageTabsContainer";
import { getThemeDetails, ThemeMode } from "selectors/themeSelectors";
import ForkApplicationModal from "pages/Applications/ForkApplicationModal";
import getAppViewerHeaderCTA from "./getAppViewerHeaderCTA";
const HeaderWrapper = styled(StyledHeader)<{ hasPages: boolean }>`
box-shadow: unset;
@ -107,17 +106,6 @@ const AppsmithLogoImg = styled.img`
max-width: 110px;
`;
const Cta = styled(Button)`
${(props) => getTypographyByKey(props, "btnLarge")}
height: 100%;
`;
const ForkButton = styled(Cta)`
svg {
transform: rotate(-90deg);
}
height: ${(props) => `calc(${props.theme.smallHeaderHeight})`};
`;
const HeaderRightItemContainer = styled.div`
display: flex;
align-items: center;
@ -162,42 +150,14 @@ export const AppViewerHeader = (props: AppViewerHeaderProps) => {
const forkUrl = `${AUTH_LOGIN_URL}?redirectUrl=${window.location.href}/fork`;
const loginUrl = `${AUTH_LOGIN_URL}?redirectUrl=${window.location.href}`;
let CTA = null;
if (props.url && canEdit) {
CTA = (
<Cta
className="t--back-to-editor"
href={props.url}
icon="arrow-left"
text={createMessage(EDIT_APP)}
/>
);
} else if (
currentApplicationDetails?.forkingEnabled &&
currentApplicationDetails?.isPublic &&
currentUser?.username === ANONYMOUS_USERNAME
) {
CTA = (
<ForkButton
className="t--fork-app"
href={forkUrl}
text={createMessage(FORK_APP)}
icon="fork"
/>
);
} else if (
currentApplicationDetails?.isPublic &&
currentUser?.username === ANONYMOUS_USERNAME
) {
CTA = (
<Cta
className="t--sign-in"
href={loginUrl}
text={createMessage(SIGN_IN)}
/>
);
}
const CTA = getAppViewerHeaderCTA({
url: props.url,
canEdit,
currentApplicationDetails,
currentUser,
forkUrl,
loginUrl,
});
return (
<ThemeProvider theme={props.lightTheme}>
@ -232,15 +192,6 @@ export const AppViewerHeader = (props: AppViewerHeaderProps) => {
title={currentApplicationDetails.name}
canOutsideClickClose={true}
/>
{currentUser &&
currentUser.username !== ANONYMOUS_USERNAME &&
currentApplicationDetails?.forkingEnabled && (
<div className="header__application-fork-btn-wrapper">
<ForkApplicationModal
applicationId={currentApplicationDetails.id}
/>
</div>
)}
{CTA && (
<HeaderRightItemContainer>{CTA}</HeaderRightItemContainer>
)}

View File

@ -0,0 +1,143 @@
import { unmountComponentAtNode } from "react-dom";
import { render } from "test/testUtils";
import getAppViewerHeaderCTA from "./getAppViewerHeaderCTA";
import { waitFor } from "@testing-library/dom";
import { ANONYMOUS_USERNAME } from "constants/userConstants";
const sampleProps = {
url:
"/applications/606ad816c7a35467ac887f87/pages/606ad816c7a35467ac887f89/edit",
canEdit: true,
currentApplicationDetails: {
id: "606ad816c7a35467ac887f87",
userPermissions: [
"manage:applications",
"canComment:applications",
"read:applications",
"publish:applications",
"makePublic:applications",
],
name: "Untitled application 1",
organizationId: "606ad7eec7a35467ac887f84",
isPublic: false,
pages: [
{
id: "606ad816c7a35467ac887f89",
isDefault: true,
default: true,
},
],
appIsExample: false,
color: "#C03C3C",
icon: "flag",
new: false,
},
currentUser: {
userPermissions: [],
email: "b1@appsmith.com",
source: "FORM",
isEnabled: true,
currentOrganizationId: "606ad7eec7a35467ac887f84",
organizationIds: ["606ad7eec7a35467ac887f84"],
groupIds: [],
permissions: [],
isAnonymous: false,
username: "b1@appsmith.com",
accountNonExpired: true,
accountNonLocked: true,
credentialsNonExpired: true,
claims: {},
enabled: true,
address: {},
new: true,
},
forkUrl:
"/user/login?redirectUrl=https://dev.appsmith.com/applications/606ad816c7a35467ac887f87/pages/606ad816c7a35467ac887f89/fork",
loginUrl:
"/user/login?redirectUrl=https://dev.appsmith.com/applications/606ad816c7a35467ac887f87/pages/606ad816c7a35467ac887f89",
};
let container: any = null;
describe("get app viewer header CTA", () => {
beforeEach(async () => {
// setup a DOM element as a render target
container = document.createElement("div");
document.body.appendChild(container);
});
it("renders the edit app button and does not render the fork app button", async () => {
const CTA = getAppViewerHeaderCTA(sampleProps);
if (CTA) {
render(CTA);
const result = await waitFor(() =>
document.querySelector(".t--back-to-editor"),
);
expect(!!result).toBeTruthy();
const forkButton = await waitFor(() =>
document.querySelector(".t--fork-app"),
);
expect(!!forkButton).toBeFalsy();
}
});
it("renders the fork app button", async () => {
const CTA = getAppViewerHeaderCTA({
...sampleProps,
canEdit: false,
currentApplicationDetails: {
...sampleProps.currentApplicationDetails,
forkingEnabled: true,
isPublic: true,
},
currentUser: {
...sampleProps.currentUser,
username: ANONYMOUS_USERNAME,
},
});
if (CTA) {
render(CTA);
const result = await waitFor(() =>
document.querySelector(".t--fork-app"),
);
expect(!!result).toBeTruthy();
}
});
it("renders the fork app link", async () => {
const CTA = getAppViewerHeaderCTA({
...sampleProps,
canEdit: false,
currentApplicationDetails: {
...sampleProps.currentApplicationDetails,
forkingEnabled: true,
isPublic: true,
},
});
if (CTA) {
render(CTA);
const result = await waitFor(() =>
document.querySelector(".t--fork-btn-wrapper"),
);
expect(!!result).toBeTruthy();
}
});
it("renders the sign in link", async () => {
const CTA = getAppViewerHeaderCTA({
...sampleProps,
canEdit: false,
currentApplicationDetails: {
...sampleProps.currentApplicationDetails,
isPublic: true,
},
});
if (CTA) {
render(CTA);
const result = await waitFor(() => document.querySelector(".t--sign-in"));
expect(!!result).toBeTruthy();
}
});
afterEach(() => {
// cleanup on exiting
unmountComponentAtNode(container);
container.remove();
container = null;
});
});

View File

@ -0,0 +1,76 @@
import React from "react";
import styled from "styled-components";
import { createMessage, EDIT_APP, FORK_APP, SIGN_IN } from "constants/messages";
import { ANONYMOUS_USERNAME } from "constants/userConstants";
import { getTypographyByKey } from "constants/DefaultTheme";
import Button from "components/ads/Button";
import ForkApplicationModal from "pages/Applications/ForkApplicationModal";
const Cta = styled(Button)`
${(props) => getTypographyByKey(props, "btnLarge")}
height: 100%;
`;
const ForkButton = styled(Cta)`
svg {
transform: rotate(-90deg);
}
height: ${(props) => `calc(${props.theme.smallHeaderHeight})`};
`;
const getAppViewerHeaderCTA = ({
url,
canEdit,
currentApplicationDetails,
currentUser,
forkUrl,
loginUrl,
}: any) => {
let CTA = null;
if (url && canEdit) {
CTA = (
<Cta
className="t--back-to-editor"
href={url}
icon="arrow-left"
text={createMessage(EDIT_APP)}
/>
);
} else if (
currentApplicationDetails?.forkingEnabled &&
currentApplicationDetails?.isPublic
) {
if (currentUser?.username === ANONYMOUS_USERNAME) {
CTA = (
<ForkButton
className="t--fork-app"
href={forkUrl}
text={createMessage(FORK_APP)}
icon="fork"
/>
);
} else {
CTA = (
<div className="header__application-fork-btn-wrapper t--fork-btn-wrapper">
<ForkApplicationModal applicationId={currentApplicationDetails.id} />
</div>
);
}
} else if (
currentApplicationDetails?.isPublic &&
currentUser?.username === ANONYMOUS_USERNAME
) {
CTA = (
<Cta
className="t--sign-in"
href={loginUrl}
text={createMessage(SIGN_IN)}
/>
);
}
return CTA;
};
export default getAppViewerHeaderCTA;

View File

@ -29,7 +29,6 @@ const TriggerButton = styled(Button)`
svg {
transform: rotate(-90deg);
}
margin-right: ${(props) => props.theme.spaces[7]}px;
`;
const StyledDialog = styled(Dialog)`