From 69369ab72b163eedc4d474251d30b19c27c11e42 Mon Sep 17 00:00:00 2001 From: Novak Zaballa Date: Mon, 24 Jun 2024 12:14:18 -0400 Subject: [PATCH 1/6] feat: Announcement feature flag per page --- frontend/web/components/App.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/frontend/web/components/App.js b/frontend/web/components/App.js index cc4bd77e9bcd..d8454e674ced 100644 --- a/frontend/web/components/App.js +++ b/frontend/web/components/App.js @@ -356,6 +356,9 @@ const App = class extends Component { (!dismissed || dismissed !== announcementValue.id) && Utils.getFlagsmithHasFeature('announcement') && this.state.showAnnouncement + const announcementInPage = announcementValue?.pages?.some((page) => + pathname.includes(page), + ) const isOrganisationSelect = document.location.pathname === '/organisations' const integrations = Object.keys( JSON.parse(Utils.getFlagsmithValue('integration_data') || '{}'), @@ -390,7 +393,8 @@ const App = class extends Component { } /> )} - {user && showBanner && ( + {((user && showBanner && !announcementValue?.pages) || + announcementInPage) && (
Date: Tue, 25 Jun 2024 10:17:24 -0400 Subject: [PATCH 2/6] Add AnnouncementPerPage component --- .../web/components/AnnouncementPerPage.tsx | 46 +++++++++++++++++++ frontend/web/components/App.js | 24 ++++++++-- 2 files changed, 67 insertions(+), 3 deletions(-) create mode 100644 frontend/web/components/AnnouncementPerPage.tsx diff --git a/frontend/web/components/AnnouncementPerPage.tsx b/frontend/web/components/AnnouncementPerPage.tsx new file mode 100644 index 000000000000..2581308c1bdd --- /dev/null +++ b/frontend/web/components/AnnouncementPerPage.tsx @@ -0,0 +1,46 @@ +import React, { FC } from 'react' +import InfoMessage from './InfoMessage' +import flagsmith from 'flagsmith' + +type AnnouncementPerPageValueType = { + id: string + title: string + description: string + isClosable: boolean + buttonText: string + url: string +} + +type AnnouncementPerPageType = { + announcementPerPageValue: AnnouncementPerPageValueType +} + +const AnnouncementPerPage: FC = ({ + announcementPerPageValue, +}) => { + const { buttonText, description, id, isClosable, title, url } = + announcementPerPageValue + const closeAnnouncement = (id: string) => { + flagsmith.setTrait(`dismissed_announcement_per_page`, id) + } + + return ( +
+
+ closeAnnouncement(id)} + buttonText={buttonText} + url={url} + > +
+
{description}
+
+
+
+
+ ) +} + +export default AnnouncementPerPage diff --git a/frontend/web/components/App.js b/frontend/web/components/App.js index d8454e674ced..c67186700438 100644 --- a/frontend/web/components/App.js +++ b/frontend/web/components/App.js @@ -36,6 +36,7 @@ import AuditLogIcon from './svg/AuditLogIcon' import Permission from 'common/providers/Permission' import HomeAside from './pages/HomeAside' import ScrollToTop from './ScrollToTop' +import AnnouncementPerPage from './AnnouncementPerPage' const App = class extends Component { static propTypes = { @@ -350,13 +351,25 @@ const App = class extends Component { return
{this.props.children}
} const announcementValue = Utils.getFlagsmithJSONValue('announcement', null) + const announcementPerPageDismissed = flagsmith.getTrait( + 'dismissed_announcement_per_page', + ) + const announcementPerPageValue = Utils.getFlagsmithJSONValue( + 'announcement_per_page', + null, + ) + const showAnnouncementPerPage = + !announcementPerPageDismissed || + announcementPerPageDismissed !== announcementPerPageValue.id + Utils.getFlagsmithHasFeature('announcement_per_page') && + announcementPerPageValue?.pages?.length > 0 const dismissed = flagsmith.getTrait('dismissed_announcement') const showBanner = announcementValue && (!dismissed || dismissed !== announcementValue.id) && Utils.getFlagsmithHasFeature('announcement') && this.state.showAnnouncement - const announcementInPage = announcementValue?.pages?.some((page) => + const announcementInPage = announcementPerPageValue?.pages?.some((page) => pathname.includes(page), ) const isOrganisationSelect = document.location.pathname === '/organisations' @@ -393,8 +406,7 @@ const App = class extends Component { } /> )} - {((user && showBanner && !announcementValue?.pages) || - announcementInPage) && ( + {user && showBanner && (
)} + {user && showAnnouncementPerPage && announcementInPage && ( + + )} + {this.props.children} )} From 3b4b45a370ead73fbb02cc688fd9c5f4f49b9a6c Mon Sep 17 00:00:00 2001 From: Novak Zaballa Date: Tue, 25 Jun 2024 12:52:20 -0400 Subject: [PATCH 3/6] Add Announcement component --- frontend/web/components/Announcement.tsx | 51 +++++++++++++++++++ .../web/components/AnnouncementPerPage.tsx | 47 ++++++++++------- frontend/web/components/App.js | 45 ++-------------- 3 files changed, 83 insertions(+), 60 deletions(-) create mode 100644 frontend/web/components/Announcement.tsx diff --git a/frontend/web/components/Announcement.tsx b/frontend/web/components/Announcement.tsx new file mode 100644 index 000000000000..291aebc53c6e --- /dev/null +++ b/frontend/web/components/Announcement.tsx @@ -0,0 +1,51 @@ +import React, { FC } from 'react' +import InfoMessage from './InfoMessage' +import flagsmith from 'flagsmith' +import Utils from 'common/utils/utils' + +export type AnnouncementValueType = { + id: string + title: string + description: string + isClosable: boolean + buttonText: string + url: string +} + +type AnnouncementType = {} + +const Announcement: FC = () => { + const closeAnnouncement = (id: string) => { + flagsmith.setTrait(`dismissed_announcement`, id) + } + + const announcementValue = Utils.getFlagsmithJSONValue('announcement', null) + const { buttonText, description, id, isClosable, title, url } = + announcementValue as AnnouncementValueType + const dismissed = flagsmith.getTrait('dismissed_announcement') + + const showBanner = + announcementValue && + (!dismissed || dismissed !== announcementValue.id) && + Utils.getFlagsmithHasFeature('announcement') + + return ( + <> + {showBanner && ( + closeAnnouncement(id)} + buttonText={buttonText} + url={url} + > +
+
{description}
+
+
+ )} + + ) +} + +export default Announcement diff --git a/frontend/web/components/AnnouncementPerPage.tsx b/frontend/web/components/AnnouncementPerPage.tsx index 2581308c1bdd..76a9ee66a929 100644 --- a/frontend/web/components/AnnouncementPerPage.tsx +++ b/frontend/web/components/AnnouncementPerPage.tsx @@ -1,32 +1,41 @@ import React, { FC } from 'react' import InfoMessage from './InfoMessage' import flagsmith from 'flagsmith' +import Utils from 'common/utils/utils' +import { AnnouncementValueType } from './Announcement' -type AnnouncementPerPageValueType = { - id: string - title: string - description: string - isClosable: boolean - buttonText: string - url: string +type AnnouncementPerPageValueType = AnnouncementValueType & { + pages: string[] } -type AnnouncementPerPageType = { - announcementPerPageValue: AnnouncementPerPageValueType -} +type AnnouncementPerPageType = { pathname: string } -const AnnouncementPerPage: FC = ({ - announcementPerPageValue, -}) => { - const { buttonText, description, id, isClosable, title, url } = - announcementPerPageValue +const AnnouncementPerPage: FC = ({ pathname }) => { const closeAnnouncement = (id: string) => { flagsmith.setTrait(`dismissed_announcement_per_page`, id) } + const announcementPerPageDismissed = flagsmith.getTrait( + 'dismissed_announcement_per_page', + ) + const announcementPerPageValue = Utils.getFlagsmithJSONValue( + 'announcement_per_page', + null, + ) as AnnouncementPerPageValueType + + const { buttonText, description, id, isClosable, pages, title, url } = + announcementPerPageValue + + const showAnnouncementPerPage = + (!announcementPerPageDismissed || + announcementPerPageDismissed !== announcementPerPageValue.id) && + Utils.getFlagsmithHasFeature('announcement_per_page') && + pages?.length > 0 + + const announcementInPage = pages?.some((page) => pathname.includes(page)) return ( -
-
+ <> + {showAnnouncementPerPage && announcementInPage && ( = ({
{description}
-
-
+ )} + ) } diff --git a/frontend/web/components/App.js b/frontend/web/components/App.js index c67186700438..c58d89dfe1ac 100644 --- a/frontend/web/components/App.js +++ b/frontend/web/components/App.js @@ -37,6 +37,7 @@ import Permission from 'common/providers/Permission' import HomeAside from './pages/HomeAside' import ScrollToTop from './ScrollToTop' import AnnouncementPerPage from './AnnouncementPerPage' +import Announcement from './Announcement' const App = class extends Component { static propTypes = { @@ -350,28 +351,6 @@ const App = class extends Component { if (document.location.href.includes('widget')) { return
{this.props.children}
} - const announcementValue = Utils.getFlagsmithJSONValue('announcement', null) - const announcementPerPageDismissed = flagsmith.getTrait( - 'dismissed_announcement_per_page', - ) - const announcementPerPageValue = Utils.getFlagsmithJSONValue( - 'announcement_per_page', - null, - ) - const showAnnouncementPerPage = - !announcementPerPageDismissed || - announcementPerPageDismissed !== announcementPerPageValue.id - Utils.getFlagsmithHasFeature('announcement_per_page') && - announcementPerPageValue?.pages?.length > 0 - const dismissed = flagsmith.getTrait('dismissed_announcement') - const showBanner = - announcementValue && - (!dismissed || dismissed !== announcementValue.id) && - Utils.getFlagsmithHasFeature('announcement') && - this.state.showAnnouncement - const announcementInPage = announcementPerPageValue?.pages?.some((page) => - pathname.includes(page), - ) const isOrganisationSelect = document.location.pathname === '/organisations' const integrations = Object.keys( JSON.parse(Utils.getFlagsmithValue('integration_data') || '{}'), @@ -406,30 +385,14 @@ const App = class extends Component { } /> )} - {user && showBanner && ( + {user && (
- - this.closeAnnouncement(announcementValue.id) - } - buttonText={announcementValue.buttonText} - url={announcementValue.url} - > -
-
{announcementValue.description}
-
-
+ +
)} - {user && showAnnouncementPerPage && announcementInPage && ( - - )} {this.props.children} From 94d46462cfd2f7cc4adf65d0c2006f4c7a68d01a Mon Sep 17 00:00:00 2001 From: Novak Zaballa Date: Wed, 26 Jun 2024 13:44:36 -0400 Subject: [PATCH 4/6] Update how the announcements are displayed --- frontend/web/components/App.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/web/components/App.js b/frontend/web/components/App.js index c58d89dfe1ac..5df9a8ed880f 100644 --- a/frontend/web/components/App.js +++ b/frontend/web/components/App.js @@ -387,7 +387,7 @@ const App = class extends Component { )} {user && (
-
+
From 971c2fce6882bd631b6ecc9dd48fde45668bf2dd Mon Sep 17 00:00:00 2001 From: Novak Zaballa Date: Wed, 26 Jun 2024 14:25:21 -0400 Subject: [PATCH 5/6] Solve no FF value issue --- .../web/components/AnnouncementPerPage.tsx | 21 +++++++++---------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/frontend/web/components/AnnouncementPerPage.tsx b/frontend/web/components/AnnouncementPerPage.tsx index 76a9ee66a929..35ead3bceec3 100644 --- a/frontend/web/components/AnnouncementPerPage.tsx +++ b/frontend/web/components/AnnouncementPerPage.tsx @@ -23,28 +23,27 @@ const AnnouncementPerPage: FC = ({ pathname }) => { null, ) as AnnouncementPerPageValueType - const { buttonText, description, id, isClosable, pages, title, url } = - announcementPerPageValue - const showAnnouncementPerPage = (!announcementPerPageDismissed || announcementPerPageDismissed !== announcementPerPageValue.id) && Utils.getFlagsmithHasFeature('announcement_per_page') && - pages?.length > 0 + announcementPerPageValue?.pages?.length > 0 - const announcementInPage = pages?.some((page) => pathname.includes(page)) + const announcementInPage = announcementPerPageValue?.pages?.some((page) => + pathname.includes(page), + ) return ( <> {showAnnouncementPerPage && announcementInPage && ( closeAnnouncement(id)} - buttonText={buttonText} - url={url} + title={announcementPerPageValue?.title} + isClosable={announcementPerPageValue?.isClosable} + close={() => closeAnnouncement(announcementPerPageValue?.id)} + buttonText={announcementPerPageValue?.buttonText} + url={announcementPerPageValue?.url} >
-
{description}
+
{announcementPerPageValue?.description}
)} From 8c7a2a0965e5b5f5e821566d8fca6fc1d0ff86e7 Mon Sep 17 00:00:00 2001 From: novakzaballa Date: Thu, 27 Jun 2024 12:05:19 -0400 Subject: [PATCH 6/6] Use machPath --- .../web/components/AnnouncementPerPage.tsx | 15 +- frontend/web/routes.js | 160 ++++++++++++------ 2 files changed, 119 insertions(+), 56 deletions(-) diff --git a/frontend/web/components/AnnouncementPerPage.tsx b/frontend/web/components/AnnouncementPerPage.tsx index 35ead3bceec3..4d357df81758 100644 --- a/frontend/web/components/AnnouncementPerPage.tsx +++ b/frontend/web/components/AnnouncementPerPage.tsx @@ -3,6 +3,8 @@ import InfoMessage from './InfoMessage' import flagsmith from 'flagsmith' import Utils from 'common/utils/utils' import { AnnouncementValueType } from './Announcement' +import { matchPath } from 'react-router' +import { routes } from 'web/routes' type AnnouncementPerPageValueType = AnnouncementValueType & { pages: string[] @@ -29,9 +31,16 @@ const AnnouncementPerPage: FC = ({ pathname }) => { Utils.getFlagsmithHasFeature('announcement_per_page') && announcementPerPageValue?.pages?.length > 0 - const announcementInPage = announcementPerPageValue?.pages?.some((page) => - pathname.includes(page), - ) + const announcementInPage = announcementPerPageValue?.pages?.some((page) => { + if (Object.keys(routes).includes(page)) { + return !!matchPath(pathname, { + exact: false, + path: routes[page], + strict: false, + }) + } + return false + }) return ( <> {showAnnouncementPerPage && announcementInPage && ( diff --git a/frontend/web/routes.js b/frontend/web/routes.js index f91b836d9044..24a113eb7645 100644 --- a/frontend/web/routes.js +++ b/frontend/web/routes.js @@ -41,172 +41,226 @@ import SDKKeysPage from './components/SDKKeysPage' import { ParameterizedRoute } from './components/base/higher-order/ParameterizedRoute' import FeatureHistoryDetailPage from './components/pages/FeatureHistoryDetailPage' +export const routes = { + 'root': '/', + 'login': '/login', + 'not-found': '/404', + 'signup': '/signup', + 'home': '/home', + 'github-setup': '/github-setup', + 'maintenance': '/maintenance', + 'password-reset': '/password-reset/confirm/:uid/:token/', + 'features': '/project/:projectId/environment/:environmentId/features', + 'change-requests': + '/project/:projectId/environment/:environmentId/change-requests', + 'scheduled-changes': + '/project/:projectId/environment/:environmentId/scheduled-changes', + 'change-request': + '/project/:projectId/environment/:environmentId/change-requests/:id', + 'scheduled-change': + '/project/:projectId/environment/:environmentId/scheduled-changes/:id', + 'widget': '/widget', + 'invite': '/invite/:id', + 'invite-link': '/invite-link/:id', + 'broken': '/broken', + 'oauth': '/oauth/:type', + 'saml': '/saml', + 'environment-settings': + '/project/:projectId/environment/:environmentId/settings', + 'sdk-keys': '/project/:projectId/environment/:environmentId/sdk-keys', + 'integrations': '/project/:projectId/integrations', + 'users': '/project/:projectId/environment/:environmentId/users', + 'user-id': '/project/:projectId/environment/:environmentId/users/:identity', + 'user': '/project/:projectId/environment/:environmentId/users/:identity/:id', + 'create-environment': '/project/:projectId/environment/create', + 'project-settings-in-environment': + '/project/:projectId/environment/:environmentId/project-settings', + 'compare': '/project/:projectId/compare', + 'feature-history': '/project/:projectId/environment/:environmentId/history', + 'feature-history-detail': + '/project/:projectId/environment/:environmentId/history/:id/', + 'project-settings': '/project/:projectId/settings', + 'permissions': '/project/:projectId/permissions', + 'segments': '/project/:projectId/segments', + 'organisation-settings': '/organisation/:organisationId/settings', + 'organisation-permissions': '/organisation/:organisationId/permissions', + 'organisation-usage': '/organisation/:organisationId/usage', + 'organisation-settings-redirect': '/organisation-settings', + 'organisation-projects': '/organisation/:organisationId/projects', + 'account-settings': '/project/:projectId/environment/:environmentId/account', + 'audit-log': '/project/:projectId/audit-log', + 'organisations': '/organisations', + 'audit-log-item': '/project/:projectId/audit-log/:id', + 'create-organisation': '/create', + 'project-redirect': '/project/:projectId', + 'account': '/account', +} export default ( - - - - - + + + + + {Utils.getFlagsmithHasFeature('github_integration') && ( - + )} - + - - - - - - + + + + + + + - + - - + - + - +