diff --git a/apps/web/.env.production b/apps/web/.env.production index 06b4236a8903fb71f8f8a6bdc0c1c3e3cde80360..37668148ae86e66d1f577013ccbdf557c48f5562 100644 --- a/apps/web/.env.production +++ b/apps/web/.env.production @@ -8,4 +8,16 @@ VITE_BACKEND_QUERY=/query VITE_BACKEND_SCHEMA=/schema SENTRY_ENABLED=false -SENTRY_URL= \ No newline at end of file +SENTRY_URL= + +WIP_TABLEVIS=false +WIP_NODELINKVIS=false +WIP_RAWJSONVIS=false +WIP_PAOHVIS=true +WIP_MATRIXVIS=true +WIP_SEMANTICSUBSTRATESVIS=true +WIP_MAPVIS=true + +WIP_INSIGHT_SHARING=true +WIP_VIEWER_PERMISSIONS=true +WIP_SHARABLE_EXPLORATION=true \ No newline at end of file diff --git a/apps/web/src/components/navbar/navbar.tsx b/apps/web/src/components/navbar/navbar.tsx index 3307e9dc846c12f362f547168998eba70d172539..56dcaef7c70edf33e3628d883055ceea94394b8e 100644 --- a/apps/web/src/components/navbar/navbar.tsx +++ b/apps/web/src/components/navbar/navbar.tsx @@ -18,13 +18,13 @@ import { useDispatch } from 'react-redux'; import { Dialog, DialogContent, DialogTrigger } from '@graphpolaris/shared/lib/components/layout/Dialog'; import { UserManagementContent } from '@graphpolaris/shared/lib/components/panels/userManagementContent/UserManagementContent'; import { addInfo } from '@graphpolaris/shared/lib/data-access/store/configSlice'; +import { showManagePermissions, showSharableExploration } from 'config'; export const Navbar = () => { const dropdownRef = useRef<HTMLDivElement>(null); const auth = useAuth(); const authCache = useAuthorizationCache(); const [menuOpen, setMenuOpen] = useState(false); - const [reportingOpen, setReportingOpen] = useState(false); const dispatch = useDispatch(); const buildInfo = import.meta.env.GRAPHPOLARIS_VERSION; @@ -97,12 +97,14 @@ export const Navbar = () => { </div> {authCache.authorized ? ( <> - <DropdownItem - value="Share" - onClick={() => { - auth.newShareRoom(); - }} - /> + {showSharableExploration() && ( + <DropdownItem + value="Share" + onClick={() => { + auth.newShareRoom(); + }} + /> + )} <DropdownItem value="Settings" onClick={() => {}} /> <DropdownItem value="Log out" onClick={() => {}} /> </> @@ -119,7 +121,7 @@ export const Navbar = () => { <div className="p-2 border-t"> <h3 className="text-xs">Version: {buildInfo}</h3> </div> - {writeAllowed && ( + {showManagePermissions() && writeAllowed && ( <> <Dialog> <DialogTrigger className="ml-2 text-sm hover:bg-secondary-200">Manage Viewers Permission</DialogTrigger> diff --git a/libs/config/src/featureFlags.ts b/libs/config/src/featureFlags.ts new file mode 100644 index 0000000000000000000000000000000000000000..b6364d037ede7d1d7677ba42c2c43c626a632356 --- /dev/null +++ b/libs/config/src/featureFlags.ts @@ -0,0 +1,32 @@ +// Safely retrieve environment variable values with a default fallback +const getEnvVariable = (key: string, defaultValue: string = 'false'): string => { + return import.meta.env[key] ?? defaultValue; +}; + +// Check if the environment is production +const isProduction = (): boolean => { + return getEnvVariable('GRAPHPOLARIS_VERSION', 'dev') === 'prod'; +}; + +// Check if the Manage Permissions feature is enabled +const showManagePermissions = (): boolean => { + return !isProduction() || (isProduction() && getEnvVariable('WIP_VIEWER_PERMISSIONS') === 'false'); +}; + +// Check if the Insight Sharing feature is enabled +const showInsightSharing = (): boolean => { + return !isProduction() || (isProduction() && getEnvVariable('WIP_INSIGHT_SHARING') === 'false'); +}; + +// Check if the Insight Sharing feature is enabled +const showSharableExploration = (): boolean => { + return !isProduction() || (isProduction() && getEnvVariable('WIP_SHARABLE_EXPLORATION') === 'false'); +}; + +// Utility to check if a specific visualization is released based on environment variables +const isVisualizationReleased = (visualizationName: string): boolean => { + const visualizationFlag = getEnvVariable(`WIP_${visualizationName.toUpperCase()}`, 'false'); + return !isProduction() || (isProduction() && visualizationFlag === 'false'); +}; + +export { isProduction, showManagePermissions, showInsightSharing, showSharableExploration, isVisualizationReleased }; diff --git a/libs/config/src/index.ts b/libs/config/src/index.ts index 1bae1c0e497ca31494e4b781ecbd04b1ea49c67d..caecba356a9e756847550b9499db1163e1ba5345 100644 --- a/libs/config/src/index.ts +++ b/libs/config/src/index.ts @@ -1 +1,2 @@ export * from './colors'; +export * from './featureFlags'; diff --git a/libs/shared/lib/sidebar/index.tsx b/libs/shared/lib/sidebar/index.tsx index f50045841392b4ceacb4070147f01a3c65cfac07..9c45f29bdfa6a4d4c9de9541a32b4d8374e06d3c 100644 --- a/libs/shared/lib/sidebar/index.tsx +++ b/libs/shared/lib/sidebar/index.tsx @@ -24,6 +24,9 @@ export function Sidebar({ tab: SideNavTab; openMonitoringDialog: () => void; }) { + const isProd = import.meta.env.GRAPHPOLARIS_VERSION === 'prod'; + const isInsightSharingWIP = import.meta.env.WIP_INSIGHT_SHARING === 'true'; + return ( <div className="side-bar w-fit h-full flex shrink"> <TooltipProvider delayDuration={100}> @@ -49,18 +52,22 @@ export function Sidebar({ <TooltipContent>{t.name}</TooltipContent> </Tooltip> ))} - <Tooltip placement={'right'}> - <TooltipTrigger asChild> - <Button - variantType="secondary" - variant="ghost" - size="sm" - iconComponent="icon-[ic--outline-analytics]" - onClick={openMonitoringDialog} - /> - </TooltipTrigger> - <TooltipContent>Insight Sharing</TooltipContent> - </Tooltip> + + {(!isProd || (isProd && !isInsightSharingWIP)) && ( + <Tooltip placement={'right'}> + <TooltipTrigger asChild> + <Button + variantType="secondary" + variant="ghost" + size="sm" + iconComponent="icon-[ic--outline-analytics]" + onClick={openMonitoringDialog} + /> + </TooltipTrigger> + <TooltipContent>Insight Sharing</TooltipContent> + </Tooltip> + )} + <div className="mt-auto mb-2"> <ColorMode /> </div> diff --git a/libs/shared/lib/vis/components/VisualizationPanel.tsx b/libs/shared/lib/vis/components/VisualizationPanel.tsx index b39ab2f80b3f0f0e7fb2a4da996ba180263c9672..8f178196bc139840517584d4a66c1f719317b273 100644 --- a/libs/shared/lib/vis/components/VisualizationPanel.tsx +++ b/libs/shared/lib/vis/components/VisualizationPanel.tsx @@ -17,17 +17,21 @@ import { updateVisualization, addVisualization } from '../../data-access/store/v import { VisualizationPropTypes, VISComponentType } from '../common'; import { ErrorBoundary } from '../../components/errorBoundary'; import { addError } from '../../data-access/store/configSlice'; +import { isVisualizationReleased } from 'config'; type PromiseFunc = () => Promise<{ default: VISComponentType<any> }>; export const Visualizations: Record<string, PromiseFunc> = { - TableVis: () => import('../visualizations/tablevis/tablevis'), - PaohVis: () => import('../visualizations/paohvis/paohvis'), - RawJSONVis: () => import('../visualizations/rawjsonvis/rawjsonvis'), - NodeLinkVis: () => import('../visualizations/nodelinkvis/nodelinkvis'), - MatrixVis: () => import('../visualizations/matrixvis/matrixvis'), - SemanticSubstratesVis: () => import('../visualizations/semanticsubstratesvis/semanticsubstratesvis'), - MapVis: () => import('../visualizations/mapvis/mapvis'), + ...(isVisualizationReleased('TableVis') && { TableVis: () => import('../visualizations/tablevis/tablevis') }), + ...(isVisualizationReleased('PaohVis') && { PaohVis: () => import('../visualizations/paohvis/paohvis') }), + ...(isVisualizationReleased('RawJSONVis') && { RawJSONVis: () => import('../visualizations/rawjsonvis/rawjsonvis') }), + ...(isVisualizationReleased('NodeLinkVis') && { NodeLinkVis: () => import('../visualizations/nodelinkvis/nodelinkvis') }), + ...(isVisualizationReleased('MatrixVis') && { MatrixVis: () => import('../visualizations/matrixvis/matrixvis') }), + ...(isVisualizationReleased('SemanticSubstratesVis') && { + SemanticSubstratesVis: () => import('../visualizations/semanticsubstratesvis/semanticsubstratesvis'), + }), + ...(isVisualizationReleased('MapVis') && { MapVis: () => import('../visualizations/mapvis/mapvis') }), }; + export const VISUALIZATION_TYPES: string[] = Object.keys(Visualizations); export const VisualizationPanel = ({ fullSize }: { fullSize: () => void }) => { diff --git a/libs/shared/lib/vis/views/Recommender.tsx b/libs/shared/lib/vis/views/Recommender.tsx index 9fb611c29f7c87294e6d1e2232c7c12c3003e5c8..9417884364098bcdf6edea448cd496d105d1895a 100644 --- a/libs/shared/lib/vis/views/Recommender.tsx +++ b/libs/shared/lib/vis/views/Recommender.tsx @@ -3,6 +3,7 @@ import Info from '../../components/info'; import { addVisualization } from '../../data-access/store/visualizationSlice'; import { useAppDispatch, useCheckPermissionPolicy } from '../../data-access'; import { Visualizations } from '../components/VisualizationPanel'; +import { isVisualizationReleased } from 'config'; type VisualizationDescription = { name: string;