import React from "react"; import { Link, useLocation } from "react-router-dom"; 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 { EDIT_APP, FORK_APP, SIGN_IN } from "constants/messages"; import { isPermitted, PERMISSION_TYPE, } from "pages/Applications/permissionHelpers"; import { ApplicationPayload, PageListPayload, } from "constants/ReduxActionConstants"; import { APPLICATIONS_URL, AUTH_LOGIN_URL, SIGN_UP_URL, } from "constants/routes"; import { connect } from "react-redux"; import { AppState } from "reducers"; import { getEditorURL } from "selectors/appViewSelectors"; import { getPageList } from "selectors/editorSelectors"; import { FormDialogComponent } from "components/editorComponents/form/FormDialogComponent"; import AppInviteUsersForm from "pages/organization/AppInviteUsersForm"; import { getCurrentOrgId } from "selectors/organizationSelectors"; import { getCurrentUser } from "selectors/usersSelectors"; import { ANONYMOUS_USERNAME, User } from "constants/userConstants"; import Text, { TextType } from "components/ads/Text"; import { Classes } from "components/ads/common"; import { getTypographyByKey, Theme } from "constants/DefaultTheme"; import { IconWrapper } from "components/ads/Icon"; import Button, { Size } from "components/ads/Button"; import ProfileDropdown from "pages/common/ProfileDropdown"; import { Profile } from "pages/common/ProfileImage"; import PageTabsContainer from "./PageTabsContainer"; import { getThemeDetails, ThemeMode } from "selectors/themeSelectors"; const HeaderWrapper = styled(StyledHeader)<{ hasPages: boolean }>` box-shadow: unset; height: unset; padding: 0; background-color: ${(props) => props.theme.colors.header.background}; color: white; flex-direction: column; .${Classes.TEXT} { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; ${(props) => getTypographyByKey(props, "h4")} color: ${(props) => props.theme.colors.header.appName}; } & .header__application-share-btn { background-color: ${(props) => props.theme.colors.header.background}; border-color: ${(props) => props.theme.colors.header.background}; color: ${(props) => props.theme.colors.header.shareBtn}; ${IconWrapper} path { fill: ${(props) => props.theme.colors.header.shareBtn}; } } & .header__application-share-btn:hover { color: ${(props) => props.theme.colors.header.shareBtnHighlight}; ${IconWrapper} path { fill: ${(props) => props.theme.colors.header.shareBtnHighlight}; } } & ${Profile} { width: 24px; height: 24px; } & .current-app-name { overflow: auto; } `; const HeaderRow = styled.div<{ justify: string }>` width: 100%; display: flex; flex: 1; flex-direction: row; justify-content: ${(props) => props.justify}; height: ${(props) => `calc(${props.theme.smallHeaderHeight})`}; border-bottom: 1px solid ${(props) => props.theme.colors.header.tabsHorizontalSeparator}; `; const HeaderSection = styled.div<{ justify: string }>` display: flex; flex: 1; align-items: center; justify-content: ${(props) => props.justify}; `; const AppsmithLogoImg = styled.img` padding-left: ${(props) => props.theme.spaces[7]}px; max-width: 110px; `; const Cta = styled(Button)` ${(props) => getTypographyByKey(props, "btnLarge")} height: 100%; `; const ForkButton = styled(Cta)` svg { transform: rotate(-90deg); } `; const HeaderRightItemContainer = styled.div` display: flex; align-items: center; margin-right: ${(props) => props.theme.spaces[7]}px; height: 100%; `; type AppViewerHeaderProps = { url?: string; currentApplicationDetails?: ApplicationPayload; pages: PageListPayload; currentOrgId: string; currentUser?: User; lightTheme: Theme; }; export const AppViewerHeader = (props: AppViewerHeaderProps) => { const { currentApplicationDetails, pages, currentOrgId, currentUser } = props; const isExampleApp = currentApplicationDetails?.appIsExample; const userPermissions = currentApplicationDetails?.userPermissions ?? []; const permissionRequired = PERMISSION_TYPE.MANAGE_APPLICATION; const canEdit = isPermitted(userPermissions, permissionRequired); const { search } = useLocation(); const queryParams = new URLSearchParams(search); const isEmbed = queryParams.get("embed"); const hideHeader = !!isEmbed; const HtmlTitle = () => { if (!currentApplicationDetails?.name) return null; return ( {currentApplicationDetails?.name} ); }; if (hideHeader) return ; const forkAppUrl = `${window.location.origin}${SIGN_UP_URL}?appId=${currentApplicationDetails?.id}`; const loginAppUrl = `${window.location.origin}${AUTH_LOGIN_URL}?appId=${currentApplicationDetails?.id}`; let CTA = null; if (props.url && canEdit) { CTA = ( ); } else if (isExampleApp) { CTA = ( ); } else if ( currentApplicationDetails?.isPublic && currentUser?.username === ANONYMOUS_USERNAME ) { CTA = ; } return ( 1}> {currentApplicationDetails && ( {currentApplicationDetails.name} )} {currentApplicationDetails && ( <> } Form={AppInviteUsersForm} orgId={currentOrgId} applicationId={currentApplicationDetails.id} title={currentApplicationDetails.name} canOutsideClickClose={true} /> {CTA && ( {CTA} )} )} {currentUser && currentUser.username !== ANONYMOUS_USERNAME && ( 1 ? 35 : 0}`, }, }} /> )} ); }; const mapStateToProps = (state: AppState): AppViewerHeaderProps => ({ pages: getPageList(state), url: getEditorURL(state), currentApplicationDetails: state.ui.applications.currentApplication, currentOrgId: getCurrentOrgId(state), currentUser: getCurrentUser(state), lightTheme: getThemeDetails(state, ThemeMode.LIGHT), }); export default connect(mapStateToProps)(AppViewerHeader);