restrict certain routes to admins

This commit is contained in:
Nate Kelley 2025-01-23 11:20:48 -07:00
parent aa190a73de
commit 4de70a3420
No known key found for this signature in database
GPG Key ID: FD90372AB8D98B4F
107 changed files with 111 additions and 58 deletions

View File

@ -1,8 +1,8 @@
'use client'; 'use client';
import React from 'react'; import React from 'react';
import { SettingsEmptyState } from '../_SettingsEmptyState'; import { SettingsEmptyState } from '../../_components/SettingsEmptyState';
import { SettingsPageHeader } from '../_SettingsPageHeader'; import { SettingsPageHeader } from '../../_components/SettingsPageHeader';
export default function Page() { export default function Page() {
return ( return (

View File

@ -1,6 +1,6 @@
'use client'; 'use client';
import React, { useState } from 'react'; import React, { useState } from 'react';
import { SettingsPageHeader } from '../_SettingsPageHeader'; import { SettingsPageHeader } from '../../_components/SettingsPageHeader';
import { PermissionSearch, NewDatasetGroupModal } from '@appComponents/PermissionComponents'; import { PermissionSearch, NewDatasetGroupModal } from '@appComponents/PermissionComponents';
import { useDebounceSearch } from '@/hooks/useDebounceSearch'; import { useDebounceSearch } from '@/hooks/useDebounceSearch';
import { useListDatasetGroups } from '@/api/buster_rest'; import { useListDatasetGroups } from '@/api/buster_rest';

View File

@ -0,0 +1,17 @@
import { BusterRoutes, createBusterRoute } from '@/routes/busterRoutes';
import { useCheckIfUserIsAdmin_server } from '@/server_context/user';
import { redirect } from 'next/navigation';
export default async function Layout({ children }: { children: React.ReactNode }) {
const isAdmin = await useCheckIfUserIsAdmin_server();
if (!isAdmin) {
return redirect(
createBusterRoute({
route: BusterRoutes.SETTINGS_GENERAL
})
);
}
return <>{children}</>;
}

View File

@ -1,6 +1,6 @@
'use client'; 'use client';
import React, { useState } from 'react'; import React, { useState } from 'react';
import { SettingsPageHeader } from '../_SettingsPageHeader'; import { SettingsPageHeader } from '../../_components/SettingsPageHeader';
import { PermissionSearch, NewPermissionGroupModal } from '@appComponents/PermissionComponents'; import { PermissionSearch, NewPermissionGroupModal } from '@appComponents/PermissionComponents';
import { useDebounceSearch } from '@/hooks/useDebounceSearch'; import { useDebounceSearch } from '@/hooks/useDebounceSearch';
import { useListAllPermissionGroups } from '@/api/buster_rest'; import { useListAllPermissionGroups } from '@/api/buster_rest';

View File

@ -11,7 +11,7 @@ import React, { useMemo, useState } from 'react';
import { Text } from '@/components/text'; import { Text } from '@/components/text';
import { OrganizationUserRoleText } from './config'; import { OrganizationUserRoleText } from './config';
import { BusterRoutes, createBusterRoute } from '@/routes'; import { BusterRoutes, createBusterRoute } from '@/routes';
import { ListUserItem } from '../../_components/ListContent'; import { ListUserItem } from '../../../_components/ListContent';
export const ListUsersComponent: React.FC<{ export const ListUsersComponent: React.FC<{
users: OrganizationUser[]; users: OrganizationUser[];

View File

@ -1,7 +1,7 @@
import { prefetchGetUserPermissionGroups } from '@/api/buster_rest/users'; import { prefetchGetUserPermissionGroups } from '@/api/buster_rest/users';
import { HydrationBoundary, dehydrate } from '@tanstack/react-query'; import { HydrationBoundary, dehydrate } from '@tanstack/react-query';
import { UserPermissionGroupsController } from './UserPermissionGroupsController'; import { UserPermissionGroupsController } from './UserPermissionGroupsController';
import { useCheckIfUserIsAdmin_server } from '../../../../../../server_context/user'; import { useCheckIfUserIsAdmin_server } from '../../../../../../../server_context/user';
import { redirect } from 'next/navigation'; import { redirect } from 'next/navigation';
import { BusterRoutes, createBusterRoute } from '@/routes'; import { BusterRoutes, createBusterRoute } from '@/routes';

View File

@ -1,12 +1,12 @@
'use client'; 'use client';
import React from 'react'; import React from 'react';
import { SettingsPageHeader } from '../_SettingsPageHeader'; import { SettingsPageHeader } from '../../_components/SettingsPageHeader';
import { useDebounceSearch } from '@/hooks/useDebounceSearch'; import { useDebounceSearch } from '@/hooks/useDebounceSearch';
import { useGetOrganizationUsers } from '@/api/buster_rest'; import { useGetOrganizationUsers } from '@/api/buster_rest';
import { useUserConfigContextSelector } from '@/context/Users'; import { useUserConfigContextSelector } from '@/context/Users';
import { ListUsersComponent } from './ListUsersComponent'; import { ListUsersComponent } from './ListUsersComponent';
import { PermissionSearch } from '../../_components/PermissionComponents'; import { PermissionSearch } from '../../../_components/PermissionComponents';
export default function Page() { export default function Page() {
const userOrganization = useUserConfigContextSelector((x) => x.userOrganizations); const userOrganization = useUserConfigContextSelector((x) => x.userOrganizations);

View File

@ -1,5 +1,5 @@
import { useCheckIfUserIsAdmin_server } from '../../../../../server_context/user'; import { useCheckIfUserIsAdmin_server } from '../../../../../server_context/user';
import { SettingsPageHeader } from '../../_SettingsPageHeader'; import { SettingsPageHeader } from '../../_components/SettingsPageHeader';
import { ApiKeysController } from './ApiKeysController'; import { ApiKeysController } from './ApiKeysController';
import { createBusterRoute, BusterRoutes } from '@/routes'; import { createBusterRoute, BusterRoutes } from '@/routes';
import { redirect } from 'next/navigation'; import { redirect } from 'next/navigation';

View File

@ -1,7 +1,20 @@
import { SettingsEmptyState } from '../../_SettingsEmptyState'; import { SettingsEmptyState } from '../../_components/SettingsEmptyState';
import { SettingsPageHeader } from '../../_SettingsPageHeader'; import { SettingsPageHeader } from '../../_components/SettingsPageHeader';
import { redirect } from 'next/navigation';
import { BusterRoutes, createBusterRoute } from '@/routes/busterRoutes';
import { useCheckIfUserIsAdmin_server } from '@/server_context/user';
export default async function Page() {
const isAdmin = await useCheckIfUserIsAdmin_server();
if (!isAdmin) {
return redirect(
createBusterRoute({
route: BusterRoutes.SETTINGS_GENERAL
})
);
}
export default function Page() {
return ( return (
<div> <div>
<SettingsPageHeader title="Billing" description="Manage invoice, payment methods, & more" /> <SettingsPageHeader title="Billing" description="Manage invoice, payment methods, & more" />

View File

@ -2,8 +2,8 @@
import React from 'react'; import React from 'react';
import { BusterRoutes, createBusterRoute } from '@/routes'; import { BusterRoutes, createBusterRoute } from '@/routes';
import { HeaderContainer } from '../_HeaderContainer'; import { HeaderContainer } from '../../_HeaderContainer';
import { useContext, useState } from 'react'; import { useState } from 'react';
import { DatabaseNames, DataSourceTypes, SUPPORTED_DATASOURCES } from '@/api/buster_rest'; import { DatabaseNames, DataSourceTypes, SUPPORTED_DATASOURCES } from '@/api/buster_rest';
import { AppDataSourceIcon } from '@/components/icons/AppDataSourceIcons'; import { AppDataSourceIcon } from '@/components/icons/AppDataSourceIcons';

View File

@ -0,0 +1,16 @@
import { BusterRoutes, createBusterRoute } from '@/routes/busterRoutes';
import { useCheckIfUserIsAdmin_server } from '@/server_context/user';
import { redirect } from 'next/navigation';
export default function Layout({ children }: { children: React.ReactNode }) {
const isAdmin = useCheckIfUserIsAdmin_server();
if (!isAdmin) {
return redirect(
createBusterRoute({
route: BusterRoutes.SETTINGS_DATASOURCES
})
);
}
return <>{children}</>;
}

View File

@ -13,10 +13,12 @@ import Link from 'next/link';
import { BusterRoutes, createBusterRoute } from '@/routes'; import { BusterRoutes, createBusterRoute } from '@/routes';
import { useMount } from 'ahooks'; import { useMount } from 'ahooks';
import { Text } from '@/components'; import { Text } from '@/components';
import { SettingsEmptyState } from '../../_SettingsEmptyState'; import { SettingsEmptyState } from '../../_components/SettingsEmptyState';
import { useAppLayoutContextSelector } from '@/context/BusterAppLayout'; import { useAppLayoutContextSelector } from '@/context/BusterAppLayout';
import { useUserConfigContextSelector } from '@/context/Users';
export const DatasourceList: React.FC = () => { export const DatasourceList: React.FC = () => {
const isAdmin = useUserConfigContextSelector((state) => state.isAdmin);
const dataSourcesList = useDataSourceContextSelector((state) => state.dataSourcesList); const dataSourcesList = useDataSourceContextSelector((state) => state.dataSourcesList);
const loadingDatasources = useDataSourceContextSelector((state) => state.loadingDatasources); const loadingDatasources = useDataSourceContextSelector((state) => state.loadingDatasources);
const initDataSourceList = useDataSourceContextSelector((state) => state.initDataSourceList); const initDataSourceList = useDataSourceContextSelector((state) => state.initDataSourceList);
@ -29,7 +31,7 @@ export const DatasourceList: React.FC = () => {
return ( return (
<div className="flex flex-col space-y-4"> <div className="flex flex-col space-y-4">
<AddSourceHeader /> <AddSourceHeader isAdmin={isAdmin} />
{loadingDatasources ? ( {loadingDatasources ? (
<SkeletonLoader /> <SkeletonLoader />
@ -37,6 +39,7 @@ export const DatasourceList: React.FC = () => {
<DataSourceItems sources={dataSourcesList} /> <DataSourceItems sources={dataSourcesList} />
) : ( ) : (
<SettingsEmptyState <SettingsEmptyState
showButton={isAdmin}
title={`You don't have any data sources yet.`} title={`You don't have any data sources yet.`}
description={`You dont have any datasources. As soon as you do, they will start to appear here.`} description={`You dont have any datasources. As soon as you do, they will start to appear here.`}
buttonText="New datasource" buttonText="New datasource"
@ -52,7 +55,7 @@ export const DatasourceList: React.FC = () => {
); );
}; };
const AddSourceHeader: React.FC<{}> = () => { const AddSourceHeader: React.FC<{ isAdmin: boolean }> = ({ isAdmin }) => {
return ( return (
<div className="flex w-full justify-between"> <div className="flex w-full justify-between">
<Text>Your data sources</Text> <Text>Your data sources</Text>
@ -60,9 +63,11 @@ const AddSourceHeader: React.FC<{}> = () => {
href={createBusterRoute({ href={createBusterRoute({
route: BusterRoutes.SETTINGS_DATASOURCES_ADD route: BusterRoutes.SETTINGS_DATASOURCES_ADD
})}> })}>
<Button type="text" icon={<AppMaterialIcons icon="add" />}> {isAdmin && (
New datasource <Button type="text" icon={<AppMaterialIcons icon="add" />}>
</Button> New datasource
</Button>
)}
</Link> </Link>
</div> </div>
); );

View File

@ -1,11 +1,8 @@
'use client'; 'use client';
import { AppMaterialIcons, BackButton } from '@/components'; import { BackButton } from '@/components';
import React from 'react'; import React from 'react';
import { createStyles } from 'antd-style'; import { createStyles } from 'antd-style';
import Link from 'next/link';
import { Text } from '@/components';
const useStyles = createStyles(({ css, token }) => ({ const useStyles = createStyles(({ css, token }) => ({
icon: { icon: {

View File

@ -1,7 +1,6 @@
import React from 'react'; import React from 'react';
import { Divider } from 'antd';
import { DatasourceList } from './_DatasourceList'; import { DatasourceList } from './_DatasourceList';
import { SettingsPageHeader } from '../../_SettingsPageHeader'; import { SettingsPageHeader } from '../../_components/SettingsPageHeader';
export default function Page() { export default function Page() {
return ( return (

View File

@ -1,5 +1,5 @@
import { SettingsEmptyState } from '../../_SettingsEmptyState'; import { SettingsEmptyState } from '../../_components/SettingsEmptyState';
import { SettingsPageHeader } from '../../_SettingsPageHeader'; import { SettingsPageHeader } from '../../_components/SettingsPageHeader';
export default function Page() { export default function Page() {
return ( return (

View File

@ -1,5 +1,5 @@
import { SettingsEmptyState } from '../../_SettingsEmptyState'; import { SettingsEmptyState } from '../../_components/SettingsEmptyState';
import { SettingsPageHeader } from '../../_SettingsPageHeader'; import { SettingsPageHeader } from '../../_components/SettingsPageHeader';
export default function Page() { export default function Page() {
return ( return (

View File

@ -1,5 +1,5 @@
import { SettingsEmptyState } from '../../_SettingsEmptyState'; import { SettingsEmptyState } from '../../_components/SettingsEmptyState';
import { SettingsPageHeader } from '../../_SettingsPageHeader'; import { SettingsPageHeader } from '../../_components/SettingsPageHeader';
export default function Page() { export default function Page() {
return ( return (

View File

@ -1,5 +1,5 @@
import { SettingsEmptyState } from '../../_SettingsEmptyState'; import { SettingsEmptyState } from '../../_components/SettingsEmptyState';
import { SettingsPageHeader } from '../../_SettingsPageHeader'; import { SettingsPageHeader } from '../../_components/SettingsPageHeader';
export default function Page() { export default function Page() {
return ( return (

View File

@ -1,5 +1,5 @@
import { SettingsEmptyState } from '../../_SettingsEmptyState'; import { SettingsEmptyState } from '../../_components/SettingsEmptyState';
import { SettingsPageHeader } from '../../_SettingsPageHeader'; import { SettingsPageHeader } from '../../_components/SettingsPageHeader';
export default function Page() { export default function Page() {
return ( return (

View File

@ -1,5 +1,5 @@
import { SettingsEmptyState } from '../../_SettingsEmptyState'; import { SettingsEmptyState } from '../../_components/SettingsEmptyState';
import { SettingsPageHeader } from '../../_SettingsPageHeader'; import { SettingsPageHeader } from '../../_components/SettingsPageHeader';
export default function Page() { export default function Page() {
return ( return (

Some files were not shown because too many files have changed in this diff Show More