mirror of https://github.com/buster-so/buster.git
added pages for permission groups
This commit is contained in:
parent
f072b2c461
commit
30cb2a0ff5
|
@ -5,7 +5,7 @@ export interface GetPermissionGroupResponse {
|
||||||
name: string;
|
name: string;
|
||||||
organization_id: string;
|
organization_id: string;
|
||||||
updated_at: string;
|
updated_at: string;
|
||||||
updated_by: string; //THIS IS THE USER ID
|
updated_by: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface CreatePermissionGroupResponse extends GetPermissionGroupResponse {}
|
export interface CreatePermissionGroupResponse extends GetPermissionGroupResponse {}
|
||||||
|
|
|
@ -1,2 +1,3 @@
|
||||||
export * from './StatusBadgeIndicator';
|
export * from './StatusBadgeIndicator';
|
||||||
export * from './FavoriteStar';
|
export * from './FavoriteStar';
|
||||||
|
export * from './ListEmptyState';
|
||||||
|
|
|
@ -13,7 +13,6 @@ export const PermissionOverview: React.FC<{
|
||||||
datasetId: string;
|
datasetId: string;
|
||||||
}> = React.memo(({ datasetId }) => {
|
}> = React.memo(({ datasetId }) => {
|
||||||
const { data: datasetPermissionsOverview } = useGetDatasetPermissionsOverview(datasetId);
|
const { data: datasetPermissionsOverview } = useGetDatasetPermissionsOverview(datasetId);
|
||||||
console.log(datasetPermissionsOverview);
|
|
||||||
|
|
||||||
const { filteredItems, searchText, handleSearchChange } = useDebounceSearch({
|
const { filteredItems, searchText, handleSearchChange } = useDebounceSearch({
|
||||||
items: datasetPermissionsOverview?.users || [],
|
items: datasetPermissionsOverview?.users || [],
|
||||||
|
|
|
@ -12,8 +12,7 @@ import { ClientRedirect } from './_components/ClientRedirect';
|
||||||
import { AppLayoutClient } from './layoutClient';
|
import { AppLayoutClient } from './layoutClient';
|
||||||
|
|
||||||
export default async function Layout({
|
export default async function Layout({
|
||||||
children,
|
children
|
||||||
...rest
|
|
||||||
}: Readonly<{
|
}: Readonly<{
|
||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
}>) {
|
}>) {
|
||||||
|
|
|
@ -0,0 +1,68 @@
|
||||||
|
import {
|
||||||
|
BusterInfiniteList,
|
||||||
|
BusterListColumn,
|
||||||
|
BusterListRowItem,
|
||||||
|
EmptyStateList,
|
||||||
|
InfiniteListContainer
|
||||||
|
} from '@/components/list';
|
||||||
|
import { Card } from 'antd';
|
||||||
|
import React, { useMemo, useState } from 'react';
|
||||||
|
import { Text } from '@/components/text';
|
||||||
|
import { BusterRoutes, createBusterRoute } from '@/routes';
|
||||||
|
import { ListUserItem } from '../../_components/ListContent';
|
||||||
|
import { GetPermissionGroupResponse } from '@/api/buster-rest';
|
||||||
|
import { ListEmptyState } from '../../_components/Lists/ListEmptyState';
|
||||||
|
|
||||||
|
export const ListPermissionGroupsComponent: React.FC<{
|
||||||
|
permissionGroups: GetPermissionGroupResponse[];
|
||||||
|
isFetched: boolean;
|
||||||
|
}> = React.memo(({ permissionGroups, isFetched }) => {
|
||||||
|
const columns: BusterListColumn[] = useMemo(
|
||||||
|
() => [
|
||||||
|
{
|
||||||
|
title: 'Name',
|
||||||
|
dataIndex: 'name'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
[]
|
||||||
|
);
|
||||||
|
|
||||||
|
const permissionGroupsRows: BusterListRowItem[] = useMemo(() => {
|
||||||
|
return permissionGroups.reduce<BusterListRowItem[]>((acc, permissionGroup) => {
|
||||||
|
const rowItem: BusterListRowItem = {
|
||||||
|
id: permissionGroup.id,
|
||||||
|
data: permissionGroup,
|
||||||
|
link: createBusterRoute({
|
||||||
|
route: BusterRoutes.SETTINGS_PERMISSION_GROUPS_ID_USERS,
|
||||||
|
permissionGroupId: permissionGroup.id
|
||||||
|
})
|
||||||
|
};
|
||||||
|
acc.push(rowItem);
|
||||||
|
return acc;
|
||||||
|
}, []);
|
||||||
|
}, [permissionGroups]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<InfiniteListContainer
|
||||||
|
showContainerBorder={false}
|
||||||
|
// popupNode={
|
||||||
|
// <UserListPopupContainer
|
||||||
|
// selectedRowKeys={selectedRowKeys}
|
||||||
|
// onSelectChange={setSelectedRowKeys}
|
||||||
|
// />
|
||||||
|
// }
|
||||||
|
>
|
||||||
|
<BusterInfiniteList
|
||||||
|
columns={columns}
|
||||||
|
rows={permissionGroupsRows}
|
||||||
|
showHeader={true}
|
||||||
|
showSelectAll={false}
|
||||||
|
rowClassName="!pl-[30px]"
|
||||||
|
columnRowVariant="default"
|
||||||
|
emptyState={<EmptyStateList text="No permission groups found" />}
|
||||||
|
/>
|
||||||
|
</InfiniteListContainer>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
ListPermissionGroupsComponent.displayName = 'ListPermissionGroupsComponent';
|
|
@ -0,0 +1,3 @@
|
||||||
|
export default function Page() {
|
||||||
|
return <div>Dataset Groups</div>;
|
||||||
|
}
|
|
@ -0,0 +1,3 @@
|
||||||
|
export default function Page() {
|
||||||
|
return <div>Datasets</div>;
|
||||||
|
}
|
|
@ -0,0 +1,3 @@
|
||||||
|
export default function Page() {
|
||||||
|
return <div>Users</div>;
|
||||||
|
}
|
|
@ -1,14 +1,62 @@
|
||||||
import { SettingsEmptyState } from '../_SettingsEmptyState';
|
'use client';
|
||||||
|
import React, { useState } from 'react';
|
||||||
import { SettingsPageHeader } from '../_SettingsPageHeader';
|
import { SettingsPageHeader } from '../_SettingsPageHeader';
|
||||||
|
import { PermissionSearch, NewPermissionGroupModal } from '@appComponents/PermissionComponents';
|
||||||
|
import { useDebounceSearch } from '@/hooks/useDebounceSearch';
|
||||||
|
import { useListAllPermissionGroups } from '@/api/buster-rest';
|
||||||
|
import { ListPermissionGroupsComponent } from './ListPermissionGroupsComponent';
|
||||||
|
import { useMemoizedFn } from 'ahooks';
|
||||||
|
import { Button } from 'antd';
|
||||||
|
import { AppMaterialIcons } from '@/components';
|
||||||
|
|
||||||
export default function Page() {
|
export default function Page() {
|
||||||
|
const { data: permissionGroups, isFetched, refetch } = useListAllPermissionGroups();
|
||||||
|
const [isNewPermissionGroupModalOpen, setIsNewPermissionGroupModalOpen] = useState(false);
|
||||||
|
|
||||||
|
const { filteredItems, handleSearchChange, searchText } = useDebounceSearch({
|
||||||
|
items: permissionGroups || [],
|
||||||
|
searchPredicate: (item, searchText) =>
|
||||||
|
item.name.toLowerCase().includes(searchText.toLowerCase())
|
||||||
|
});
|
||||||
|
|
||||||
|
const onCloseNewPermissionGroupModal = useMemoizedFn(() => {
|
||||||
|
setIsNewPermissionGroupModalOpen(false);
|
||||||
|
refetch();
|
||||||
|
});
|
||||||
|
|
||||||
|
const onOpenNewPermissionGroupModal = useMemoizedFn(() => {
|
||||||
|
setIsNewPermissionGroupModalOpen(true);
|
||||||
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<>
|
||||||
<SettingsPageHeader
|
<div className="flex h-full flex-col space-y-4 overflow-y-auto">
|
||||||
title="Permission Groups"
|
<div className="px-[30px] pt-[46px]">
|
||||||
description="Manage security & how members authenticate"
|
<SettingsPageHeader
|
||||||
|
title="Permission Groups"
|
||||||
|
description="Manage your permission groups and set explicit permissions."
|
||||||
|
type="alternate"
|
||||||
|
/>
|
||||||
|
<div className="flex justify-between space-x-3">
|
||||||
|
<PermissionSearch searchText={searchText} setSearchText={handleSearchChange} />
|
||||||
|
<Button
|
||||||
|
onClick={onOpenNewPermissionGroupModal}
|
||||||
|
type="default"
|
||||||
|
icon={<AppMaterialIcons icon="add" />}>
|
||||||
|
New Permission Group
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="">
|
||||||
|
<ListPermissionGroupsComponent permissionGroups={filteredItems} isFetched={isFetched} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<NewPermissionGroupModal
|
||||||
|
isOpen={isNewPermissionGroupModalOpen}
|
||||||
|
onClose={onCloseNewPermissionGroupModal}
|
||||||
/>
|
/>
|
||||||
<SettingsEmptyState />
|
</>
|
||||||
</div>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,18 +0,0 @@
|
||||||
import React, { useState, useTransition } from 'react';
|
|
||||||
import { SearchInput } from '@/components/inputs';
|
|
||||||
|
|
||||||
export const SearchUsers: React.FC<{
|
|
||||||
onChange: (value: string) => void;
|
|
||||||
}> = React.memo(({ onChange }) => {
|
|
||||||
return (
|
|
||||||
<div className="flex max-w-[400px] items-center space-x-2">
|
|
||||||
<SearchInput
|
|
||||||
className="max-w-[280px]"
|
|
||||||
placeholder="Search users name or email..."
|
|
||||||
onChange={onChange}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
SearchUsers.displayName = 'SearchUsers';
|
|
|
@ -1,5 +0,0 @@
|
||||||
import React from 'react';
|
|
||||||
|
|
||||||
export default function Layout({ children }: { children: React.ReactNode }) {
|
|
||||||
return <>{children}</>;
|
|
||||||
}
|
|
|
@ -2,18 +2,18 @@
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { SettingsPageHeader } from '../_SettingsPageHeader';
|
import { SettingsPageHeader } from '../_SettingsPageHeader';
|
||||||
import { SearchUsers } from './SearchUsers';
|
|
||||||
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';
|
||||||
|
|
||||||
export default function Page() {
|
export default function Page() {
|
||||||
const userOrganization = useUserConfigContextSelector((x) => x.userOrganizations);
|
const userOrganization = useUserConfigContextSelector((x) => x.userOrganizations);
|
||||||
const firstOrganizationId = userOrganization?.id! || '';
|
const firstOrganizationId = userOrganization?.id! || '';
|
||||||
const { data: users, isFetched } = useGetOrganizationUsers(firstOrganizationId);
|
const { data: users, isFetched } = useGetOrganizationUsers(firstOrganizationId);
|
||||||
|
|
||||||
const { filteredItems, handleSearchChange } = useDebounceSearch({
|
const { filteredItems, handleSearchChange, searchText } = useDebounceSearch({
|
||||||
items: users || [],
|
items: users || [],
|
||||||
searchPredicate: (item, searchText) =>
|
searchPredicate: (item, searchText) =>
|
||||||
item.email.includes(searchText) || item.name.includes(searchText)
|
item.email.includes(searchText) || item.name.includes(searchText)
|
||||||
|
@ -27,7 +27,11 @@ export default function Page() {
|
||||||
description="Manage your organization's users and their permissions"
|
description="Manage your organization's users and their permissions"
|
||||||
type="alternate"
|
type="alternate"
|
||||||
/>
|
/>
|
||||||
<SearchUsers onChange={handleSearchChange} />
|
<PermissionSearch
|
||||||
|
placeholder="Search users name or email..."
|
||||||
|
searchText={searchText}
|
||||||
|
setSearchText={handleSearchChange}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<ListUsersComponent users={filteredItems} isFetched={isFetched} />
|
<ListUsersComponent users={filteredItems} isFetched={isFetched} />
|
||||||
|
|
|
@ -29,7 +29,9 @@ export enum BusterAppRoutes {
|
||||||
SETTINGS_DATASOURCES_ADD = '/app/settings/datasources/add',
|
SETTINGS_DATASOURCES_ADD = '/app/settings/datasources/add',
|
||||||
SETTINGS_INTEGRATIONS = '/app/settings/integrations',
|
SETTINGS_INTEGRATIONS = '/app/settings/integrations',
|
||||||
SETTINGS_PERMISSION_GROUPS = '/app/settings/permission-groups',
|
SETTINGS_PERMISSION_GROUPS = '/app/settings/permission-groups',
|
||||||
SETTINGS_PERMISSION_GROUPS_ID = '/app/settings/permission-groups/:permissionGroupId',
|
SETTINGS_PERMISSION_GROUPS_ID_USERS = '/app/settings/permission-groups/:permissionGroupId/users',
|
||||||
|
SETTINGS_PERMISSION_GROUPS_ID_DATASET_GROUPS = '/app/settings/permission-groups/:permissionGroupId/dataset-groups',
|
||||||
|
SETTINGS_PERMISSION_GROUPS_ID_DATASETS = '/app/settings/permission-groups/:permissionGroupId/datasets',
|
||||||
SETTINGS_API_KEYS = '/app/settings/api-keys',
|
SETTINGS_API_KEYS = '/app/settings/api-keys',
|
||||||
SETTINGS_EMBEDS = '/app/settings/embeds',
|
SETTINGS_EMBEDS = '/app/settings/embeds',
|
||||||
SETTINGS_BILLING = '/app/settings/billing',
|
SETTINGS_BILLING = '/app/settings/billing',
|
||||||
|
@ -86,8 +88,16 @@ export type BusterAppRoutesWithArgs = {
|
||||||
[BusterAppRoutes.SETTINGS_PERMISSION_GROUPS]: {
|
[BusterAppRoutes.SETTINGS_PERMISSION_GROUPS]: {
|
||||||
route: BusterAppRoutes.SETTINGS_PERMISSION_GROUPS;
|
route: BusterAppRoutes.SETTINGS_PERMISSION_GROUPS;
|
||||||
};
|
};
|
||||||
[BusterAppRoutes.SETTINGS_PERMISSION_GROUPS_ID]: {
|
[BusterAppRoutes.SETTINGS_PERMISSION_GROUPS_ID_USERS]: {
|
||||||
route: BusterAppRoutes.SETTINGS_PERMISSION_GROUPS_ID;
|
route: BusterAppRoutes.SETTINGS_PERMISSION_GROUPS_ID_USERS;
|
||||||
|
permissionGroupId: string;
|
||||||
|
};
|
||||||
|
[BusterAppRoutes.SETTINGS_PERMISSION_GROUPS_ID_DATASET_GROUPS]: {
|
||||||
|
route: BusterAppRoutes.SETTINGS_PERMISSION_GROUPS_ID_DATASET_GROUPS;
|
||||||
|
permissionGroupId: string;
|
||||||
|
};
|
||||||
|
[BusterAppRoutes.SETTINGS_PERMISSION_GROUPS_ID_DATASETS]: {
|
||||||
|
route: BusterAppRoutes.SETTINGS_PERMISSION_GROUPS_ID_DATASETS;
|
||||||
permissionGroupId: string;
|
permissionGroupId: string;
|
||||||
};
|
};
|
||||||
[BusterAppRoutes.SETTINGS_API_KEYS]: { route: BusterAppRoutes.SETTINGS_API_KEYS };
|
[BusterAppRoutes.SETTINGS_API_KEYS]: { route: BusterAppRoutes.SETTINGS_API_KEYS };
|
||||||
|
|
Loading…
Reference in New Issue