chore: Visual changes for core navigation elements on IDE (#37880)
## Description Updates a few visual elements for better Navigational experience using the Segmented Controls Fixes #37881 ## Automation /ok-to-test tags="@tag.IDE, @tag.Sanity" ### 🔍 Cypress test results <!-- This is an auto-generated comment: Cypress test results --> > [!TIP] > 🟢 🟢 🟢 All cypress tests have passed! 🎉 🎉 🎉 > Workflow run: <https://github.com/appsmithorg/appsmith/actions/runs/12409098657> > Commit: a94e072ab76b5a1146f25dd822576c6b01e57c1e > <a href="https://internal.appsmith.com/app/cypress-dashboard/rundetails-65890b3c81d7400d08fa9ee5?branch=master&workflowId=12409098657&attempt=3" target="_blank">Cypress dashboard</a>. > Tags: `@tag.IDE, @tag.Sanity` > Spec: > <hr>Thu, 19 Dec 2024 12:51:29 UTC <!-- end of auto-generated comment: Cypress test results --> ## Communication Should the DevRel and Marketing teams inform users about this change? - [ ] Yes - [ ] No <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit ## Release Notes - **New Features** - Added `testId` property to sidebar buttons for enhanced testing capabilities. - Updated button titles from "Data" to "Datasources" for clarity. - Introduced `BottomButtons` configuration for sidebar buttons based on data source availability. - **Bug Fixes** - Improved visual distinction of selected segments in the Segmented Control. - **Style** - Enhanced styling for sidebar buttons and segments, including hover effects and separators. - **Tests** - Added tests to verify rendering of sidebar buttons with the correct test IDs. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
parent
4a91204e4d
commit
1ade47d31a
|
|
@ -6,11 +6,12 @@ import { LeftPane } from "./IDE/LeftPane";
|
|||
import PageList from "./PageList";
|
||||
|
||||
export enum AppSidebarButton {
|
||||
Data = "Data",
|
||||
Data = "Datasources",
|
||||
Editor = "Editor",
|
||||
Libraries = "Libraries",
|
||||
Settings = "Settings",
|
||||
}
|
||||
|
||||
export const AppSidebar = new Sidebar(Object.values(AppSidebarButton));
|
||||
|
||||
export enum PagePaneSegment {
|
||||
|
|
@ -42,6 +43,7 @@ export enum EntityType {
|
|||
JSObject = "JSObject",
|
||||
Page = "Page",
|
||||
}
|
||||
|
||||
class EditorNavigation {
|
||||
public locators = {
|
||||
MaximizeBtn: "[data-testid='t--ide-maximize']",
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ export class Sidebar {
|
|||
buttons: string[];
|
||||
locators = {
|
||||
sidebar: ".t--sidebar",
|
||||
sidebarButton: (name: string) => `.t--sidebar-${name}`,
|
||||
sidebarButton: (name: string) => `[data-testid='t--sidebar-${name}']`,
|
||||
};
|
||||
|
||||
constructor(buttons: string[]) {
|
||||
|
|
|
|||
|
|
@ -41,6 +41,12 @@ export const StyledSegment = styled.span`
|
|||
& > * {
|
||||
color: var(--ads-v2-colors-control-segment-value-default-fg);
|
||||
}
|
||||
|
||||
&[data-selected="true"] {
|
||||
span {
|
||||
font-weight: var(--ads-v2-font-weight-bold);
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export const StyledControlContainer = styled.div`
|
||||
|
|
@ -81,6 +87,7 @@ export const StyledControlContainer = styled.div`
|
|||
|
||||
/* Select all segments which is not a selected and last child */
|
||||
/* seperator */
|
||||
|
||||
&:not(:hover):not(:last-child):not([data-selected="true"]):not(
|
||||
:has(+ [data-selected="true"])
|
||||
):after {
|
||||
|
|
|
|||
|
|
@ -1,3 +1,6 @@
|
|||
<svg width="13" height="12" viewBox="0 0 13 12" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M7.16667 12V5.33333H12.5V12H7.16667ZM0.5 6.66667V0H5.83333V6.66667H0.5ZM4.5 5.33333V1.33333H1.83333V5.33333H4.5ZM0.5 12V8H5.83333V12H0.5ZM1.83333 10.6667H4.5V9.33333H1.83333V10.6667ZM8.5 10.6667H11.1667V6.66667H8.5V10.6667ZM7.16667 0H12.5V4H7.16667V0ZM8.5 1.33333V2.66667H11.1667V1.33333H8.5Z" fill="#4C5664"/>
|
||||
<svg width="15" height="16" viewBox="0 0 15 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M7.67353 13.8542V7.25693H12.3958V13.8542H7.67353ZM1.77075 8.57638V1.97916H6.49297V8.57638H1.77075ZM5.31242 7.25693V3.2986H2.95131V7.25693H5.31242ZM1.77075 13.8542V9.89582H6.49297V13.8542H1.77075ZM2.95131 12.5347H5.31242V11.2153H2.95131V12.5347ZM8.85409 12.5347H11.2152V8.57638H8.85409V12.5347ZM7.67353 1.97916H12.3958V5.93749H7.67353V1.97916ZM8.85409 3.2986V4.61805H11.2152V3.2986H8.85409Z"
|
||||
fill="currentColor"/>
|
||||
</svg>
|
||||
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 423 B After Width: | Height: | Size: 536 B |
|
|
@ -44,6 +44,7 @@ function IDESidebar(props: IDESidebarProps) {
|
|||
key={button.state}
|
||||
onClick={onClick}
|
||||
selected={editorState === button.state}
|
||||
testId={button.testId}
|
||||
title={button.title}
|
||||
tooltip={button.tooltip}
|
||||
urlSuffix={button.urlSuffix}
|
||||
|
|
@ -58,6 +59,7 @@ function IDESidebar(props: IDESidebarProps) {
|
|||
key={button.state}
|
||||
onClick={onClick}
|
||||
selected={editorState === button.state}
|
||||
testId={button.testId}
|
||||
title={button.title}
|
||||
tooltip={button.tooltip}
|
||||
urlSuffix={button.urlSuffix}
|
||||
|
|
|
|||
|
|
@ -11,9 +11,16 @@ const sidebarButtonProps: SidebarButtonProps = {
|
|||
selected: false,
|
||||
title: "Test",
|
||||
urlSuffix: "/test",
|
||||
testId: "testId",
|
||||
};
|
||||
|
||||
describe("SidebarButton", () => {
|
||||
it("should render the button with the correct test id", () => {
|
||||
const { getByTestId } = render(<SidebarButton {...sidebarButtonProps} />);
|
||||
|
||||
expect(getByTestId("t--sidebar-testId")).toBeDefined();
|
||||
});
|
||||
|
||||
it("should render the warning icon in case the datasource list is empty", () => {
|
||||
const withWarningCondition = {
|
||||
...sidebarButtonProps,
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ const ConditionConfig: Record<Condition, { icon: string; color: string }> = {
|
|||
|
||||
export interface SidebarButtonProps {
|
||||
title?: string;
|
||||
testId: string;
|
||||
selected: boolean;
|
||||
icon: string;
|
||||
onClick: (urlSuffix: string) => void;
|
||||
|
|
@ -33,10 +34,8 @@ const Container = styled(Flex)`
|
|||
padding: 8px 0;
|
||||
`;
|
||||
|
||||
const IconContainer = styled.div<{ selected: boolean }>`
|
||||
const IconContainer = styled.div`
|
||||
padding: 2px;
|
||||
background-color: ${(props) =>
|
||||
props.selected ? "var(--colors-raw-orange-100, #fbe6dc)" : "white"};
|
||||
border-radius: 3px;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
|
|
@ -46,11 +45,16 @@ const IconContainer = styled.div<{ selected: boolean }>`
|
|||
cursor: pointer;
|
||||
position: relative;
|
||||
|
||||
&:hover {
|
||||
background: ${(props) =>
|
||||
props.selected
|
||||
? "var(--colors-raw-orange-100, #fbe6dc)"
|
||||
: "var(--ads-v2-color-bg-subtle, #f1f5f9);"};
|
||||
&[data-selected="false"] {
|
||||
background-color: var(--ads-v2-color-bg);
|
||||
|
||||
&:hover {
|
||||
background-color: var(--ads-v2-color-bg-subtle, #f1f5f9);
|
||||
}
|
||||
}
|
||||
|
||||
&[data-selected="true"] {
|
||||
background-color: var(--ads-v2-color-bg-muted);
|
||||
}
|
||||
`;
|
||||
|
||||
|
|
@ -85,9 +89,9 @@ function SidebarButton(props: SidebarButtonProps) {
|
|||
<IconContainer
|
||||
className={`t--sidebar-${title || tooltip}`}
|
||||
data-selected={selected}
|
||||
data-testid={"t--sidebar-" + props.testId}
|
||||
onClick={handleOnClick}
|
||||
role="button"
|
||||
selected={selected}
|
||||
>
|
||||
<Icon name={icon} size="lg" />
|
||||
{condition && (
|
||||
|
|
|
|||
|
|
@ -31,11 +31,11 @@ export enum EditorState {
|
|||
}
|
||||
|
||||
export const SidebarTopButtonTitles = {
|
||||
DATA: "Data",
|
||||
EDITOR: "Editor",
|
||||
};
|
||||
|
||||
export const SidebarBottomButtonTitles = {
|
||||
DATA: "Datasources",
|
||||
SETTINGS: "Settings",
|
||||
LIBRARIES: "Libraries",
|
||||
};
|
||||
|
|
@ -62,27 +62,31 @@ export const TopButtons: IDESidebarButton[] = [
|
|||
state: EditorState.EDITOR,
|
||||
icon: "editor-v3",
|
||||
title: SidebarTopButtonTitles.EDITOR,
|
||||
testId: SidebarTopButtonTitles.EDITOR,
|
||||
urlSuffix: "",
|
||||
},
|
||||
{
|
||||
state: EditorState.DATA,
|
||||
icon: "datasource-v3",
|
||||
title: SidebarTopButtonTitles.DATA,
|
||||
urlSuffix: "datasource",
|
||||
},
|
||||
];
|
||||
|
||||
export const BottomButtons: IDESidebarButton[] = [
|
||||
{
|
||||
state: EditorState.DATA,
|
||||
icon: "datasource-v3",
|
||||
tooltip: SidebarBottomButtonTitles.DATA,
|
||||
testId: SidebarBottomButtonTitles.DATA,
|
||||
urlSuffix: "datasource",
|
||||
},
|
||||
{
|
||||
state: EditorState.LIBRARIES,
|
||||
icon: "packages-v3",
|
||||
tooltip: SidebarBottomButtonTitles.LIBRARIES,
|
||||
testId: SidebarBottomButtonTitles.LIBRARIES,
|
||||
urlSuffix: "libraries",
|
||||
},
|
||||
{
|
||||
state: EditorState.SETTINGS,
|
||||
icon: "settings-v3",
|
||||
tooltip: SidebarBottomButtonTitles.SETTINGS,
|
||||
testId: SidebarBottomButtonTitles.SETTINGS,
|
||||
urlSuffix: "settings",
|
||||
},
|
||||
];
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import React from "react";
|
||||
import React, { useMemo } from "react";
|
||||
import { createMessage, EDITOR_PANE_TEXTS } from "ee/constants/messages";
|
||||
import { EditorEntityTab } from "ee/entities/IDE/constants";
|
||||
import { useCurrentEditorState, useSegmentNavigation } from "../../hooks";
|
||||
|
|
@ -8,23 +8,30 @@ const SegmentSwitcher = () => {
|
|||
const { segment } = useCurrentEditorState();
|
||||
const { onSegmentChange } = useSegmentNavigation();
|
||||
|
||||
const segmentOptions = useMemo(() => {
|
||||
return [
|
||||
{
|
||||
label: createMessage(EDITOR_PANE_TEXTS.queries_tab),
|
||||
startIcon: "queries-line",
|
||||
value: EditorEntityTab.QUERIES,
|
||||
},
|
||||
{
|
||||
label: createMessage(EDITOR_PANE_TEXTS.js_tab),
|
||||
startIcon: "content-type-json",
|
||||
value: EditorEntityTab.JS,
|
||||
},
|
||||
{
|
||||
label: createMessage(EDITOR_PANE_TEXTS.ui_tab),
|
||||
startIcon: "dashboard-line",
|
||||
value: EditorEntityTab.UI,
|
||||
},
|
||||
];
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<EditorSegments
|
||||
onSegmentChange={onSegmentChange}
|
||||
options={[
|
||||
{
|
||||
label: createMessage(EDITOR_PANE_TEXTS.queries_tab),
|
||||
value: EditorEntityTab.QUERIES,
|
||||
},
|
||||
{
|
||||
label: createMessage(EDITOR_PANE_TEXTS.js_tab),
|
||||
value: EditorEntityTab.JS,
|
||||
},
|
||||
{
|
||||
label: createMessage(EDITOR_PANE_TEXTS.ui_tab),
|
||||
value: EditorEntityTab.UI,
|
||||
},
|
||||
]}
|
||||
options={segmentOptions}
|
||||
selectedSegment={segment}
|
||||
/>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -26,11 +26,11 @@ function Sidebar() {
|
|||
const datasources = useSelector(getDatasources);
|
||||
const datasourcesExist = datasources.length > 0;
|
||||
|
||||
// Updates the top button config based on datasource existence
|
||||
const topButtons = React.useMemo(() => {
|
||||
// Updates the bottom button config based on datasource existence
|
||||
const bottomButtons = React.useMemo(() => {
|
||||
return datasourcesExist
|
||||
? TopButtons
|
||||
: TopButtons.map((button) => {
|
||||
? BottomButtons
|
||||
: BottomButtons.map((button) => {
|
||||
if (button.state === EditorState.DATA) {
|
||||
return {
|
||||
...button,
|
||||
|
|
@ -64,11 +64,11 @@ function Sidebar() {
|
|||
|
||||
return (
|
||||
<IDESidebar
|
||||
bottomButtons={BottomButtons}
|
||||
bottomButtons={bottomButtons}
|
||||
editorState={appState}
|
||||
id={"t--app-sidebar"}
|
||||
onClick={onClick}
|
||||
topButtons={topButtons}
|
||||
topButtons={TopButtons}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user