From a73d87a943ee0c90d039f12dd77bdaf99404bcd6 Mon Sep 17 00:00:00 2001 From: Jaanus Sellin Date: Wed, 3 Jan 2024 15:08:01 +0200 Subject: [PATCH] feat: make feedback available for OSS (#5748) --- .../FeatureToggleListTable.tsx | 11 +-- .../feedbackNew/FeedbackComponent.tsx | 77 +++++++++++++++---- .../component/feedbackNew/FeedbackContext.ts | 13 ++-- .../feedbackNew/FeedbackProvider.tsx | 13 ++-- .../useUserFeedbackApi/useUserFeedbackApi.ts | 33 ++------ .../__snapshots__/create-config.test.ts.snap | 2 +- src/lib/middleware/secure-headers.ts | 1 + src/lib/types/experimental.ts | 2 +- src/server-dev.ts | 1 - 9 files changed, 87 insertions(+), 66 deletions(-) diff --git a/frontend/src/component/feature/FeatureToggleList/FeatureToggleListTable.tsx b/frontend/src/component/feature/FeatureToggleList/FeatureToggleListTable.tsx index f666bb819e..a8331d1141 100644 --- a/frontend/src/component/feature/FeatureToggleList/FeatureToggleListTable.tsx +++ b/frontend/src/component/feature/FeatureToggleList/FeatureToggleListTable.tsx @@ -84,7 +84,7 @@ const FeatureToggleListTableComponent: VFC = () => { const [showExportDialog, setShowExportDialog] = useState(false); const { setToastApiError } = useToast(); - const { uiConfig, isPro, isOss, isEnterprise } = useUiConfig(); + const { uiConfig } = useUiConfig(); const featureSearchFeedback = useUiFlag('featureSearchFeedback'); const stateConfig = { @@ -275,16 +275,8 @@ const FeatureToggleListTableComponent: VFC = () => { } const createFeedbackContext = () => { - const userType = isPro() - ? 'pro' - : isOss() - ? 'oss' - : isEnterprise() - ? 'enterprise' - : 'unknown'; openFeedback({ category: feedbackCategory, - userType, title: 'How easy was it to use search and filters?', positiveLabel: 'What do you like most about search and filters?', areasForImprovementsLabel: @@ -335,7 +327,6 @@ const FeatureToggleListTableComponent: VFC = () => { /> ({ position: 'relative', @@ -155,12 +159,34 @@ const StyledCloseButton = styled(IconButton)(({ theme }) => ({ color: theme.palette.background.paper, })); -export const FeedbackComponent = () => { +export const FeedbackComponentWrapper = () => { const { feedbackData, showFeedback, closeFeedback } = useFeedback(); if (!feedbackData) return null; + return ( + + ); +}; + +interface IFeedbackComponent { + feedbackData: FeedbackData; + showFeedback: boolean; + closeFeedback: () => void; +} + +export const FeedbackComponent = ({ + feedbackData, + showFeedback, + closeFeedback, +}: IFeedbackComponent) => { const { setToastData } = useToast(); + const theme = useTheme(); + const { isPro, isOss, isEnterprise } = useUiConfig(); const { addFeedback } = useUserFeedbackApi(); const { setHasSubmittedFeedback } = useUserSubmittedFeedback( feedbackData.category, @@ -184,19 +210,22 @@ export const FeedbackComponent = () => { const formData = new FormData(event.currentTarget); const data = Object.fromEntries(formData); + let toastType: IToast['type'] = 'error'; + let toastTitle = 'Feedback not sent'; + if (isProvideFeedbackSchema(data)) { - await addFeedback(data as ProvideFeedbackSchema); - setToastData({ - title: 'Feedback sent', - type: 'success', - }); - setHasSubmittedFeedback(true); - } else { - setToastData({ - title: 'Feedback not sent', - type: 'error', - }); + try { + await addFeedback(data as ProvideFeedbackSchema); + toastTitle = 'Feedback sent'; + toastType = 'success'; + setHasSubmittedFeedback(true); + } catch (e) {} } + + setToastData({ + title: toastTitle, + type: toastType, + }); closeFeedback(); }; @@ -206,6 +235,22 @@ export const FeedbackComponent = () => { setSelectedScore(event.target.value); }; + const getUserType = () => { + if (isPro()) { + return 'pro'; + } + + if (isOss()) { + return 'oss'; + } + + if (isEnterprise()) { + return 'enterprise'; + } + + return 'unknown'; + }; + return ( { {feedbackData.title} @@ -273,7 +318,8 @@ export const FeedbackComponent = () => { size='small' InputLabelProps={{ style: { - fontSize: '14px', + fontSize: + theme.fontSizes.smallBody, }, }} /> @@ -290,7 +336,8 @@ export const FeedbackComponent = () => { rows={3} InputLabelProps={{ style: { - fontSize: '14px', + fontSize: + theme.fontSizes.smallBody, }, }} variant='outlined' diff --git a/frontend/src/component/feedbackNew/FeedbackContext.ts b/frontend/src/component/feedbackNew/FeedbackContext.ts index 65c492bf36..03fa7b991b 100644 --- a/frontend/src/component/feedbackNew/FeedbackContext.ts +++ b/frontend/src/component/feedbackNew/FeedbackContext.ts @@ -3,21 +3,22 @@ import { ProvideFeedbackSchema } from '../../openapi'; import { IFeedbackCategory } from 'hooks/useSubmittedFeedback'; interface IFeedbackContext { - feedbackData: IFeedbackData | undefined; - openFeedback: (data: IFeedbackData) => void; + feedbackData: FeedbackData | undefined; + openFeedback: (data: FeedbackData) => void; closeFeedback: () => void; showFeedback: boolean; setShowFeedback: (visible: boolean) => void; } -type IFeedbackText = { +interface IFeedbackText { title: string; positiveLabel: string; areasForImprovementsLabel: string; -}; +} -export type IFeedbackData = Pick & - IFeedbackText & { category: IFeedbackCategory }; +export type FeedbackData = IFeedbackText & { + category: IFeedbackCategory; +}; export const FeedbackContext = createContext( undefined, diff --git a/frontend/src/component/feedbackNew/FeedbackProvider.tsx b/frontend/src/component/feedbackNew/FeedbackProvider.tsx index 4f3cadf593..85414d899c 100644 --- a/frontend/src/component/feedbackNew/FeedbackProvider.tsx +++ b/frontend/src/component/feedbackNew/FeedbackProvider.tsx @@ -1,14 +1,17 @@ -import { FeedbackComponent } from './FeedbackComponent'; -import { FeedbackContext, IFeedbackData } from './FeedbackContext'; +import { + FeedbackComponent, + FeedbackComponentWrapper, +} from './FeedbackComponent'; +import { FeedbackContext, FeedbackData } from './FeedbackContext'; import { FC, useState } from 'react'; export const FeedbackProvider: FC = ({ children }) => { - const [feedbackData, setFeedbackData] = useState( + const [feedbackData, setFeedbackData] = useState( undefined, ); const [showFeedback, setShowFeedback] = useState(false); - const openFeedback = (data: IFeedbackData) => { + const openFeedback = (data: FeedbackData) => { setFeedbackData(data); setShowFeedback(true); }; @@ -29,7 +32,7 @@ export const FeedbackProvider: FC = ({ children }) => { }} > {children} - + ); }; diff --git a/frontend/src/hooks/api/actions/useUserFeedbackApi/useUserFeedbackApi.ts b/frontend/src/hooks/api/actions/useUserFeedbackApi/useUserFeedbackApi.ts index af50e7f8bf..16d7747bb7 100644 --- a/frontend/src/hooks/api/actions/useUserFeedbackApi/useUserFeedbackApi.ts +++ b/frontend/src/hooks/api/actions/useUserFeedbackApi/useUserFeedbackApi.ts @@ -2,41 +2,20 @@ import useAPI from '../useApi/useApi'; import { ProvideFeedbackSchema } from '../../../../openapi'; import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig'; -const ENDPOINT = 'feedback'; +const ENDPOINT = 'https://app.unleash-hosted.com/hosted/feedback'; export const useUserFeedbackApi = () => { const { uiConfig } = useUiConfig(); - const { loading, makeRequest, createRequest, errors } = useAPI({ - propagateErrors: true, - }); - const addFeedback = async (feedbackSchema: ProvideFeedbackSchema) => { - if (uiConfig.feedbackUriPath !== undefined) { - await fetch(uiConfig.feedbackUriPath, { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify(feedbackSchema), - }); - } else { - const requestId = 'addFeedback'; - const req = createRequest( - ENDPOINT, - { - method: 'POST', - body: JSON.stringify(feedbackSchema), - }, - requestId, - ); - - const response = await makeRequest(req.caller, req.id); - return response.json(); - } + await fetch(uiConfig.feedbackUriPath || ENDPOINT, { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify(feedbackSchema), + }); }; return { addFeedback, - errors, - loading, }; }; diff --git a/src/lib/__snapshots__/create-config.test.ts.snap b/src/lib/__snapshots__/create-config.test.ts.snap index 474591f27e..f3468980aa 100644 --- a/src/lib/__snapshots__/create-config.test.ts.snap +++ b/src/lib/__snapshots__/create-config.test.ts.snap @@ -84,7 +84,7 @@ exports[`should create default config 1`] = ` "embedProxy": true, "embedProxyFrontend": true, "featureSearchAPI": false, - "featureSearchFeedback": false, + "featureSearchFeedback": true, "featureSearchFeedbackPosting": false, "featureSearchFrontend": false, "featuresExportImport": true, diff --git a/src/lib/middleware/secure-headers.ts b/src/lib/middleware/secure-headers.ts index 9d863ac14d..c9bbfebfdb 100644 --- a/src/lib/middleware/secure-headers.ts +++ b/src/lib/middleware/secure-headers.ts @@ -53,6 +53,7 @@ const secureHeaders: (config: IUnleashConfig) => RequestHandler = (config) => { 'plausible.getunleash.io', 'gravatar.com', 'europe-west3-metrics-304612.cloudfunctions.net', + 'app.unleash-hosted.com', ...config.additionalCspAllowedDomains.connectSrc, ], mediaSrc: [ diff --git a/src/lib/types/experimental.ts b/src/lib/types/experimental.ts index a607bf5d3d..93dfc3fec3 100644 --- a/src/lib/types/experimental.ts +++ b/src/lib/types/experimental.ts @@ -155,7 +155,7 @@ const flags: IFlags = { ), featureSearchFeedback: parseEnvVarBoolean( process.env.UNLEASH_EXPERIMENTAL_FEATURE_SEARCH_FEEDBACK, - false, + true, ), featureSearchFeedbackPosting: parseEnvVarBoolean( process.env.UNLEASH_EXPERIMENTAL_FEATURE_SEARCH_FEEDBACK_POSTING, diff --git a/src/server-dev.ts b/src/server-dev.ts index 745c894eec..9119ad1b2e 100644 --- a/src/server-dev.ts +++ b/src/server-dev.ts @@ -47,7 +47,6 @@ process.nextTick(async () => { stripHeadersOnAPI: true, celebrateUnleash: true, increaseUnleashWidth: true, - featureSearchFeedback: true, }, }, authentication: {