Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: Moving navigation header to Explorer templates in ADS #38131

Merged
merged 9 commits into from
Dec 18, 2024
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,10 @@ export const StyledControlContainer = styled.div`
cursor: pointer;
height: 100%;

&[data-selected="false"]:hover {
background-color: var(--ads-v2-color-bg-muted);
}

&:focus-visible {
outline: var(--ads-v2-border-width-outline) solid
var(--ads-v2-color-outline);
Expand All @@ -77,7 +81,7 @@ export const StyledControlContainer = styled.div`

/* Select all segments which is not a selected and last child */
/* seperator */
&:not(:last-child):not([data-selected="true"]):not(
&:not(:hover):not(:last-child):not([data-selected="true"]):not(
:has(+ [data-selected="true"])
):after {
content: "";
Expand All @@ -87,15 +91,4 @@ export const StyledControlContainer = styled.div`
height: 16px;
background-color: var(--ads-v2-colors-control-field-default-border);
}

/* This before is to mask the separator in left side of selected control */
/* Mask the seperator with track background color */
&[data-selected="true"]:not(:first-child):after {
content: "";
position: absolute;
left: -7px;
width: 2px;
height: 16px;
background-color: var(--ads-v2-colors-control-track-default-bg);
}
`;
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { Canvas, Meta } from "@storybook/blocks";

import * as EditorSegmentsStories from "./EditorSegments.stories";

<Meta of={EditorSegmentsStories} />

# Editor Segments

Editor Segments is is built on top of the ADS component - Segmented Control. It is a preset template built for Entity Explorer which has a `max-width of 247px` and has extra padding around each of the segments.

Editor Segments present a range of options, and should be used when the user can execute those options instantaneously. It can also accept `children` to add more UI controls, if needed. These will be placed on the right side of the segments. It takes `options`, `selectedSegment` and `onSegmentChange` props to handle the value and onChange functionalities of Segmented Control component.

The options presented should not be binary. If you have a `yes | no` scenario, use a switch, instead.

## Anatomy

### Default implementation

Note: The `options` needs to be passed as required, the UI shown below are not default values being provided to the Editor segments. It also means the `selectedSegment` and `onSegmentChange` props needs to be passed as well.

<Canvas of={EditorSegmentsStories.EditorSegmentsStory} />

### More UI controls

<Canvas of={EditorSegmentsStories.EditorSegmentsStoryWithChildren} />
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
import React from "react";
import { EditorSegments } from "./EditorSegments";
import type { EditorSegmentsProps } from "./EditorSegments.types";
import type { StoryObj } from "@storybook/react";
import { Button } from "../../../Button";

export default {
title: "ADS/Templates/Editor Segments",
ankitakinger marked this conversation as resolved.
Show resolved Hide resolved
component: EditorSegments,
};

// eslint-disable-next-line react/function-component-definition
const Template = (args: EditorSegmentsProps) => {
return <EditorSegments {...args}>{args.children}</EditorSegments>;
};

export const EditorSegmentsStory = Template.bind({}) as StoryObj;
EditorSegmentsStory.storyName = "Default";
EditorSegmentsStory.args = {
options: [
{
value: "queries",
label: "Queries",
startIcon: "queries-v3",
},
{
value: "js",
label: "JS",
startIcon: "content-type-json",
},
{
value: "ui",
label: "UI",
startIcon: "dashboard-line",
isDisabled: true,
},
],
defaultValue: "queries",
};

export const EditorSegmentsStoryWithIcons = Template.bind({}) as StoryObj;
EditorSegmentsStoryWithIcons.storyName = "Only Icons";
EditorSegmentsStoryWithIcons.args = {
options: [
{
value: "queries",
startIcon: "queries-v3",
},
{
value: "js",
startIcon: "content-type-json",
},
{
value: "ui",
startIcon: "dashboard-line",
},
],
defaultValue: "queries",
};

export const EditorSegmentsStoryWithLabels = Template.bind({}) as StoryObj;
EditorSegmentsStoryWithLabels.storyName = "Only Labels";
EditorSegmentsStoryWithLabels.args = {
options: [
{
value: "queries",
label: "Queries",
},
{
value: "js",
label: "JS",
},
{
value: "ui",
label: "UI",
},
],
defaultValue: "queries",
};

export const EditorSegmentsStoryWithChildren = Template.bind({}) as StoryObj;
EditorSegmentsStoryWithChildren.storyName = "With Children";
EditorSegmentsStoryWithChildren.args = {
options: [
{
value: "queries",
label: "Queries",
},
{
value: "js",
label: "JS",
},
{
value: "ui",
label: "UI",
},
],
defaultValue: "queries",
isFullWidth: true,
children: <Button isIconButton kind="secondary" startIcon="plus" />,
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import styled from "styled-components";
import { Flex } from "../../../Flex";

export const Container = styled(Flex)`
.editor-pane-segment-control {
max-width: 247px;
}
`;
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import React from "react";
import { SegmentedControl } from "../../../SegmentedControl";
import { Container } from "./EditorSegments.styles";
import type { EditorSegmentsProps } from "./EditorSegments.types";

const EditorSegments = (props: EditorSegmentsProps) => {
const { children, onSegmentChange, options, selectedSegment } = props;

return (
<Container
alignItems="center"
backgroundColor="var(--ads-v2-colors-control-track-default-bg)"
className="ide-editor-left-pane__header"
gap="spaces-2"
justifyContent="space-between"
padding="spaces-2"
>
<SegmentedControl
className="editor-pane-segment-control"
onChange={onSegmentChange}
options={options}
value={selectedSegment}
/>
{children}
</Container>
);
};

EditorSegments.displayName = "EditorSegments";

EditorSegments.defaultProps = {};

export { EditorSegments };
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import type { SegmentedControlOption } from "../../../SegmentedControl";
ankitakinger marked this conversation as resolved.
Show resolved Hide resolved

export interface EditorSegmentsProps {
selectedSegment: string;
onSegmentChange: (value: string) => void;
options: SegmentedControlOption[];
children?: React.ReactNode | React.ReactNode[];
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from "./EditorSegments";
export * from "./EditorSegments.types";
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export { ListItemContainer, ListHeaderContainer } from "./styles";
export { ListWithHeader } from "./ListWithHeader";
export { EditorSegments } from "./EditorSegments";
4 changes: 2 additions & 2 deletions app/client/src/pages/Editor/IDE/EditorPane/Explorer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import {
BUILDER_PATH,
BUILDER_PATH_DEPRECATED,
} from "ee/constants/routes/appRoutes";
import SegmentedHeader from "./components/SegmentedHeader";
import SegmentSwitcher from "./components/SegmentSwitcher";
import { useSelector } from "react-redux";
import { getIDEViewMode } from "selectors/ideSelectors";
import { EditorViewMode } from "ee/entities/IDE/constants";
Expand All @@ -41,7 +41,7 @@ const EditorPaneExplorer = () => {
: "100%"
}
>
<SegmentedHeader />
<SegmentSwitcher />
<Switch>
<SentryRoute
component={JSExplorer}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import React from "react";
import { createMessage, EDITOR_PANE_TEXTS } from "ee/constants/messages";
import { EditorEntityTab } from "ee/entities/IDE/constants";
import { useCurrentEditorState, useSegmentNavigation } from "../../hooks";
import { EditorSegments } from "@appsmith/ads";

const SegmentSwitcher = () => {
const { segment } = useCurrentEditorState();
const { onSegmentChange } = useSegmentNavigation();

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,
},
]}
selectedSegment={segment}
/>
);
};

export default SegmentSwitcher;

This file was deleted.

12 changes: 8 additions & 4 deletions app/client/src/pages/Editor/IDE/hooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ import { closeJSActionTab } from "actions/jsActionActions";
import { closeQueryActionTab } from "actions/pluginActionActions";
import { getCurrentBasePageId } from "selectors/editorSelectors";
import { getCurrentEntityInfo } from "../utils";
import { useEditorType } from "ee/hooks";
import { useParentEntityInfo } from "ee/hooks/datasourceEditorHooks";

export const useCurrentEditorState = () => {
const [selectedSegment, setSelectedSegment] = useState<EditorEntityTab>(
Expand Down Expand Up @@ -58,7 +60,9 @@ export const useCurrentEditorState = () => {
export const useSegmentNavigation = (): {
onSegmentChange: (value: string) => void;
} => {
const basePageId = useSelector(getCurrentBasePageId);
const editorType = useEditorType(location.pathname);
const { parentEntityId: baseParentEntityId } =
useParentEntityInfo(editorType);
ankitakinger marked this conversation as resolved.
Show resolved Hide resolved

/**
* Callback to handle the segment change
Expand All @@ -70,17 +74,17 @@ export const useSegmentNavigation = (): {
const onSegmentChange = (value: string) => {
switch (value) {
case EditorEntityTab.QUERIES:
history.push(queryListURL({ basePageId }), {
history.push(queryListURL({ baseParentEntityId }), {
invokedBy: NavigationMethod.SegmentControl,
});
break;
case EditorEntityTab.JS:
history.push(jsCollectionListURL({ basePageId }), {
history.push(jsCollectionListURL({ baseParentEntityId }), {
invokedBy: NavigationMethod.SegmentControl,
});
break;
case EditorEntityTab.UI:
history.push(widgetListURL({ basePageId }), {
history.push(widgetListURL({ baseParentEntityId }), {
invokedBy: NavigationMethod.SegmentControl,
});
break;
Expand Down
Loading