Skip to content

Commit 3e5cac4

Browse files
committed
Extract feedback snippet to shared components folder and remove navigation solutionId prop
1 parent b311856 commit 3e5cac4

File tree

22 files changed

+263
-82
lines changed

22 files changed

+263
-82
lines changed

.github/CODEOWNERS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -640,6 +640,7 @@ src/platform/packages/shared/shared-ux/chrome/navigation @elastic/appex-sharedux
640640
src/platform/packages/shared/shared-ux/code_editor/impl @elastic/appex-sharedux
641641
src/platform/packages/shared/shared-ux/code_editor/mocks @elastic/appex-sharedux
642642
src/platform/packages/shared/shared-ux/error_boundary @elastic/appex-sharedux
643+
src/platform/packages/shared/shared-ux/feedback_snippet/impl @elastic/appex-sharedux
643644
src/platform/packages/shared/shared-ux/file/context @elastic/appex-sharedux
644645
src/platform/packages/shared/shared-ux/file/file_picker/impl @elastic/appex-sharedux
645646
src/platform/packages/shared/shared-ux/file/file_upload/impl @elastic/appex-sharedux

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -971,6 +971,7 @@
971971
"@kbn/shared-ux-card-no-data-types": "link:src/platform/packages/shared/shared-ux/card/no_data/types",
972972
"@kbn/shared-ux-chrome-navigation": "link:src/platform/packages/shared/shared-ux/chrome/navigation",
973973
"@kbn/shared-ux-error-boundary": "link:src/platform/packages/shared/shared-ux/error_boundary",
974+
"@kbn/shared-ux-feedback-snippet": "link:src/platform/packages/shared/shared-ux/feedback_snippet/impl",
974975
"@kbn/shared-ux-file-context": "link:src/platform/packages/shared/shared-ux/file/context",
975976
"@kbn/shared-ux-file-image": "link:src/platform/packages/shared/shared-ux/file/image/impl",
976977
"@kbn/shared-ux-file-picker": "link:src/platform/packages/shared/shared-ux/file/file_picker/impl",

src/core/packages/chrome/browser-internal/src/ui/project/sidenav_v2/navigation/navigation.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import { RedirectNavigationAppLinks } from './redirect_app_links';
2525
import type { NavigationItems } from './to_navigation_items';
2626
import { toNavigationItems } from './to_navigation_items';
2727
import { PanelStateManager } from './panel_state_manager';
28+
import { NavigationFeedbackSnippet } from './navigation_feedback_snippet';
2829

2930
export interface ChromeNavigationProps {
3031
// sidenav state
@@ -63,7 +64,7 @@ export const Navigation = (props: ChromeNavigationProps) => {
6364
<NavigationComponent
6465
items={navItems}
6566
logo={logoItem}
66-
solutionId={solutionId}
67+
sidePanelFooter={<NavigationFeedbackSnippet solutionId={solutionId} />}
6768
isCollapsed={props.isCollapsed}
6869
setWidth={props.setWidth}
6970
activeItemId={activeItemId}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the "Elastic License
4+
* 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side
5+
* Public License v 1"; you may not use this file except in compliance with, at
6+
* your election, the "Elastic License 2.0", the "GNU Affero General Public
7+
* License v3.0 only", or the "Server Side Public License, v 1".
8+
*/
9+
10+
import React from 'react';
11+
import { FeedbackSnippet } from '@kbn/shared-ux-feedback-snippet';
12+
import type { SolutionId } from '@kbn/core-chrome-browser';
13+
import { FormattedMessage } from '@kbn/i18n-react';
14+
15+
interface NavigationFeedbackSnippetProps {
16+
solutionId: SolutionId;
17+
}
18+
19+
const feedbackPanelLocalStorageKey = 'core.ui.chrome.sideNavigation.feedbackInteraction';
20+
const feedbackSnippetId = 'sideNavigationFeedback';
21+
22+
const feedbackUrls: { [id in SolutionId]: string } = {
23+
es: 'https://ela.st/search-nav-feedback',
24+
chat: 'https://ela.st/search-nav-feedback',
25+
oblt: 'https://ela.st/o11y-nav-feedback',
26+
security: 'https://ela.st/security-nav-feedback',
27+
};
28+
29+
const feedbackButtonMessage = (
30+
<FormattedMessage
31+
id="core.ui.chrome.sideNavigation.sideNavigation.feedbackButtonText"
32+
defaultMessage="Navigation feedback"
33+
/>
34+
);
35+
36+
const promptViewMessage = (
37+
<FormattedMessage
38+
id="core.ui.chrome.sideNavigation.feedbackPanel.promptTitle"
39+
defaultMessage="How's the navigation working for you?"
40+
/>
41+
);
42+
43+
export const NavigationFeedbackSnippet = ({ solutionId }: NavigationFeedbackSnippetProps) => {
44+
const feedbackSurveyUrl = feedbackUrls[solutionId];
45+
46+
return (
47+
<FeedbackSnippet
48+
feedbackButtonMessage={feedbackButtonMessage}
49+
feedbackSnippetId={feedbackSnippetId}
50+
feedbackPanelLocalStorageKey={feedbackPanelLocalStorageKey}
51+
promptViewMessage={promptViewMessage}
52+
surveyUrl={feedbackSurveyUrl}
53+
/>
54+
);
55+
};

src/core/packages/chrome/navigation/src/__stories__/navigation.stories.tsx

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,6 @@ export default {
7676
iconType: LOGO.type,
7777
},
7878
setWidth: () => {},
79-
solutionId: 'oblt',
8079
},
8180
} as Meta<PropsAndArgs>;
8281

@@ -221,7 +220,6 @@ const Layout = ({ ...props }: PropsAndArgs) => {
221220
items={props.items}
222221
logo={props.logo}
223222
setWidth={setNavigationWidth}
224-
solutionId={props.solutionId}
225223
/>
226224
}
227225
sidebar={

src/core/packages/chrome/navigation/src/components/navigation.tsx

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ import React from 'react';
1212
import { useIsWithinBreakpoints } from '@elastic/eui';
1313
import { css } from '@emotion/react';
1414

15-
import type { SolutionId } from '@kbn/core-chrome-browser';
1615
import { i18n } from '@kbn/i18n';
1716
import { FormattedMessage } from '@kbn/i18n-react';
1817
import type { MenuItem, NavigationStructure, SecondaryMenuItem, SideNavLogo } from '../../types';
@@ -32,9 +31,9 @@ export interface NavigationProps {
3231
*/
3332
activeItemId?: string;
3433
/**
35-
* The solution id, used for building feedback survey links.
34+
* Content to display inside the side panel footer.
3635
*/
37-
solutionId: SolutionId;
36+
sidePanelFooter?: React.ReactNode;
3837
/**
3938
* Whether the navigation is collapsed. This can be controlled by the parent component.
4039
*/
@@ -63,7 +62,7 @@ export const Navigation = ({
6362
items,
6463
logo,
6564
setWidth,
66-
solutionId,
65+
sidePanelFooter,
6766
...rest
6867
}: NavigationProps) => {
6968
const isMobile = useIsWithinBreakpoints(['xs', 's']);
@@ -347,7 +346,7 @@ export const Navigation = ({
347346
</SideNav>
348347

349348
{isSidePanelOpen && sidePanelContent && (
350-
<SideNav.Panel solutionId={solutionId}>
349+
<SideNav.Panel sidePanelFooter={sidePanelFooter}>
351350
<SecondaryMenu
352351
badgeType={sidePanelContent.badgeType}
353352
isPanel

src/core/packages/chrome/navigation/src/components/side_nav/panel.tsx

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,11 @@ import type { ReactNode } from 'react';
1212
import React, { useRef } from 'react';
1313
import { css } from '@emotion/react';
1414

15-
import type { SolutionId } from '@kbn/core-chrome-browser';
1615
import { useRovingIndex } from '../../utils/use_roving_index';
17-
import { FeedbackSnippet } from '../feedback_snippet';
1816

1917
export interface SideNavPanelProps {
2018
children: ReactNode;
21-
solutionId: SolutionId;
19+
sidePanelFooter?: ReactNode;
2220
}
2321

2422
/**
@@ -28,7 +26,7 @@ export interface SideNavPanelProps {
2826
*
2927
* TODO: pass ref to EuiPanel
3028
*/
31-
export const SideNavPanel = ({ children, solutionId }: SideNavPanelProps): JSX.Element => {
29+
export const SideNavPanel = ({ children, sidePanelFooter }: SideNavPanelProps): JSX.Element => {
3230
const ref = useRef<HTMLDivElement | null>(null);
3331

3432
const { euiTheme } = useEuiTheme();
@@ -63,7 +61,7 @@ export const SideNavPanel = ({ children, solutionId }: SideNavPanelProps): JSX.E
6361
>
6462
{children}
6563
</div>
66-
<FeedbackSnippet solutionId={solutionId} />
64+
{sidePanelFooter}
6765
</EuiPanel>
6866
</div>
6967
);

src/core/packages/chrome/navigation/tsconfig.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,5 +20,6 @@
2020
"@kbn/i18n",
2121
"@kbn/i18n-react",
2222
"@kbn/core-chrome-browser",
23+
"@kbn/shared-ux-feedback-snippet"
2324
]
2425
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# @kbn/shared-ux-feedback-snippet
2+
3+
---
4+
id: sharedUX/Components/FeedbackSnippet
5+
slug: /shared-ux/components/feedback_snippet
6+
title: Feedback Snippet
7+
summary: A component to gather user feedback that initially renders as a panel and becomes a button after interaction.
8+
tags: ['shared-ux', 'component']
9+
date: 2025-09-11
10+
---
11+
12+
# Feedback Snippet
13+
A snippet to gather user feedback. It initially renders as a panel, and once interacted with, it becomes a persistent button. It manages its own state (panel vs. button) based on user interaction tracked in `localStorage`.
14+
15+
## Behavior
16+
The component has two main states:
17+
- **Panel:** On its first render for a user, the component displays as a full panel with the `promptViewMessage` and options to provide positive ("Yes") or negative ("No") feedback. A "Dismiss" (x) button is also available.
18+
- **Button:** The component uses the provided `feedbackPanelLocalStorageKey` to track whether the user has interacted with it. If a value is present for that key, the component will render as a button instead.
19+
20+
## Feedback Panel Views
21+
- **Prompt:** The panel shows a custom `promptViewMessage` to gather feedback from the user.
22+
- **Positive:** The panel shows a thank you message and then automatically dismisses itself.
23+
- **Negative:** The panel updates to show a custom `surveyUrl` call-to-action button. The panel remains visible until the user explicitly dismisses it or navigates to the survey (which opens in a new tab).
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the "Elastic License
4+
* 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side
5+
* Public License v 1"; you may not use this file except in compliance with, at
6+
* your election, the "Elastic License 2.0", the "GNU Affero General Public
7+
* License v3.0 only", or the "Server Side Public License, v 1".
8+
*/
9+
10+
export { FeedbackSnippet } from './src/feedback_snippet';

0 commit comments

Comments
 (0)