mirror of
https://github.com/apache/superset.git
synced 2026-04-18 23:55:00 +00:00
fix(AllEntities): Display action buttons according to the user permissions (#33553)
This commit is contained in:
@@ -91,12 +91,13 @@ describe('AllEntitiesTable', () => {
|
||||
jest.restoreAllMocks();
|
||||
});
|
||||
|
||||
it('renders when empty', () => {
|
||||
it('renders when empty with button to tag if user has perm', () => {
|
||||
render(
|
||||
<AllEntitiesTable
|
||||
search=""
|
||||
setShowTagModal={mockSetShowTagModal}
|
||||
objects={mockObjects}
|
||||
canEditTag
|
||||
/>,
|
||||
{ useRouter: true },
|
||||
);
|
||||
@@ -108,25 +109,70 @@ describe('AllEntitiesTable', () => {
|
||||
expect(screen.getByText('Add tag to entities')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('renders when empty without button to tag if user does not have perm', () => {
|
||||
render(
|
||||
<AllEntitiesTable
|
||||
search=""
|
||||
setShowTagModal={mockSetShowTagModal}
|
||||
objects={mockObjects}
|
||||
canEditTag={false}
|
||||
/>,
|
||||
{ useRouter: true },
|
||||
);
|
||||
|
||||
expect(
|
||||
screen.getByText('No entities have this tag currently assigned'),
|
||||
).toBeInTheDocument();
|
||||
|
||||
expect(screen.queryByText('Add tag to entities')).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('renders the correct tags for each object type, excluding the current tag', () => {
|
||||
render(
|
||||
<AllEntitiesTable
|
||||
search=""
|
||||
setShowTagModal={mockSetShowTagModal}
|
||||
objects={mockObjectsWithTags}
|
||||
canEditTag
|
||||
/>,
|
||||
{ useRouter: true },
|
||||
);
|
||||
|
||||
expect(screen.getByText('Dashboards')).toBeInTheDocument();
|
||||
expect(screen.getByText('Sales Dashboard')).toBeInTheDocument();
|
||||
expect(screen.getByText('Sales')).toBeInTheDocument();
|
||||
|
||||
expect(screen.getByText('Charts')).toBeInTheDocument();
|
||||
expect(screen.getByText('Monthly Revenue')).toBeInTheDocument();
|
||||
expect(screen.getByText('Revenue')).toBeInTheDocument();
|
||||
|
||||
expect(screen.getByText('Queries')).toBeInTheDocument();
|
||||
expect(screen.getByText('User Engagement')).toBeInTheDocument();
|
||||
expect(screen.getByText('Engagement')).toBeInTheDocument();
|
||||
|
||||
expect(screen.queryByText('Current Tag')).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('Only list asset types that have entities', () => {
|
||||
const mockObjects = {
|
||||
dashboard: [],
|
||||
chart: [mockObjectsWithTags.chart[0]],
|
||||
query: [],
|
||||
};
|
||||
|
||||
render(
|
||||
<AllEntitiesTable
|
||||
search=""
|
||||
setShowTagModal={mockSetShowTagModal}
|
||||
objects={mockObjects}
|
||||
canEditTag
|
||||
/>,
|
||||
{ useRouter: true },
|
||||
);
|
||||
|
||||
expect(screen.queryByText('Dashboards')).not.toBeInTheDocument();
|
||||
expect(screen.getByText('Charts')).toBeInTheDocument();
|
||||
expect(screen.getByText('Monthly Revenue')).toBeInTheDocument();
|
||||
expect(screen.queryByText('Queries')).not.toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -53,20 +53,22 @@ interface AllEntitiesTableProps {
|
||||
search?: string;
|
||||
setShowTagModal: (show: boolean) => void;
|
||||
objects: TaggedObjects;
|
||||
canEditTag: boolean;
|
||||
}
|
||||
|
||||
export default function AllEntitiesTable({
|
||||
search = '',
|
||||
setShowTagModal,
|
||||
objects,
|
||||
canEditTag,
|
||||
}: AllEntitiesTableProps) {
|
||||
type objectType = 'dashboard' | 'chart' | 'query';
|
||||
|
||||
const [tagId] = useQueryParam('id', NumberParam);
|
||||
const showListViewObjs =
|
||||
objects.dashboard.length > 0 ||
|
||||
objects.chart.length > 0 ||
|
||||
objects.query.length > 0;
|
||||
const showDashboardList = objects.dashboard.length > 0;
|
||||
const showChartList = objects.chart.length > 0;
|
||||
const showQueryList = objects.query.length > 0;
|
||||
const showListViewObjs = showDashboardList || showChartList || showQueryList;
|
||||
|
||||
const renderTable = (type: objectType) => {
|
||||
const data = objects[type].map((o: TaggedObject) => ({
|
||||
@@ -134,20 +136,34 @@ export default function AllEntitiesTable({
|
||||
<AllEntitiesTableContainer>
|
||||
{showListViewObjs ? (
|
||||
<>
|
||||
<div className="entity-title">{t('Dashboards')}</div>
|
||||
{renderTable('dashboard')}
|
||||
<div className="entity-title">{t('Charts')}</div>
|
||||
{renderTable('chart')}
|
||||
<div className="entity-title">{t('Queries')}</div>
|
||||
{renderTable('query')}
|
||||
{showDashboardList && (
|
||||
<>
|
||||
<div className="entity-title">{t('Dashboards')}</div>
|
||||
{renderTable('dashboard')}
|
||||
</>
|
||||
)}
|
||||
{showChartList && (
|
||||
<>
|
||||
<div className="entity-title">{t('Charts')}</div>
|
||||
{renderTable('chart')}
|
||||
</>
|
||||
)}
|
||||
{showQueryList && (
|
||||
<>
|
||||
<div className="entity-title">{t('Queries')}</div>
|
||||
{renderTable('query')}
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
) : (
|
||||
<EmptyState
|
||||
image="dashboard.svg"
|
||||
size="large"
|
||||
title={t('No entities have this tag currently assigned')}
|
||||
buttonAction={() => setShowTagModal(true)}
|
||||
buttonText={t('Add tag to entities')}
|
||||
{...(canEditTag && {
|
||||
buttonAction: () => setShowTagModal(true),
|
||||
buttonText: t('Add tag to entities'),
|
||||
})}
|
||||
/>
|
||||
)}
|
||||
</AllEntitiesTableContainer>
|
||||
|
||||
@@ -35,6 +35,9 @@ import { fetchObjectsByTagIds, fetchSingleTag } from 'src/features/tags/tags';
|
||||
import Loading from 'src/components/Loading';
|
||||
import getOwnerName from 'src/utils/getOwnerName';
|
||||
import { TaggedObject, TaggedObjects } from 'src/types/TaggedObject';
|
||||
import { findPermission } from 'src/utils/findPermission';
|
||||
import { useSelector } from 'react-redux';
|
||||
import { RootState } from 'src/dashboard/types';
|
||||
|
||||
const additionalItemsStyles = (theme: SupersetTheme) => css`
|
||||
display: flex;
|
||||
@@ -100,6 +103,10 @@ function AllEntities() {
|
||||
query: [],
|
||||
});
|
||||
|
||||
const canEditTag = useSelector((state: RootState) =>
|
||||
findPermission('can_write', 'Tag', state.user?.roles),
|
||||
);
|
||||
|
||||
const editableTitleProps = {
|
||||
title: tag?.name || '',
|
||||
placeholder: 'testing',
|
||||
@@ -211,14 +218,16 @@ function AllEntities() {
|
||||
}
|
||||
rightPanelAdditionalItems={
|
||||
<>
|
||||
<Button
|
||||
data-test="bulk-select-action"
|
||||
buttonStyle="secondary"
|
||||
onClick={() => setShowTagModal(true)}
|
||||
showMarginRight={false}
|
||||
>
|
||||
{t('Edit Tag')}{' '}
|
||||
</Button>
|
||||
{canEditTag && (
|
||||
<Button
|
||||
data-test="bulk-select-action"
|
||||
buttonStyle="secondary"
|
||||
onClick={() => setShowTagModal(true)}
|
||||
showMarginRight={false}
|
||||
>
|
||||
{t('Edit tag')}{' '}
|
||||
</Button>
|
||||
)}
|
||||
</>
|
||||
}
|
||||
menuDropdownProps={{
|
||||
@@ -232,6 +241,7 @@ function AllEntities() {
|
||||
search={tag?.name || ''}
|
||||
setShowTagModal={setShowTagModal}
|
||||
objects={objects}
|
||||
canEditTag={canEditTag}
|
||||
/>
|
||||
</div>
|
||||
</AllEntitiesContainer>
|
||||
|
||||
@@ -22,6 +22,7 @@ from flask_appbuilder.models.sqla.interface import SQLAInterface
|
||||
from flask_appbuilder.security.decorators import has_access
|
||||
|
||||
from superset import is_feature_enabled
|
||||
from superset.constants import RouteMethod
|
||||
from superset.superset_typing import FlaskResponse
|
||||
from superset.tags.models import Tag
|
||||
from superset.views.base import SupersetModelView
|
||||
@@ -33,7 +34,7 @@ class TaggedObjectsModelView(SupersetModelView):
|
||||
route_base = "/superset/all_entities"
|
||||
datamodel = SQLAInterface(Tag)
|
||||
class_permission_name = "Tags"
|
||||
include_route_methods = {"list"}
|
||||
include_route_methods = {RouteMethod.LIST}
|
||||
|
||||
@has_access
|
||||
@expose("/")
|
||||
|
||||
Reference in New Issue
Block a user