feat: disallow collapsing sidebar when signposting is enabled (#24938)
This commit is contained in:
parent
3652e31f90
commit
3cedd9251f
|
|
@ -4,6 +4,7 @@ import {
|
|||
locators,
|
||||
draggableWidgets,
|
||||
installer,
|
||||
homePage,
|
||||
} from "../../../../support/Objects/ObjectsCore";
|
||||
|
||||
const ExplorerMenu = {
|
||||
|
|
@ -98,6 +99,7 @@ describe("Entity explorer tests related to pinning and unpinning", function () {
|
|||
});
|
||||
cy.get(locators._canvas).trigger("mousemove", 500, 400);
|
||||
agHelper.AssertElementVisible(entityExplorer._entityExplorer);
|
||||
entityExplorer.PinUnpinEntityExplorer(false);
|
||||
},
|
||||
);
|
||||
|
||||
|
|
@ -122,6 +124,21 @@ describe("Entity explorer tests related to pinning and unpinning", function () {
|
|||
});
|
||||
cy.get(locators._canvas).trigger("mousemove", 500, 400);
|
||||
agHelper.AssertElementVisible(entityExplorer._entityExplorer);
|
||||
entityExplorer.PinUnpinEntityExplorer(false);
|
||||
},
|
||||
);
|
||||
|
||||
it("5. Explorer should be visible by default on a new application", function () {
|
||||
agHelper.AssertElementVisible(entityExplorer._entityExplorer);
|
||||
entityExplorer.PinUnpinEntityExplorer(true);
|
||||
agHelper.GetElement(locators._canvas).trigger("mousemove", 500, 100, {
|
||||
force: true,
|
||||
});
|
||||
agHelper
|
||||
.GetElement(entityExplorer._entityExplorer)
|
||||
.should("not.be.visible");
|
||||
homePage.NavigateToHome();
|
||||
homePage.CreateNewApplication();
|
||||
agHelper.AssertElementVisible(entityExplorer._entityExplorer);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
36
app/client/src/pages/Editor/EditorHeader.test.tsx
Normal file
36
app/client/src/pages/Editor/EditorHeader.test.tsx
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
import React from "react";
|
||||
import EditorHeader from "./EditorHeader";
|
||||
import { render, screen } from "test/testUtils";
|
||||
import type { AppState } from "@appsmith/reducers";
|
||||
|
||||
function renderComponent(initialState?: Partial<AppState>) {
|
||||
render(<EditorHeader />, {
|
||||
initialState,
|
||||
});
|
||||
}
|
||||
|
||||
describe("EditorHeader", () => {
|
||||
it("Show sidebar nav button by default", () => {
|
||||
renderComponent();
|
||||
const wrapper = screen.queryAllByTestId("sidebar-nav-button");
|
||||
expect(wrapper.length).toBe(1);
|
||||
});
|
||||
it("sidebar nav button should be hidden when signposting is enabled", () => {
|
||||
const initialState: any = {
|
||||
entities: {
|
||||
pageList: {
|
||||
applicationId: "1",
|
||||
},
|
||||
},
|
||||
ui: {
|
||||
onBoarding: {
|
||||
firstTimeUserOnboardingApplicationIds: ["1"],
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
renderComponent(initialState);
|
||||
const wrapper = screen.queryAllByTestId("sidebar-nav-button");
|
||||
expect(wrapper.length).toBe(0);
|
||||
});
|
||||
});
|
||||
|
|
@ -1,7 +1,6 @@
|
|||
import React, { useCallback, useEffect, useState, lazy, Suspense } from "react";
|
||||
import styled, { ThemeProvider } from "styled-components";
|
||||
import classNames from "classnames";
|
||||
import type { ApplicationPayload } from "@appsmith/constants/ReduxActionConstants";
|
||||
import { ReduxActionTypes } from "@appsmith/constants/ReduxActionConstants";
|
||||
import { APPLICATIONS_URL } from "constants/routes";
|
||||
import AppInviteUsersForm from "pages/workspace/AppInviteUsersForm";
|
||||
|
|
@ -19,6 +18,7 @@ import {
|
|||
getAllUsers,
|
||||
getCurrentWorkspaceId,
|
||||
} from "@appsmith/selectors/workspaceSelectors";
|
||||
import type { ConnectedProps } from "react-redux";
|
||||
import { connect, useDispatch, useSelector } from "react-redux";
|
||||
import DeployLinkButtonDialog from "components/designSystems/appsmith/header/DeployLinkButton";
|
||||
import { updateApplication } from "@appsmith/actions/applicationActions";
|
||||
|
|
@ -29,7 +29,6 @@ import {
|
|||
} from "@appsmith/selectors/applicationSelectors";
|
||||
import EditorAppName from "./EditorAppName";
|
||||
import { getCurrentUser } from "selectors/usersSelectors";
|
||||
import type { User } from "constants/userConstants";
|
||||
import {
|
||||
EditInteractionKind,
|
||||
SavingState,
|
||||
|
|
@ -59,7 +58,6 @@ import { EditorSaveIndicator } from "./EditorSaveIndicator";
|
|||
|
||||
import { retryPromise } from "utils/AppsmithUtils";
|
||||
import { fetchUsersForWorkspace } from "@appsmith/actions/workspaceActions";
|
||||
import type { WorkspaceUser } from "@appsmith/constants/workspaceConstants";
|
||||
|
||||
import { getIsGitConnected } from "selectors/gitSyncSelectors";
|
||||
import {
|
||||
|
|
@ -92,6 +90,7 @@ import EmbedSnippetForm from "@appsmith/pages/Applications/EmbedSnippetTab";
|
|||
import { getAppsmithConfigs } from "@appsmith/configs";
|
||||
import { getIsAppSettingsPaneWithNavigationTabOpen } from "selectors/appSettingsPaneSelectors";
|
||||
import type { NavigationSetting } from "constants/AppConstants";
|
||||
import { getIsFirstTimeUserOnboardingEnabled } from "selectors/onboardingSelectors";
|
||||
|
||||
const { cloudHosting } = getAppsmithConfigs();
|
||||
|
||||
|
|
@ -195,23 +194,6 @@ const SidebarNavButton = styled(Button)`
|
|||
}
|
||||
`;
|
||||
|
||||
type EditorHeaderProps = {
|
||||
pageSaveError?: boolean;
|
||||
pageName?: string;
|
||||
pageId: string;
|
||||
isPublishing: boolean;
|
||||
publishedTime?: string;
|
||||
workspaceId: string;
|
||||
applicationId?: string;
|
||||
currentApplication?: ApplicationPayload;
|
||||
isSaving: boolean;
|
||||
publishApplication: (appId: string) => void;
|
||||
lastUpdatedTime?: number;
|
||||
inOnboarding: boolean;
|
||||
sharedUserList: WorkspaceUser[];
|
||||
currentUser?: User;
|
||||
};
|
||||
|
||||
const GlobalSearch = lazy(() => {
|
||||
return retryPromise(
|
||||
() =>
|
||||
|
|
@ -223,7 +205,10 @@ const GlobalSearch = lazy(() => {
|
|||
|
||||
const theme = getTheme(ThemeMode.LIGHT);
|
||||
|
||||
export function EditorHeader(props: EditorHeaderProps) {
|
||||
// Seperating redux props types from props being passed to the component from a parent
|
||||
type PropsFromRedux = ConnectedProps<typeof connector>;
|
||||
|
||||
export function EditorHeader(props: PropsFromRedux) {
|
||||
const {
|
||||
applicationId,
|
||||
currentApplication,
|
||||
|
|
@ -241,6 +226,7 @@ export function EditorHeader(props: EditorHeaderProps) {
|
|||
const isErroredSavingName = useSelector(getIsErroredSavingAppName);
|
||||
const applicationList = useSelector(getApplicationList);
|
||||
const isPreviewMode = useSelector(previewModeSelector);
|
||||
const signpostingEnabled = useSelector(getIsFirstTimeUserOnboardingEnabled);
|
||||
const deployLink = useHref(viewerURL, { pageId });
|
||||
const isAppSettingsPaneWithNavigationTabOpen = useSelector(
|
||||
getIsAppSettingsPaneWithNavigationTabOpen,
|
||||
|
|
@ -341,59 +327,68 @@ export function EditorHeader(props: EditorHeaderProps) {
|
|||
data-testid="t--appsmith-editor-header"
|
||||
>
|
||||
<HeaderSection className="space-x-2">
|
||||
<Tooltip
|
||||
content={
|
||||
<div className="flex items-center justify-between">
|
||||
<span>
|
||||
{!pinned
|
||||
? createMessage(LOCK_ENTITY_EXPLORER_MESSAGE)
|
||||
: createMessage(CLOSE_ENTITY_EXPLORER_MESSAGE)}
|
||||
</span>
|
||||
<span className="ml-4">{modText()} /</span>
|
||||
</div>
|
||||
}
|
||||
placement="bottomLeft"
|
||||
>
|
||||
<SidebarNavButton
|
||||
className={classNames({
|
||||
"transition-all transform duration-400": true,
|
||||
"-translate-x-full opacity-0": isPreviewingApp,
|
||||
"translate-x-0 opacity-100": !isPreviewingApp,
|
||||
})}
|
||||
kind="tertiary"
|
||||
onClick={onPin}
|
||||
size="md"
|
||||
{!signpostingEnabled && (
|
||||
<Tooltip
|
||||
content={
|
||||
<div className="flex items-center justify-between">
|
||||
<span>
|
||||
{!pinned
|
||||
? createMessage(LOCK_ENTITY_EXPLORER_MESSAGE)
|
||||
: createMessage(CLOSE_ENTITY_EXPLORER_MESSAGE)}
|
||||
</span>
|
||||
<span className="ml-4">{modText()} /</span>
|
||||
</div>
|
||||
}
|
||||
placement="bottomLeft"
|
||||
>
|
||||
<div
|
||||
className="t--pin-entity-explorer group relative"
|
||||
onMouseEnter={onMenuHover}
|
||||
<SidebarNavButton
|
||||
className={classNames({
|
||||
"transition-all transform duration-400": true,
|
||||
"-translate-x-full opacity-0": isPreviewingApp,
|
||||
"translate-x-0 opacity-100": !isPreviewingApp,
|
||||
})}
|
||||
data-testid="sidebar-nav-button"
|
||||
kind="tertiary"
|
||||
onClick={onPin}
|
||||
size="md"
|
||||
>
|
||||
<Icon
|
||||
className="absolute transition-opacity group-hover:opacity-0"
|
||||
name="hamburger"
|
||||
size="md"
|
||||
/>
|
||||
{pinned && (
|
||||
<div
|
||||
className="t--pin-entity-explorer group relative"
|
||||
onMouseEnter={onMenuHover}
|
||||
>
|
||||
<Icon
|
||||
className="absolute transition-opacity opacity-0 group-hover:opacity-100"
|
||||
name="menu-fold"
|
||||
onClick={onPin}
|
||||
className="absolute transition-opacity group-hover:opacity-0"
|
||||
name="hamburger"
|
||||
size="md"
|
||||
/>
|
||||
)}
|
||||
{!pinned && (
|
||||
<Icon
|
||||
className="absolute transition-opacity opacity-0 group-hover:opacity-100"
|
||||
name="menu-unfold"
|
||||
onClick={onPin}
|
||||
size="md"
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</SidebarNavButton>
|
||||
</Tooltip>
|
||||
{pinned && (
|
||||
<Icon
|
||||
className="absolute transition-opacity opacity-0 group-hover:opacity-100"
|
||||
name="menu-fold"
|
||||
onClick={onPin}
|
||||
size="md"
|
||||
/>
|
||||
)}
|
||||
{!pinned && (
|
||||
<Icon
|
||||
className="absolute transition-opacity opacity-0 group-hover:opacity-100"
|
||||
name="menu-unfold"
|
||||
onClick={onPin}
|
||||
size="md"
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</SidebarNavButton>
|
||||
</Tooltip>
|
||||
)}
|
||||
|
||||
<Tooltip content={createMessage(LOGO_TOOLTIP)} placement="bottomLeft">
|
||||
<AppsmithLink to={APPLICATIONS_URL}>
|
||||
<AppsmithLink
|
||||
className={classNames({
|
||||
"ml-2": signpostingEnabled,
|
||||
})}
|
||||
to={APPLICATIONS_URL}
|
||||
>
|
||||
<img
|
||||
alt="Appsmith logo"
|
||||
className="t--appsmith-logo"
|
||||
|
|
@ -575,4 +570,5 @@ EditorHeader.whyDidYouRender = {
|
|||
logOnDifferentValues: false,
|
||||
};
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(EditorHeader);
|
||||
const connector = connect(mapStateToProps, mapDispatchToProps);
|
||||
export default connector(EditorHeader);
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@ import { SelectionRequestType } from "sagas/WidgetSelectUtils";
|
|||
import * as widgetActions from "actions/widgetActions";
|
||||
import * as uiSelectors from "selectors/ui";
|
||||
import { NavigationMethod } from "../../../utils/history";
|
||||
import { setExplorerPinnedAction } from "actions/explorerActions";
|
||||
|
||||
jest.mock("constants/routes", () => {
|
||||
return {
|
||||
|
|
@ -531,3 +532,74 @@ describe("cmd + s hotkey", () => {
|
|||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("mod + / hotkey", () => {
|
||||
it("Should dispatch pin/unpin explorer on mod + /", async () => {
|
||||
const dispatchSpy = jest.spyOn(store, "dispatch");
|
||||
const component = render(
|
||||
<GlobalHotKeys
|
||||
getMousePosition={() => {
|
||||
return { x: 0, y: 0 };
|
||||
}}
|
||||
>
|
||||
<div />
|
||||
</GlobalHotKeys>,
|
||||
);
|
||||
dispatchSpy.mockClear();
|
||||
|
||||
dispatchTestKeyboardEventWithCode(
|
||||
component.container,
|
||||
"keydown",
|
||||
"/",
|
||||
191,
|
||||
false,
|
||||
true,
|
||||
);
|
||||
|
||||
expect(dispatchSpy).toBeCalledTimes(2);
|
||||
expect(dispatchSpy).toHaveBeenNthCalledWith(
|
||||
1,
|
||||
setExplorerPinnedAction(false),
|
||||
);
|
||||
});
|
||||
|
||||
it("Shouldn't dispatch pin/unpin explorer on mod + / when signposting is enabled", async () => {
|
||||
const dispatchSpy = jest.spyOn(store, "dispatch");
|
||||
const state: any = {
|
||||
entities: {
|
||||
pageList: {
|
||||
applicationId: "1",
|
||||
},
|
||||
},
|
||||
ui: {
|
||||
onBoarding: {
|
||||
firstTimeUserOnboardingApplicationIds: ["1"],
|
||||
},
|
||||
},
|
||||
};
|
||||
const component = render(
|
||||
<GlobalHotKeys
|
||||
getMousePosition={() => {
|
||||
return { x: 0, y: 0 };
|
||||
}}
|
||||
>
|
||||
<div />
|
||||
</GlobalHotKeys>,
|
||||
{
|
||||
initialState: state,
|
||||
},
|
||||
);
|
||||
dispatchSpy.mockClear();
|
||||
|
||||
dispatchTestKeyboardEventWithCode(
|
||||
component.container,
|
||||
"keydown",
|
||||
"/",
|
||||
191,
|
||||
false,
|
||||
true,
|
||||
);
|
||||
|
||||
expect(dispatchSpy).toBeCalledTimes(0);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -47,6 +47,7 @@ import { toggleInstaller } from "actions/JSLibraryActions";
|
|||
import { SelectionRequestType } from "sagas/WidgetSelectUtils";
|
||||
import { toast } from "design-system";
|
||||
import { showDebuggerFlag } from "selectors/debuggerSelectors";
|
||||
import { getIsFirstTimeUserOnboardingEnabled } from "selectors/onboardingSelectors";
|
||||
|
||||
type Props = {
|
||||
copySelectedWidget: () => void;
|
||||
|
|
@ -72,6 +73,7 @@ type Props = {
|
|||
isPreviewMode: boolean;
|
||||
setPreviewModeAction: (shouldSet: boolean) => void;
|
||||
isExplorerPinned: boolean;
|
||||
isSignpostingEnabled: boolean;
|
||||
setExplorerPinnedAction: (shouldPinned: boolean) => void;
|
||||
showCommitModal: () => void;
|
||||
getMousePosition: () => { x: number; y: number };
|
||||
|
|
@ -332,6 +334,7 @@ class GlobalHotKeys extends React.Component<Props> {
|
|||
/>
|
||||
<Hotkey
|
||||
combo="mod + /"
|
||||
disabled={this.props.isSignpostingEnabled}
|
||||
global
|
||||
label="Pin/Unpin Entity Explorer"
|
||||
onKeyDown={() => {
|
||||
|
|
@ -363,6 +366,7 @@ const mapStateToProps = (state: AppState) => ({
|
|||
appMode: getAppMode(state),
|
||||
isPreviewMode: previewModeSelector(state),
|
||||
isExplorerPinned: getExplorerPinned(state),
|
||||
isSignpostingEnabled: getIsFirstTimeUserOnboardingEnabled(state),
|
||||
});
|
||||
|
||||
const mapDispatchToProps = (dispatch: any) => {
|
||||
|
|
|
|||
|
|
@ -45,6 +45,10 @@ import { getSearchQuery, updateSlugNamesInURL } from "utils/helpers";
|
|||
import { generateAutoHeightLayoutTreeAction } from "actions/autoHeightActions";
|
||||
import { safeCrashAppRequest } from "../actions/errorActions";
|
||||
import { resetSnipingMode } from "actions/propertyPaneActions";
|
||||
import {
|
||||
setExplorerActiveAction,
|
||||
setExplorerPinnedAction,
|
||||
} from "actions/explorerActions";
|
||||
import {
|
||||
isEditorPath,
|
||||
isViewerPath,
|
||||
|
|
@ -132,6 +136,8 @@ function* resetEditorSaga() {
|
|||
// previously
|
||||
yield put(setPreviewModeAction(false));
|
||||
yield put(resetSnipingMode());
|
||||
yield put(setExplorerActiveAction(true));
|
||||
yield put(setExplorerPinnedAction(true));
|
||||
yield put(resetEditorSuccess());
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user