From 1f89f780bd205d36b572689e1103c860f787a13e Mon Sep 17 00:00:00 2001 From: Lucas Pelegrino Date: Tue, 24 Sep 2024 09:54:31 -0300 Subject: [PATCH] feat: Adds new admin feature preview setting management (#33212) Co-authored-by: Guilherme Gazzo --- .changeset/quick-rings-wave.md | 7 + .../UserMenu/hooks/useAccountItems.tsx | 4 +- .../hooks/useFeaturePreviewEnableQuery.ts | 28 ++++ .../sidebar/header/hooks/useAccountItems.tsx | 4 +- .../AccountFeaturePreviewBadge.tsx | 21 --- .../AccountFeaturePreviewPage.tsx | 44 ++---- .../client/views/account/sidebarItems.tsx | 5 +- .../AdminFeaturePreviewPage.tsx | 127 ++++++++++++++++++ .../AdminFeaturePreviewRoute.tsx | 26 ++++ apps/meteor/client/views/admin/routes.tsx | 9 ++ .../meteor/client/views/admin/sidebarItems.ts | 8 ++ .../featurePreview/enhanced-navigation.png | Bin 0 -> 2372 bytes .../resizable-contextual-bar.png | Bin 0 -> 4776 bytes .../images/featurePreview/timestamp.png | Bin 0 -> 51432 bytes apps/meteor/server/settings/accounts.ts | 5 + .../tests/end-to-end/api/miscellaneous.ts | 1 + packages/i18n/src/locales/en.i18n.json | 16 ++- packages/i18n/src/locales/hi-IN.i18n.json | 6 +- .../FeaturePreview/FeaturePreviewBadge.tsx | 21 +++ .../src/components/FeaturePreview/index.ts | 2 + packages/ui-client/src/components/index.ts | 2 +- .../useDefaultSettingFeaturePreviewList.ts | 12 ++ .../ui-client/src/hooks/useFeaturePreview.ts | 5 +- .../src/hooks/useFeaturePreviewList.ts | 32 +++-- ... usePreferenceFeaturePreviewList.spec.tsx} | 13 +- .../hooks/usePreferenceFeaturePreviewList.ts | 16 +++ packages/ui-client/src/index.ts | 2 + 27 files changed, 324 insertions(+), 92 deletions(-) create mode 100644 .changeset/quick-rings-wave.md create mode 100644 apps/meteor/client/hooks/useFeaturePreviewEnableQuery.ts delete mode 100644 apps/meteor/client/views/account/featurePreview/AccountFeaturePreviewBadge.tsx create mode 100644 apps/meteor/client/views/admin/featurePreview/AdminFeaturePreviewPage.tsx create mode 100644 apps/meteor/client/views/admin/featurePreview/AdminFeaturePreviewRoute.tsx create mode 100644 apps/meteor/public/images/featurePreview/enhanced-navigation.png create mode 100644 apps/meteor/public/images/featurePreview/resizable-contextual-bar.png create mode 100644 apps/meteor/public/images/featurePreview/timestamp.png create mode 100644 packages/ui-client/src/components/FeaturePreview/FeaturePreviewBadge.tsx create mode 100644 packages/ui-client/src/components/FeaturePreview/index.ts create mode 100644 packages/ui-client/src/hooks/useDefaultSettingFeaturePreviewList.ts rename packages/ui-client/src/hooks/{useFeaturePreviewList.spec.tsx => usePreferenceFeaturePreviewList.spec.tsx} (79%) create mode 100644 packages/ui-client/src/hooks/usePreferenceFeaturePreviewList.ts diff --git a/.changeset/quick-rings-wave.md b/.changeset/quick-rings-wave.md new file mode 100644 index 000000000000..0ea22897ff45 --- /dev/null +++ b/.changeset/quick-rings-wave.md @@ -0,0 +1,7 @@ +--- +"@rocket.chat/meteor": minor +"@rocket.chat/i18n": minor +"@rocket.chat/ui-client": minor +--- + +Added new Admin Feature Preview management view, this will allow the workspace admins to both enable feature previewing in the workspace as well as define which feature previews are enabled by default for the users in the workspace. diff --git a/apps/meteor/client/NavBarV2/NavBarSettingsToolbar/UserMenu/hooks/useAccountItems.tsx b/apps/meteor/client/NavBarV2/NavBarSettingsToolbar/UserMenu/hooks/useAccountItems.tsx index 82c39c5c1b10..e54e2b72d675 100644 --- a/apps/meteor/client/NavBarV2/NavBarSettingsToolbar/UserMenu/hooks/useAccountItems.tsx +++ b/apps/meteor/client/NavBarV2/NavBarSettingsToolbar/UserMenu/hooks/useAccountItems.tsx @@ -1,7 +1,7 @@ import { Badge } from '@rocket.chat/fuselage'; import { useEffectEvent } from '@rocket.chat/fuselage-hooks'; -import { defaultFeaturesPreview, useFeaturePreviewList } from '@rocket.chat/ui-client'; import type { GenericMenuItemProps } from '@rocket.chat/ui-client'; +import { defaultFeaturesPreview, usePreferenceFeaturePreviewList } from '@rocket.chat/ui-client'; import { useRouter, useTranslation } from '@rocket.chat/ui-contexts'; import React from 'react'; @@ -9,7 +9,7 @@ export const useAccountItems = (): GenericMenuItemProps[] => { const t = useTranslation(); const router = useRouter(); - const { unseenFeatures, featurePreviewEnabled } = useFeaturePreviewList(); + const { unseenFeatures, featurePreviewEnabled } = usePreferenceFeaturePreviewList(); const handleMyAccount = useEffectEvent(() => { router.navigate('/account'); diff --git a/apps/meteor/client/hooks/useFeaturePreviewEnableQuery.ts b/apps/meteor/client/hooks/useFeaturePreviewEnableQuery.ts new file mode 100644 index 000000000000..fd88f0237d29 --- /dev/null +++ b/apps/meteor/client/hooks/useFeaturePreviewEnableQuery.ts @@ -0,0 +1,28 @@ +import type { FeaturePreviewProps } from '@rocket.chat/ui-client'; +import { useMemo } from 'react'; + +const handleFeaturePreviewEnableQuery = (item: FeaturePreviewProps, _: any, features: FeaturePreviewProps[]) => { + if (item.enableQuery) { + const expected = item.enableQuery.value; + const received = features.find((el) => el.name === item.enableQuery?.name)?.value; + if (expected !== received) { + item.disabled = true; + item.value = false; + } else { + item.disabled = false; + } + } + return item; +}; + +const groupFeaturePreview = (features: FeaturePreviewProps[]) => + Object.entries( + features.reduce((result, currentValue) => { + (result[currentValue.group] = result[currentValue.group] || []).push(currentValue); + return result; + }, {} as Record), + ); + +export const useFeaturePreviewEnableQuery = (features: FeaturePreviewProps[]) => { + return useMemo(() => groupFeaturePreview(features.map(handleFeaturePreviewEnableQuery)), [features]); +}; diff --git a/apps/meteor/client/sidebar/header/hooks/useAccountItems.tsx b/apps/meteor/client/sidebar/header/hooks/useAccountItems.tsx index 2be6b2b1dea2..51ab7a198a67 100644 --- a/apps/meteor/client/sidebar/header/hooks/useAccountItems.tsx +++ b/apps/meteor/client/sidebar/header/hooks/useAccountItems.tsx @@ -1,7 +1,7 @@ import { Badge } from '@rocket.chat/fuselage'; import { useMutableCallback } from '@rocket.chat/fuselage-hooks'; -import { defaultFeaturesPreview, useFeaturePreviewList } from '@rocket.chat/ui-client'; import type { GenericMenuItemProps } from '@rocket.chat/ui-client'; +import { defaultFeaturesPreview, usePreferenceFeaturePreviewList } from '@rocket.chat/ui-client'; import { useRouter, useTranslation } from '@rocket.chat/ui-contexts'; import React from 'react'; @@ -9,7 +9,7 @@ export const useAccountItems = (): GenericMenuItemProps[] => { const t = useTranslation(); const router = useRouter(); - const { unseenFeatures, featurePreviewEnabled } = useFeaturePreviewList(); + const { unseenFeatures, featurePreviewEnabled } = usePreferenceFeaturePreviewList(); const handleMyAccount = useMutableCallback(() => { router.navigate('/account'); diff --git a/apps/meteor/client/views/account/featurePreview/AccountFeaturePreviewBadge.tsx b/apps/meteor/client/views/account/featurePreview/AccountFeaturePreviewBadge.tsx deleted file mode 100644 index c109ca1aefb5..000000000000 --- a/apps/meteor/client/views/account/featurePreview/AccountFeaturePreviewBadge.tsx +++ /dev/null @@ -1,21 +0,0 @@ -import { Badge } from '@rocket.chat/fuselage'; -import { useFeaturePreviewList } from '@rocket.chat/ui-client'; -import React from 'react'; -import { useTranslation } from 'react-i18next'; - -const AccountFeaturePreviewBadge = () => { - const { t } = useTranslation(); - const { unseenFeatures } = useFeaturePreviewList(); - - if (!unseenFeatures) { - return null; - } - - return ( - - {unseenFeatures} - - ); -}; - -export default AccountFeaturePreviewBadge; diff --git a/apps/meteor/client/views/account/featurePreview/AccountFeaturePreviewPage.tsx b/apps/meteor/client/views/account/featurePreview/AccountFeaturePreviewPage.tsx index dd9ab6a90959..358d2394003b 100644 --- a/apps/meteor/client/views/account/featurePreview/AccountFeaturePreviewPage.tsx +++ b/apps/meteor/client/views/account/featurePreview/AccountFeaturePreviewPage.tsx @@ -1,4 +1,3 @@ -import { css } from '@rocket.chat/css-in-js'; import { ButtonGroup, Button, @@ -13,9 +12,10 @@ import { FieldLabel, FieldRow, FieldHint, + Callout, + Margins, } from '@rocket.chat/fuselage'; -import type { FeaturePreviewProps } from '@rocket.chat/ui-client'; -import { useFeaturePreviewList } from '@rocket.chat/ui-client'; +import { usePreferenceFeaturePreviewList } from '@rocket.chat/ui-client'; import type { TranslationKey } from '@rocket.chat/ui-contexts'; import { useToastMessageDispatch, useTranslation, useEndpoint } from '@rocket.chat/ui-contexts'; import type { ChangeEvent } from 'react'; @@ -23,26 +23,12 @@ import React, { useEffect, Fragment } from 'react'; import { useForm } from 'react-hook-form'; import { Page, PageHeader, PageScrollableContentWithShadow, PageFooter } from '../../../components/Page'; +import { useFeaturePreviewEnableQuery } from '../../../hooks/useFeaturePreviewEnableQuery'; -const handleEnableQuery = (features: FeaturePreviewProps[]) => { - return features.map((item) => { - if (item.enableQuery) { - const expected = item.enableQuery.value; - const received = features.find((el) => el.name === item.enableQuery?.name)?.value; - if (expected !== received) { - item.disabled = true; - item.value = false; - } else { - item.disabled = false; - } - } - return item; - }); -}; const AccountFeaturePreviewPage = () => { const t = useTranslation(); const dispatchToastMessage = useToastMessageDispatch(); - const { features, unseenFeatures } = useFeaturePreviewList(); + const { features, unseenFeatures } = usePreferenceFeaturePreviewList(); const setUserPreferences = useEndpoint('POST', '/v1/users.setPreferences'); @@ -85,12 +71,7 @@ const AccountFeaturePreviewPage = () => { setValue('featuresPreview', updated, { shouldDirty: true }); }; - const grouppedFeaturesPreview = Object.entries( - handleEnableQuery(featuresPreview).reduce((result, currentValue) => { - (result[currentValue.group] = result[currentValue.group] || []).push(currentValue); - return result; - }, {} as Record), - ); + const grouppedFeaturesPreview = useFeaturePreviewEnableQuery(featuresPreview); return ( @@ -105,14 +86,11 @@ const AccountFeaturePreviewPage = () => { )} {featuresPreview.length > 0 && ( <> - - {t('Feature_preview_page_description')} + + + {t('Feature_preview_page_description')} + {t('Feature_preview_page_callout')} + {grouppedFeaturesPreview?.map(([group, features], index) => ( diff --git a/apps/meteor/client/views/account/sidebarItems.tsx b/apps/meteor/client/views/account/sidebarItems.tsx index ca0376be329d..fa2ab8bd5e40 100644 --- a/apps/meteor/client/views/account/sidebarItems.tsx +++ b/apps/meteor/client/views/account/sidebarItems.tsx @@ -1,10 +1,9 @@ -import { defaultFeaturesPreview } from '@rocket.chat/ui-client'; +import { defaultFeaturesPreview, FeaturePreviewBadge } from '@rocket.chat/ui-client'; import React from 'react'; import { hasPermission, hasAtLeastOnePermission } from '../../../app/authorization/client'; import { settings } from '../../../app/settings/client'; import { createSidebarItems } from '../../lib/createSidebarItems'; -import AccountFeaturePreviewBadge from './featurePreview/AccountFeaturePreviewBadge'; export const { registerSidebarItem: registerAccountSidebarItem, @@ -54,7 +53,7 @@ export const { href: '/account/feature-preview', i18nLabel: 'Feature_preview', icon: 'flask', - badge: () => , + badge: () => , permissionGranted: () => settings.get('Accounts_AllowFeaturePreview') && defaultFeaturesPreview?.length > 0, }, { diff --git a/apps/meteor/client/views/admin/featurePreview/AdminFeaturePreviewPage.tsx b/apps/meteor/client/views/admin/featurePreview/AdminFeaturePreviewPage.tsx new file mode 100644 index 000000000000..615fd20cf5a6 --- /dev/null +++ b/apps/meteor/client/views/admin/featurePreview/AdminFeaturePreviewPage.tsx @@ -0,0 +1,127 @@ +import { + ButtonGroup, + Button, + Box, + ToggleSwitch, + Accordion, + Field, + FieldGroup, + FieldLabel, + FieldRow, + FieldHint, + Callout, + Margins, +} from '@rocket.chat/fuselage'; +import { useDefaultSettingFeaturePreviewList } from '@rocket.chat/ui-client'; +import type { TranslationKey } from '@rocket.chat/ui-contexts'; +import { useToastMessageDispatch, useTranslation, useSettingsDispatch } from '@rocket.chat/ui-contexts'; +import type { ChangeEvent } from 'react'; +import React, { Fragment } from 'react'; +import { useForm } from 'react-hook-form'; + +import { Page, PageHeader, PageScrollableContentWithShadow, PageFooter } from '../../../components/Page'; +import { useFeaturePreviewEnableQuery } from '../../../hooks/useFeaturePreviewEnableQuery'; +import { useEditableSetting } from '../EditableSettingsContext'; +import Setting from '../settings/Setting'; +import SettingsGroupPageSkeleton from '../settings/SettingsGroupPage/SettingsGroupPageSkeleton'; + +const AdminFeaturePreviewPage = () => { + const t = useTranslation(); + const dispatchToastMessage = useToastMessageDispatch(); + const allowFeaturePreviewSetting = useEditableSetting('Accounts_AllowFeaturePreview'); + const { features } = useDefaultSettingFeaturePreviewList(); + + const { + watch, + formState: { isDirty }, + setValue, + handleSubmit, + reset, + } = useForm({ + defaultValues: { featuresPreview: features }, + }); + const { featuresPreview } = watch(); + const dispatch = useSettingsDispatch(); + + const handleSave = async () => { + try { + const featuresToBeSaved = featuresPreview.map((feature) => ({ name: feature.name, value: feature.value })); + + await dispatch([ + { _id: allowFeaturePreviewSetting!._id, value: allowFeaturePreviewSetting!.value }, + { _id: 'Accounts_Default_User_Preferences_featuresPreview', value: JSON.stringify(featuresToBeSaved) }, + ]); + dispatchToastMessage({ type: 'success', message: t('Preferences_saved') }); + } catch (error) { + dispatchToastMessage({ type: 'error', message: error }); + } finally { + reset({ featuresPreview }); + } + }; + + const handleFeatures = (e: ChangeEvent) => { + const updated = featuresPreview.map((item) => (item.name === e.target.name ? { ...item, value: e.target.checked } : item)); + setValue('featuresPreview', updated, { shouldDirty: true }); + }; + + const grouppedFeaturesPreview = useFeaturePreviewEnableQuery(featuresPreview); + + if (!allowFeaturePreviewSetting) { + // TODO: Implement FeaturePreviewSkeleton component + return ; + } + + return ( + + + + + + + {t('Feature_preview_admin_page_description')} + {t('Feature_preview_page_callout')} + {t('Feature_preview_admin_page_callout')} + + + + + {grouppedFeaturesPreview?.map(([group, features], index) => ( + + + {features.map((feature) => ( + + + + {t(feature.i18n)} + + + {feature.description && {t(feature.description)}} + + {feature.imageUrl && } + + ))} + + + ))} + + + + + + + + + + + ); +}; + +export default AdminFeaturePreviewPage; diff --git a/apps/meteor/client/views/admin/featurePreview/AdminFeaturePreviewRoute.tsx b/apps/meteor/client/views/admin/featurePreview/AdminFeaturePreviewRoute.tsx new file mode 100644 index 000000000000..a7d6bd77d136 --- /dev/null +++ b/apps/meteor/client/views/admin/featurePreview/AdminFeaturePreviewRoute.tsx @@ -0,0 +1,26 @@ +import { usePermission } from '@rocket.chat/ui-contexts'; +import type { ReactElement } from 'react'; +import React, { memo } from 'react'; + +import SettingsProvider from '../../../providers/SettingsProvider'; +import NotAuthorizedPage from '../../notAuthorized/NotAuthorizedPage'; +import EditableSettingsProvider from '../settings/EditableSettingsProvider'; +import AdminFeaturePreviewPage from './AdminFeaturePreviewPage'; + +const AdminFeaturePreviewRoute = (): ReactElement => { + const canViewFeaturesPreview = usePermission('manage-cloud'); + + if (!canViewFeaturesPreview) { + return ; + } + + return ( + + + + + + ); +}; + +export default memo(AdminFeaturePreviewRoute); diff --git a/apps/meteor/client/views/admin/routes.tsx b/apps/meteor/client/views/admin/routes.tsx index f70df1625871..d244d5e2f19b 100644 --- a/apps/meteor/client/views/admin/routes.tsx +++ b/apps/meteor/client/views/admin/routes.tsx @@ -104,6 +104,10 @@ declare module '@rocket.chat/ui-contexts' { pathname: `/admin/subscription`; pattern: '/admin/subscription'; }; + 'admin-feature-preview': { + pathname: '/admin/feature-preview'; + pattern: '/admin/feature-preview'; + }; } } @@ -237,3 +241,8 @@ registerAdminRoute('/subscription', { name: 'subscription', component: lazy(() => import('./subscription/SubscriptionRoute')), }); + +registerAdminRoute('/feature-preview', { + name: 'admin-feature-preview', + component: lazy(() => import('./featurePreview/AdminFeaturePreviewRoute')), +}); diff --git a/apps/meteor/client/views/admin/sidebarItems.ts b/apps/meteor/client/views/admin/sidebarItems.ts index 013206d9e9a8..fc7d307396d4 100644 --- a/apps/meteor/client/views/admin/sidebarItems.ts +++ b/apps/meteor/client/views/admin/sidebarItems.ts @@ -1,3 +1,5 @@ +import { defaultFeaturesPreview } from '@rocket.chat/ui-client'; + import { hasPermission, hasAtLeastOnePermission, hasAllPermission } from '../../../app/authorization/client'; import { createSidebarItems } from '../../lib/createSidebarItems'; @@ -129,6 +131,12 @@ export const { icon: 'emoji', permissionGranted: (): boolean => hasPermission('manage-emoji'), }, + { + href: '/admin/feature-preview', + i18nLabel: 'Feature_preview', + icon: 'flask', + permissionGranted: () => defaultFeaturesPreview?.length > 0, + }, { href: '/admin/settings', i18nLabel: 'Settings', diff --git a/apps/meteor/public/images/featurePreview/enhanced-navigation.png b/apps/meteor/public/images/featurePreview/enhanced-navigation.png new file mode 100644 index 0000000000000000000000000000000000000000..4240326ba985d0a054ae5d9c8521b24c8d93e6f7 GIT binary patch literal 2372 zcmeHIYgCg*8lKz;k(*0VynsLp8%mX01@Ra$34#GB2w8)n2Lz6kXazzALMRv_YP;xG zVrfx?0*kHdhC)CtVh|D##7hAYg%TP_P1$fufB*?0CfSL{AKkOvo<04szxKyBGw<`h z^UgExH}gzEL^#D}&89T~0Gp8DKq>$zF&wv8TEKSeq4Rv$;nISm(*aoTVg3*yRQGuZ zBGRdp08rcKGzASbgB(T%puW)RWda5O%aM>k@?kbYDJ7;mXg7)%7}|_U^u0g_?-vIh z3PLLno>;U^yRy;Ip#U%U`gz?3Q9dbXM|jd~=gzm4M_kLikKsE!!V_rWmyy}L8oj)= zS2fb?Im$rG8QwM!!;_UE8Rx|HP0%OX2>m!4{!$M9@ zmzycKXS|vvx3jAFOuN;#LOx%@xz-bPQB~L4+B$H!?W8hJu;wTX4KMQ=yEwA+byHJQ z4Srntp0Hr<_>yuo%x4&B_O`IRa^*|1XD(Z^^k)!1hMgXbR43&u9)Lcv`iBcipXe%2 zq_vq)1Omaa`(22J@|`C&yL#jc-3GtCI}p2cuqKsjiPzA?P2zh4jxQVm;07eyMCq?+ zYV8fOwUa-ksVNIq0FcPLSd^mM+Od*DToGaEjy4EpBb~T5rBg*r>d@@<%gYepB7JF0 zqq_ZhTTbt4e99^Fl9eP{muC7SQ?As-T7ZUt1HXW7`egSV>XAs%dT2+~9d#BA(P*)j z(D0-Wc6F=Xq;Ez*19MWIbzS0osT7X6ozKk>&N3dh)U{&Re&fo8P%s&w0N~{VcrIKq z2x~}d4RQmV;DFu^gWmrCgjZEc@Ze_b(=Aoh-_d=XJZ8+v)lKA~z%BN~S86rpYMt?0u zFkC3)tSau`mnY25=B{g)dM3owSbf=Vw0-aZz2T~fTHkJ@F6pcLmqLRS&;Cv>BWR!I z+RPN!dq?ck6I|axSa+4|B7lNzG$S`NkbWu8%wj3c6P@vb)pL!5@#dmB^TW{?vN zBGfH=G3iH<==4p-aBGihHuu9{(zqJ-xB51NXv62_%8>>T@awGan@0K^3i((iN+xo%#ouHt&I7j7;gA~ zaM|kYft59-NVWnweEfy~obuR!X;>4?FtKhWk9LQc+ATc4!u|H0t|p=C4#)UkIs1b* zU~l>r;^|xj-Rs_fd+|eK`kzi4=TVAO6y`vwsAMd7!IrRlB4EwT%Irr}B_*-~AjVn(;{-)H)yq<^yYV&jM#%$9>QVh%U z%UJHItG`bwI}ZY}o0&klMYUn~qrAe2#ymoOtW#gr9Dz%HofNmdj`t8&#p7n_pOvuZ z=F?L2tj|bH_{0E*sl4L|c!c+jV` zeXy-WWIHdBNTLXs_UIBMDy?(d=pS%;{K~$(^7C(zfUTgQC0m#>rkYzG!&0srmo+zP z%uIJAf4!wl*sSe43silWOG&I~w3z|7=J<^(E=H1Jo*@0}lR+k4a4{Z+7t=?Z<-^16 z#HH**nNR$)vabV9KteLt5UV>qWh13{~`%a65CIDvwi8xxILa6 z!t*MO@WlMq>6uJgtPOPTCQBxzspEI!dI! CCsuy| literal 0 HcmV?d00001 diff --git a/apps/meteor/public/images/featurePreview/resizable-contextual-bar.png b/apps/meteor/public/images/featurePreview/resizable-contextual-bar.png new file mode 100644 index 0000000000000000000000000000000000000000..c36c7e44a29d8c27c9c035a77026f1cd7e7dabd0 GIT binary patch literal 4776 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 a2K(3rHj$^VY%~U(889)lFep3k9Q`kU29J{f literal 0 HcmV?d00001 diff --git a/apps/meteor/public/images/featurePreview/timestamp.png b/apps/meteor/public/images/featurePreview/timestamp.png new file mode 100644 index 0000000000000000000000000000000000000000..7573f97db55b73e2d880af67e6705e3c4a2040c7 GIT binary patch literal 51432 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

&c?(AAUaFYNC38B5NhzYmJ_RR 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 p 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 i18nLabel: 'Sidebar_Sections_Order', i18nDescription: 'Sidebar_Sections_Order_Description', }); + + await this.add('Accounts_Default_User_Preferences_featuresPreview', '[]', { + type: 'string', + public: true, + }); }); await this.section('Avatar', async function () { diff --git a/apps/meteor/tests/end-to-end/api/miscellaneous.ts b/apps/meteor/tests/end-to-end/api/miscellaneous.ts index b8341f7c0994..d933f1f3c4b3 100644 --- a/apps/meteor/tests/end-to-end/api/miscellaneous.ts +++ b/apps/meteor/tests/end-to-end/api/miscellaneous.ts @@ -186,6 +186,7 @@ describe('miscellaneous', () => { 'muteFocusedConversations', 'notifyCalendarEvents', 'enableMobileRinging', + 'featuresPreview', ].filter((p) => Boolean(p)); expect(res.body).to.have.property('success', true); diff --git a/packages/i18n/src/locales/en.i18n.json b/packages/i18n/src/locales/en.i18n.json index 0e99c1bdc1d8..47d2034e002e 100644 --- a/packages/i18n/src/locales/en.i18n.json +++ b/packages/i18n/src/locales/en.i18n.json @@ -85,6 +85,7 @@ "Accounts_AllowEmailChange": "Allow Email Change", "Accounts_AllowEmailNotifications": "Allow Email Notifications", "Accounts_AllowFeaturePreview": "Allow Feature Preview", + "Accounts_AllowFeaturePreview_Description": "Make feature preview available to all workspace members.", "Accounts_AllowPasswordChange": "Allow Password Change", "Accounts_AllowPasswordChangeForOAuthUsers": "Allow Password Change for OAuth Users", "Accounts_AllowRealNameChange": "Allow Name Change", @@ -1125,8 +1126,8 @@ "Common_Access": "Common Access", "Commit": "Commit", "Community": "Community", - "Contextualbar_resizable": "Contextual bar resizable", - "Contextualbar_resizable_description": "Allows you to adjust the size of the contextual bar by simply dragging, giving you instant customization and flexibility", + "Contextualbar_resizable": "Resizable contextual bar", + "Contextualbar_resizable_description": "Adjust the size of the contextual bar by clicking and dragging the edge, giving you instant customization and flexibility.", "Free_Edition": "Free edition", "Composer_not_available_phone_calls": "Messages are not available on phone calls", "Condensed": "Condensed", @@ -1949,8 +1950,8 @@ "Enable_Password_History": "Enable Password History", "Enable_Password_History_Description": "When enabled, users won't be able to update their passwords to some of their most recently used passwords.", "Enable_Svg_Favicon": "Enable SVG favicon", - "Enable_timestamp": "Enable timestamp parsing in messages", - "Enable_timestamp_description": "Enable timestamps to be parsed in messages", + "Enable_timestamp": "Timestamp in messages", + "Enable_timestamp_description": "Render Unix timestamps inside messages in your local (system) timezone.", "Enable_to_bypass_email_verification": "Enable to bypass email verification", "Enable_two-factor_authentication": "Enable two-factor authentication via TOTP", "Enable_two-factor_authentication_email": "Enable two-factor authentication via Email", @@ -2284,7 +2285,10 @@ "Favorite_Rooms": "Enable Favorite Rooms", "Favorites": "Favorites", "Feature_preview": "Feature preview", - "Feature_preview_page_description": "Welcome to the features preview page! Here, you can enable the latest cutting-edge features that are currently under development and not yet officially released.\n\nPlease note that these configurations are still in the testing phase and may not be stable or fully functional.", + "Feature_preview_page_description": "Enable the latest features that are currently under development.", + "Feature_preview_page_callout": "Feature previews are being tested and may not be stable or fully functional. Features may become premium capabilities once officially released.", + "Feature_preview_admin_page_description": "Choose what feature previews to make available to workspace members.", + "Feature_preview_admin_page_callout": "Features enabled here will be enabled to each user in their feature preview preferences.", "featured": "featured", "Featured": "Featured", "Feature_depends_on_selected_call_provider_to_be_enabled_from_administration_settings": "This feature depends on the above selected call provider to be enabled from the administration settings (Admin -> Video Conference).", @@ -4364,7 +4368,7 @@ "Queue_Time": "Queue Time", "Queue_management": "Queue Management", "Quick_reactions": "Quick reactions", - "Quick_reactions_description": "The three most used reactions get an easy access while your mouse is over the message", + "Quick_reactions_description": "Easily access your most used and most recent emoji message reactions by hovering on a message.", "quote": "quote", "Quote": "Quote", "Random": "Random", diff --git a/packages/i18n/src/locales/hi-IN.i18n.json b/packages/i18n/src/locales/hi-IN.i18n.json index 090e081e83fa..3110d6e82a67 100644 --- a/packages/i18n/src/locales/hi-IN.i18n.json +++ b/packages/i18n/src/locales/hi-IN.i18n.json @@ -2169,7 +2169,6 @@ "Favorite_Rooms": "पसंदीदा कमरे सक्षम करें", "Favorites": "पसंदीदा", "Feature_preview": "फ़ीचर पूर्वावलोकन", - "Feature_preview_page_description": "फीचर पूर्वावलोकन पृष्ठ पर आपका स्वागत है! यहां, आप नवीनतम अत्याधुनिक सुविधाओं को सक्षम कर सकते हैं जो वर्तमान में विकास के अधीन हैं और अभी तक आधिकारिक तौर पर जारी नहीं की गई हैं।\n\nकृपया ध्यान दें कि ये कॉन्फ़िगरेशन अभी भी परीक्षण चरण में हैं और स्थिर या पूरी तरह कार्यात्मक नहीं हो सकते हैं।", "featured": "प्रदर्शित", "Featured": "प्रदर्शित", "Feature_depends_on_selected_call_provider_to_be_enabled_from_administration_settings": "यह सुविधा प्रशासन सेटिंग्स (एडमिन -> वीडियो कॉन्फ्रेंस) से सक्षम होने के लिए उपरोक्त चयनित कॉल प्रदाता पर निर्भर करती है।", @@ -4128,7 +4127,6 @@ "Queue_Time": "कतार समय", "Queue_management": "कतार प्रबंधन", "Quick_reactions": "त्वरित प्रतिक्रियाएँ", - "Quick_reactions_description": "जब आपका माउस संदेश पर होता है तो सबसे अधिक उपयोग की जाने वाली तीन प्रतिक्रियाओं तक आसान पहुंच मिलती है", "quote": "उद्धरण", "Quote": "उद्धरण", "Random": "Random", @@ -4987,7 +4985,7 @@ "The_application_will_be_able_to": "<1>{{appName}} यह करने में सक्षम होगा:", "The_channel_name_is_required": "चैनल का नाम आवश्यक है", "The_emails_are_being_sent": "ईमेल भेजे जा रहे हैं.", - "The_empty_room__roomName__will_be_removed_automatically": "खाली कमरा {{roomName}} स्वचालित रूप से हटा दिया जाएगा।", + "The_empty_room__roomName__will_be_removed_automatically": "खाली कमरा {{roomName}} स्वचालित रूप से हटा दिया जाएगा।", "The_image_resize_will_not_work_because_we_can_not_detect_ImageMagick_or_GraphicsMagick_installed_in_your_server": "छवि का आकार बदलना काम नहीं करेगा क्योंकि हम आपके सर्वर पर स्थापित ImageMagick या ग्राफ़िक्सMagick का पता नहीं लगा सकते हैं।", "The_message_is_a_discussion_you_will_not_be_able_to_recover": "संदेश एक चर्चा है आप संदेशों को पुनर्प्राप्त नहीं कर पाएंगे!", "The_mobile_notifications_were_disabled_to_all_users_go_to_Admin_Push_to_enable_the_Push_Gateway_again": "मोबाइल सूचनाएं सभी उपयोगकर्ताओं के लिए अक्षम कर दी गई थीं, पुश गेटवे को फिर से सक्षम करने के लिए \"एडमिन > पुश\" पर जाएं", @@ -6134,4 +6132,4 @@ "Unlimited_seats": "असीमित सीटें", "Unlimited_MACs": "असीमित एमएसी", "Unlimited_seats_MACs": "असीमित सीटें और एमएसी" -} \ No newline at end of file +} diff --git a/packages/ui-client/src/components/FeaturePreview/FeaturePreviewBadge.tsx b/packages/ui-client/src/components/FeaturePreview/FeaturePreviewBadge.tsx new file mode 100644 index 000000000000..eece30cc7280 --- /dev/null +++ b/packages/ui-client/src/components/FeaturePreview/FeaturePreviewBadge.tsx @@ -0,0 +1,21 @@ +import { Badge } from '@rocket.chat/fuselage'; +import { useTranslation } from '@rocket.chat/ui-contexts'; + +import { usePreferenceFeaturePreviewList } from '../../hooks/usePreferenceFeaturePreviewList'; + +const FeaturePreviewBadge = () => { + const t = useTranslation(); + const { unseenFeatures } = usePreferenceFeaturePreviewList(); + + if (!unseenFeatures) { + return null; + } + + return ( + + {unseenFeatures} + + ); +}; + +export default FeaturePreviewBadge; diff --git a/packages/ui-client/src/components/FeaturePreview/index.ts b/packages/ui-client/src/components/FeaturePreview/index.ts new file mode 100644 index 000000000000..f6b8e5f2071e --- /dev/null +++ b/packages/ui-client/src/components/FeaturePreview/index.ts @@ -0,0 +1,2 @@ +export { FeaturePreview, FeaturePreviewOn, FeaturePreviewOff } from './FeaturePreview'; +export { default as FeaturePreviewBadge } from './FeaturePreviewBadge'; diff --git a/packages/ui-client/src/components/index.ts b/packages/ui-client/src/components/index.ts index 8642983229aa..7308c8e75431 100644 --- a/packages/ui-client/src/components/index.ts +++ b/packages/ui-client/src/components/index.ts @@ -11,7 +11,7 @@ export * as UserStatus from './UserStatus'; export * from './Header'; export * from './HeaderV2'; export * from './MultiSelectCustom/MultiSelectCustom'; -export * from './FeaturePreview/FeaturePreview'; +export * from './FeaturePreview'; export * from './RoomBanner'; export { default as UserAutoComplete } from './UserAutoComplete'; export * from './GenericMenu'; diff --git a/packages/ui-client/src/hooks/useDefaultSettingFeaturePreviewList.ts b/packages/ui-client/src/hooks/useDefaultSettingFeaturePreviewList.ts new file mode 100644 index 000000000000..373862379cc1 --- /dev/null +++ b/packages/ui-client/src/hooks/useDefaultSettingFeaturePreviewList.ts @@ -0,0 +1,12 @@ +import { useSetting } from '@rocket.chat/ui-contexts'; +import { useMemo } from 'react'; + +import { parseSetting, useFeaturePreviewList } from './useFeaturePreviewList'; + +export const useDefaultSettingFeaturePreviewList = () => { + const featurePreviewSettingJSON = useSetting('Accounts_Default_User_Preferences_featuresPreview'); + + const settingFeaturePreview = useMemo(() => parseSetting(featurePreviewSettingJSON), [featurePreviewSettingJSON]); + + return useFeaturePreviewList(settingFeaturePreview ?? []); +}; diff --git a/packages/ui-client/src/hooks/useFeaturePreview.ts b/packages/ui-client/src/hooks/useFeaturePreview.ts index 4bdda9c9251a..bd46adfdefff 100644 --- a/packages/ui-client/src/hooks/useFeaturePreview.ts +++ b/packages/ui-client/src/hooks/useFeaturePreview.ts @@ -1,7 +1,8 @@ -import { type FeaturesAvailable, useFeaturePreviewList } from './useFeaturePreviewList'; +import { type FeaturesAvailable } from './useFeaturePreviewList'; +import { usePreferenceFeaturePreviewList } from './usePreferenceFeaturePreviewList'; export const useFeaturePreview = (featureName: FeaturesAvailable) => { - const { features } = useFeaturePreviewList(); + const { features } = usePreferenceFeaturePreviewList(); const currentFeature = features?.find((feature) => feature.name === featureName); diff --git a/packages/ui-client/src/hooks/useFeaturePreviewList.ts b/packages/ui-client/src/hooks/useFeaturePreviewList.ts index ff103a8d84ef..08bda4ff81ff 100644 --- a/packages/ui-client/src/hooks/useFeaturePreviewList.ts +++ b/packages/ui-client/src/hooks/useFeaturePreviewList.ts @@ -1,5 +1,4 @@ import type { TranslationKey } from '@rocket.chat/ui-contexts'; -import { useUserPreference, useSetting } from '@rocket.chat/ui-contexts'; export type FeaturesAvailable = | 'quickReactions' @@ -24,6 +23,7 @@ export type FeaturePreviewProps = { }; }; +// TODO: Move the features preview array to another directory to be accessed from both BE and FE. export const defaultFeaturesPreview: FeaturePreviewProps[] = [ { name: 'quickReactions', @@ -47,6 +47,7 @@ export const defaultFeaturesPreview: FeaturePreviewProps[] = [ i18n: 'Enable_timestamp', description: 'Enable_timestamp_description', group: 'Message', + imageUrl: 'images/featurePreview/timestamp.png', value: false, enabled: true, }, @@ -55,6 +56,7 @@ export const defaultFeaturesPreview: FeaturePreviewProps[] = [ i18n: 'Contextualbar_resizable', description: 'Contextualbar_resizable_description', group: 'Navigation', + imageUrl: 'images/featurePreview/resizable-contextual-bar.png', value: false, enabled: true, }, @@ -63,6 +65,7 @@ export const defaultFeaturesPreview: FeaturePreviewProps[] = [ i18n: 'New_navigation', description: 'New_navigation_description', group: 'Navigation', + imageUrl: 'images/featurePreview/enhanced-navigation.png', value: false, enabled: true, }, @@ -82,22 +85,27 @@ export const defaultFeaturesPreview: FeaturePreviewProps[] = [ export const enabledDefaultFeatures = defaultFeaturesPreview.filter((feature) => feature.enabled); -export const useFeaturePreviewList = () => { - const featurePreviewEnabled = useSetting('Accounts_AllowFeaturePreview'); - const userFeaturesPreview = useUserPreference('featuresPreview'); - - if (!featurePreviewEnabled) { - return { unseenFeatures: 0, features: [] as FeaturePreviewProps[], featurePreviewEnabled }; +// TODO: Remove this logic after we have a way to store object settings. +export const parseSetting = (setting?: FeaturePreviewProps[] | string) => { + if (typeof setting === 'string') { + try { + return JSON.parse(setting) as FeaturePreviewProps[]; + } catch (_) { + return; + } } + return setting; +}; +export const useFeaturePreviewList = (featuresList: Pick[]) => { const unseenFeatures = enabledDefaultFeatures.filter( - (feature) => !userFeaturesPreview?.find((userFeature) => userFeature.name === feature.name), + (defaultFeature) => !featuresList?.find((feature) => feature.name === defaultFeature.name), ).length; - const mergedFeatures = enabledDefaultFeatures.map((feature) => { - const userFeature = userFeaturesPreview?.find((userFeature) => userFeature.name === feature.name); - return { ...feature, ...userFeature }; + const mergedFeatures = enabledDefaultFeatures.map((defaultFeature) => { + const features = featuresList?.find((feature) => feature.name === defaultFeature.name); + return { ...defaultFeature, ...features }; }); - return { unseenFeatures, features: mergedFeatures, featurePreviewEnabled }; + return { unseenFeatures, features: mergedFeatures }; }; diff --git a/packages/ui-client/src/hooks/useFeaturePreviewList.spec.tsx b/packages/ui-client/src/hooks/usePreferenceFeaturePreviewList.spec.tsx similarity index 79% rename from packages/ui-client/src/hooks/useFeaturePreviewList.spec.tsx rename to packages/ui-client/src/hooks/usePreferenceFeaturePreviewList.spec.tsx index e348cfb6a864..ac3d6f92d51a 100644 --- a/packages/ui-client/src/hooks/useFeaturePreviewList.spec.tsx +++ b/packages/ui-client/src/hooks/usePreferenceFeaturePreviewList.spec.tsx @@ -1,10 +1,11 @@ import { mockAppRoot } from '@rocket.chat/mock-providers'; import { renderHook } from '@testing-library/react'; -import { useFeaturePreviewList, enabledDefaultFeatures } from './useFeaturePreviewList'; +import { enabledDefaultFeatures } from './useFeaturePreviewList'; +import { usePreferenceFeaturePreviewList } from './usePreferenceFeaturePreviewList'; it('should return the number of unseen features and Accounts_AllowFeaturePreview enabled ', () => { - const { result } = renderHook(() => useFeaturePreviewList(), { + const { result } = renderHook(() => usePreferenceFeaturePreviewList(), { legacyRoot: true, wrapper: mockAppRoot().withSetting('Accounts_AllowFeaturePreview', true).build(), }); @@ -18,7 +19,7 @@ it('should return the number of unseen features and Accounts_AllowFeaturePreview }); it('should return the number of unseen features and Accounts_AllowFeaturePreview disabled ', () => { - const { result } = renderHook(() => useFeaturePreviewList(), { + const { result } = renderHook(() => usePreferenceFeaturePreviewList(), { legacyRoot: true, wrapper: mockAppRoot().withSetting('Accounts_AllowFeaturePreview', false).build(), }); @@ -32,7 +33,7 @@ it('should return the number of unseen features and Accounts_AllowFeaturePreview }); it('should return 0 unseen features', () => { - const { result } = renderHook(() => useFeaturePreviewList(), { + const { result } = renderHook(() => usePreferenceFeaturePreviewList(), { legacyRoot: true, wrapper: mockAppRoot() .withSetting('Accounts_AllowFeaturePreview', true) @@ -49,7 +50,7 @@ it('should return 0 unseen features', () => { }); it('should ignore removed feature previews', () => { - const { result } = renderHook(() => useFeaturePreviewList(), { + const { result } = renderHook(() => usePreferenceFeaturePreviewList(), { legacyRoot: true, wrapper: mockAppRoot() .withSetting('Accounts_AllowFeaturePreview', true) @@ -72,7 +73,7 @@ it('should ignore removed feature previews', () => { }); it('should turn off ignored feature previews', async () => { - const { result } = renderHook(() => useFeaturePreviewList(), { + const { result } = renderHook(() => usePreferenceFeaturePreviewList(), { legacyRoot: true, wrapper: mockAppRoot() .withSetting('Accounts_AllowFeaturePreview', true) diff --git a/packages/ui-client/src/hooks/usePreferenceFeaturePreviewList.ts b/packages/ui-client/src/hooks/usePreferenceFeaturePreviewList.ts new file mode 100644 index 000000000000..d7c4c13417d2 --- /dev/null +++ b/packages/ui-client/src/hooks/usePreferenceFeaturePreviewList.ts @@ -0,0 +1,16 @@ +import { useSetting, useUserPreference } from '@rocket.chat/ui-contexts'; +import { useMemo } from 'react'; + +import { FeaturePreviewProps, parseSetting, useFeaturePreviewList } from './useFeaturePreviewList'; + +export const usePreferenceFeaturePreviewList = () => { + const featurePreviewEnabled = useSetting('Accounts_AllowFeaturePreview'); + const userFeaturesPreviewPreference = useUserPreference('featuresPreview'); + const userFeaturesPreview = useMemo(() => parseSetting(userFeaturesPreviewPreference), [userFeaturesPreviewPreference]); + const { unseenFeatures, features } = useFeaturePreviewList(userFeaturesPreview ?? []); + + if (!featurePreviewEnabled) { + return { unseenFeatures: 0, features: [] as FeaturePreviewProps[], featurePreviewEnabled }; + } + return { unseenFeatures, features, featurePreviewEnabled }; +}; diff --git a/packages/ui-client/src/index.ts b/packages/ui-client/src/index.ts index 3e640343da5b..a96ef265aadc 100644 --- a/packages/ui-client/src/index.ts +++ b/packages/ui-client/src/index.ts @@ -1,5 +1,7 @@ export * from './components'; export * from './hooks/useFeaturePreview'; +export * from './hooks/useDefaultSettingFeaturePreviewList'; export * from './hooks/useFeaturePreviewList'; +export * from './hooks/usePreferenceFeaturePreviewList'; export * from './hooks/useDocumentTitle'; export * from './helpers';