fix: side by side blank state, tooltip, and add button UI (#31479)

## Description

This PR fixes following issues
- JS and Query Blank state issue in side by side mode.
- Added tooltip for minimize and maximize button.
- Fixed add button getting squeezed issue.

#### PR fixes following issue(s)
Fixes https://github.com/appsmithorg/appsmith/issues/31330

#### Media


https://github.com/appsmithorg/appsmith/assets/87797149/e0e30e47-1f3a-447d-93a5-144e48360cec



#### Type of change

- Bug fix (non-breaking change which fixes an issue)
- New feature (non-breaking change which adds functionality)

## Testing
>
#### How Has This Been Tested?
> Please describe the tests that you ran to verify your changes. Also
list any relevant details for your test configuration.
> Delete anything that is not relevant
- [ ] Manual
- [ ] JUnit
- [ ] Jest
- [ ] Cypress
>
>
#### Test Plan
> Add Testsmith test cases links that relate to this PR
>
>
#### Issues raised during DP testing
> Link issues raised during DP testing for better visiblity and tracking
(copy link from comments dropped on this PR)
>
>
>
## Checklist:
#### Dev activity
- [x] My code follows the style guidelines of this project
- [x] I have performed a self-review of my own code
- [x] I have commented my code, particularly in hard-to-understand areas
- [ ] I have made corresponding changes to the documentation
- [x] My changes generate no new warnings
- [ ] I have added tests that prove my fix is effective or that my
feature works
- [x] New and existing unit tests pass locally with my changes
- [ ] PR is being merged under a feature flag


#### QA activity:
- [ ] [Speedbreak
features](https://github.com/appsmithorg/TestSmith/wiki/Guidelines-for-test-plans#speedbreakers-)
have been covered
- [ ] Test plan covers all impacted features and [areas of
interest](https://github.com/appsmithorg/TestSmith/wiki/Guidelines-for-test-plans#areas-of-interest-)
- [ ] Test plan has been peer reviewed by project stakeholders and other
QA members
- [ ] Manually tested functionality on DP
- [ ] We had an implementation alignment call with stakeholders post QA
Round 2
- [ ] Cypress test cases have been added and approved by SDET/manual QA
- [ ] Added `Test Plan Approved` label after Cypress tests were reviewed
- [ ] Added `Test Plan Approved` label after JUnit tests were reviewed


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

- **New Features**
- Introduced tooltips for maximize and minimize buttons in the editor
interface, enhancing user interaction.
- Added new empty state components for JavaScript actions and queries,
improving the user experience for adding new elements.
- Implemented split-screen empty states for both JavaScript actions and
queries, catering to users who prefer side-by-side editing.

- **Enhancements**
- Updated the editor's segmented header and full-screen tabs with
tooltips, providing clearer guidance on button functionalities.
- Adjusted the maximum width of tabs in the editor to accommodate
additional elements, ensuring a more organized display.

- **Refactor**
- Replaced the use of `EmptyState` with new `Empty` components in
JavaScript and Query editor panes, streamlining the interface and
aligning with new functionalities.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
albinAppsmith 2024-03-05 15:01:52 +05:30 committed by GitHub
parent 7258ab51c5
commit 46b4252ae6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
13 changed files with 162 additions and 47 deletions

View File

@ -2455,3 +2455,7 @@ export const HEADER_TITLES = {
export const PASTE_FAILED = (str: string): string => `Paste failed! ${str}`;
export const CREATE_A_NEW_ITEM = (item: string) => `Create a new ${item}`;
export const MAXIMIZE_BUTTON_TOOLTIP = () =>
`Expand code editor to full-screen`;
export const MINIMIZE_BUTTON_TOOLTIP = () => `Open code editor next to the UI`;

View File

@ -13,6 +13,7 @@ import JSEditor from "pages/Editor/JSEditor";
import AddJS from "pages/Editor/IDE/EditorPane/JS/Add";
import { ADD_PATH } from "@appsmith/constants/routes/appRoutes";
import ListJS from "pages/Editor/IDE/EditorPane/JS/List";
import { BlankStateContainer } from "pages/Editor/IDE/EditorPane/JS/BlankStateContainer";
export const useJSAdd = () => {
const pageId = useSelector(getCurrentPageId);
@ -56,6 +57,12 @@ export const useJSSegmentRoutes = (path: string): UseRoutes => {
component: JSEditor,
path: [path + "/:collectionId"],
},
{
key: "JSEmpty",
component: BlankStateContainer,
exact: true,
path: [path],
},
];
}
return [

View File

@ -34,6 +34,7 @@ import type { AppState } from "@appsmith/reducers";
import keyBy from "lodash/keyBy";
import { getPluginEntityIcon } from "pages/Editor/Explorer/ExplorerIcons";
import type { ListItemProps } from "design-system";
import { BlankStateContainer } from "pages/Editor/IDE/EditorPane/Query/BlankStateContainer";
export const useQueryAdd = () => {
const location = useLocation();
@ -96,6 +97,7 @@ export const useGroupedAddQueryOperations = (): GroupedAddOperations => {
export const useQuerySegmentRoutes = (path: string): UseRoutes => {
const isSideBySideEnabled = useSelector(getIsSideBySideEnabled);
const editorMode = useSelector(getIDEViewMode);
if (isSideBySideEnabled && editorMode === EditorViewMode.SplitScreen) {
return [
{
@ -130,6 +132,12 @@ export const useQuerySegmentRoutes = (path: string): UseRoutes => {
exact: true,
path: [path + "/:queryId"],
},
{
key: "QueryEmpty",
component: BlankStateContainer,
exact: true,
path: [path],
},
];
}
return [

View File

@ -0,0 +1,32 @@
import React from "react";
import { useSelector } from "react-redux";
import { EDITOR_PANE_TEXTS, createMessage } from "@appsmith/constants/messages";
import { getPagePermissions } from "selectors/editorSelectors";
import { useFeatureFlag } from "utils/hooks/useFeatureFlag";
import { getHasCreateActionPermission } from "@appsmith/utils/BusinessFeatures/permissionPageHelpers";
import { FEATURE_FLAG } from "@appsmith/entities/FeatureFlag";
import { useJSAdd } from "@appsmith/pages/Editor/IDE/EditorPane/JS/hooks";
import { EmptyState } from "../components/EmptyState";
const BlankState: React.FC = () => {
const pagePermissions = useSelector(getPagePermissions);
const isFeatureEnabled = useFeatureFlag(FEATURE_FLAG.license_gac_enabled);
const canCreateActions = getHasCreateActionPermission(
isFeatureEnabled,
pagePermissions,
);
const addButtonClickHandler = useJSAdd();
return (
<EmptyState
buttonClassName="t--add-item"
buttonText={createMessage(EDITOR_PANE_TEXTS.js_add_button)}
description={createMessage(EDITOR_PANE_TEXTS.js_blank_state_description)}
icon={"js-square-v3"}
onClick={canCreateActions ? addButtonClickHandler : undefined}
/>
);
};
export { BlankState };

View File

@ -0,0 +1,14 @@
import React from "react";
import { Flex } from "design-system";
import { BlankState } from "./BlankState";
const BlankStateContainer: React.FC = () => {
return (
<Flex flexDirection="column" gap="spaces-3" overflow="hidden" py="spaces-3">
<BlankState />
</Flex>
);
};
export { BlankStateContainer };

View File

@ -14,11 +14,11 @@ import { useFeatureFlag } from "utils/hooks/useFeatureFlag";
import { FEATURE_FLAG } from "@appsmith/entities/FeatureFlag";
import { getHasCreateActionPermission } from "@appsmith/utils/BusinessFeatures/permissionPageHelpers";
import { createMessage, EDITOR_PANE_TEXTS } from "@appsmith/constants/messages";
import { EmptyState } from "../components/EmptyState";
import { ActionParentEntityType } from "@appsmith/entities/Engine/actionHelpers";
import { FilesContextProvider } from "pages/Editor/Explorer/Files/FilesContextProvider";
import { useJSAdd } from "@appsmith/pages/Editor/IDE/EditorPane/JS/hooks";
import { JSListItem } from "@appsmith/pages/Editor/IDE/EditorPane/JS/ListItem";
import { BlankState } from "./BlankState";
const JSContainer = styled(Flex)`
& .t--entity-item {
@ -114,17 +114,7 @@ const ListJSObjects = () => {
</Flex>
</FilesContextProvider>
{(!jsList || jsList.length === 0) && (
<EmptyState
buttonClassName="t--add-item"
buttonText={createMessage(EDITOR_PANE_TEXTS.js_add_button)}
description={createMessage(
EDITOR_PANE_TEXTS.js_blank_state_description,
)}
icon={"js-square-v3"}
onClick={canCreateActions ? addButtonClickHandler : undefined}
/>
)}
{(!jsList || jsList.length === 0) && <BlankState />}
</JSContainer>
);
};

View File

@ -0,0 +1,34 @@
import React from "react";
import { useSelector } from "react-redux";
import { EDITOR_PANE_TEXTS, createMessage } from "@appsmith/constants/messages";
import { getHasCreateActionPermission } from "@appsmith/utils/BusinessFeatures/permissionPageHelpers";
import { getPagePermissions } from "selectors/editorSelectors";
import { useFeatureFlag } from "utils/hooks/useFeatureFlag";
import { FEATURE_FLAG } from "@appsmith/entities/FeatureFlag";
import { EmptyState } from "../components/EmptyState";
import { useQueryAdd } from "@appsmith/pages/Editor/IDE/EditorPane/Query/hooks";
const BlankState: React.FC = () => {
const pagePermissions = useSelector(getPagePermissions);
const isFeatureEnabled = useFeatureFlag(FEATURE_FLAG.license_gac_enabled);
const canCreateActions = getHasCreateActionPermission(
isFeatureEnabled,
pagePermissions,
);
const addButtonClickHandler = useQueryAdd();
return (
<EmptyState
buttonClassName="t--add-item"
buttonText={createMessage(EDITOR_PANE_TEXTS.query_add_button)}
description={createMessage(
EDITOR_PANE_TEXTS.query_blank_state_description,
)}
icon={"queries-v3"}
onClick={canCreateActions ? addButtonClickHandler : undefined}
/>
);
};
export { BlankState };

View File

@ -0,0 +1,20 @@
import React from "react";
import { Flex } from "design-system";
import { BlankState } from "./BlankState";
const BlankStateContainer: React.FC = () => {
return (
<Flex
flex="1"
flexDirection="column"
gap="spaces-3"
overflow="hidden"
py="spaces-3"
>
<BlankState />
</Flex>
);
};
export { BlankStateContainer };

View File

@ -15,10 +15,10 @@ import { selectQuerySegmentEditorList } from "@appsmith/selectors/appIDESelector
import { ActionParentEntityType } from "@appsmith/entities/Engine/actionHelpers";
import { FilesContextProvider } from "pages/Editor/Explorer/Files/FilesContextProvider";
import { createMessage, EDITOR_PANE_TEXTS } from "@appsmith/constants/messages";
import { EmptyState } from "../components/EmptyState";
import { useQueryAdd } from "@appsmith/pages/Editor/IDE/EditorPane/Query/hooks";
import { QueryListItem } from "@appsmith/pages/Editor/IDE/EditorPane/Query/ListItem";
import { getShowWorkflowFeature } from "@appsmith/selectors/workflowSelectors";
import { BlankState } from "./BlankState";
const ListQuery = () => {
const pageId = useSelector(getCurrentPageId) as string;
@ -98,17 +98,7 @@ const ListQuery = () => {
})}
</Flex>
{Object.keys(files).length === 0 && (
<EmptyState
buttonClassName="t--add-item"
buttonText={createMessage(EDITOR_PANE_TEXTS.query_add_button)}
description={createMessage(
EDITOR_PANE_TEXTS.query_blank_state_description,
)}
icon={"queries-v3"}
onClick={canCreateActions ? addButtonClickHandler : undefined}
/>
)}
{Object.keys(files).length === 0 && <BlankState />}
</Flex>
);
};

View File

@ -1,6 +1,10 @@
import React from "react";
import { Button, Flex, SegmentedControl } from "design-system";
import { createMessage, EDITOR_PANE_TEXTS } from "@appsmith/constants/messages";
import { Button, Flex, SegmentedControl, Tooltip } from "design-system";
import {
createMessage,
EDITOR_PANE_TEXTS,
MAXIMIZE_BUTTON_TOOLTIP,
} from "@appsmith/constants/messages";
import {
EditorEntityTab,
EditorViewMode,
@ -82,15 +86,17 @@ const SegmentedHeader = () => {
{isSideBySideEnabled &&
editorMode === EditorViewMode.SplitScreen &&
segment !== EditorEntityTab.UI ? (
<Button
id="editor-mode-maximize"
isIconButton
kind="tertiary"
onClick={() =>
dispatch(setIdeEditorViewMode(EditorViewMode.FullScreen))
}
startIcon="maximize-v3"
/>
<Tooltip content={createMessage(MAXIMIZE_BUTTON_TOOLTIP)}>
<Button
id="editor-mode-maximize"
isIconButton
kind="tertiary"
onClick={() =>
dispatch(setIdeEditorViewMode(EditorViewMode.FullScreen))
}
startIcon="maximize-v3"
/>
</Tooltip>
) : null}
</Container>
);

View File

@ -1,6 +1,6 @@
import React, { useCallback } from "react";
import { useDispatch, useSelector } from "react-redux";
import { Button } from "design-system";
import { Button, Tooltip } from "design-system";
import { getIDEViewMode, getIsSideBySideEnabled } from "selectors/ideSelectors";
import type { EntityItem } from "@appsmith/entities/IDE/constants";
import {
@ -14,6 +14,10 @@ import { useCurrentEditorState } from "../hooks";
import { getCurrentPageId } from "@appsmith/selectors/entitiesSelector";
import history, { NavigationMethod } from "utils/history";
import { TabSelectors } from "./constants";
import {
MINIMIZE_BUTTON_TOOLTIP,
createMessage,
} from "@appsmith/constants/messages";
const FullScreenTabs = () => {
const dispatch = useDispatch();
@ -44,13 +48,18 @@ const FullScreenTabs = () => {
return (
<Container>
<FileTabs navigateToTab={onClick} tabs={files} />
<Button
id="editor-mode-minimize"
isIconButton
kind="tertiary"
onClick={setSplitScreenMode}
startIcon="minimize-v3"
/>
<Tooltip
content={createMessage(MINIMIZE_BUTTON_TOOLTIP)}
placement="bottomRight"
>
<Button
id="editor-mode-minimize"
isIconButton
kind="tertiary"
onClick={setSplitScreenMode}
startIcon="minimize-v3"
/>
</Tooltip>
</Container>
);
};

View File

@ -54,7 +54,7 @@ const SplitScreenTabs = () => {
if (!isSideBySideEnabled) return null;
if (ideViewMode === EditorViewMode.FullScreen) return null;
if (segment === EditorEntityTab.UI) return null;
return (
return files.length > 0 ? (
<Container>
<Button
isIconButton
@ -65,7 +65,7 @@ const SplitScreenTabs = () => {
<FileTabs navigateToTab={onClick} tabs={files} />
<ListButton items={overflowList} navigateToTab={onClick} />
</Container>
);
) : null;
};
export default SplitScreenTabs;

View File

@ -11,8 +11,9 @@ import { DEFAULT_SPLIT_SCREEN_WIDTH } from "constants/AppConstants";
* 4px gap between every tabs * 4 (since max tab count is 5,
* there will be 5 gaps)
* 26px Add button width
* 62px show more list button(considering 3 digit width as max)
* ======================================
* 54px
* 116px
*
*/
export const StyledTab = styled(Flex)`
@ -28,7 +29,7 @@ export const StyledTab = styled(Flex)`
border-top-right-radius: var(--ads-v2-border-radius);
align-items: center;
justify-content: center;
max-width: calc((${DEFAULT_SPLIT_SCREEN_WIDTH} - 54px) / 5);
max-width: calc((${DEFAULT_SPLIT_SCREEN_WIDTH} - 116px) / 5);
// After element - the seperator in between tabs
&:not(&.active):not(:has(+ .active)):not(:last-child):after {