mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 01:38:56 -04:00
Fleet Privileges Display (#204402)
## Summary Fixed privileges display for features/subFeatures that require all spaces. ### Before Role privileges display for only `Default` space selected <img width="728" alt="Screenshot 2024-12-17 at 13 32 17" src="https://github.com/user-attachments/assets/151b7012-aa1a-430c-be22-cc91e64362e3" /> Privileges summary display for only `Default` space selected <img width="471" alt="Screenshot 2024-12-17 at 13 32 50" src="https://github.com/user-attachments/assets/964c2223-163d-4081-a37d-196f5df5df5c" /> ### After Role privileges display for only `Default` space selected <img width="739" alt="Screenshot 2024-12-17 at 13 30 00" src="https://github.com/user-attachments/assets/0f98a9d7-211d-46ec-82c6-25d29a44be6b" /> Privileges summary display for only `Default` space selected <img width="569" alt="Screenshot 2024-12-17 at 13 30 19" src="https://github.com/user-attachments/assets/932771fd-6486-4b7e-9de5-6cd34ab74dc9" /> ### How to test With `Default` space: 1. Navigate to Creating a new Role and assign Kibana privileges. 2. Set the Spaces to `Default` Space and the privilege level to All. 3. Navigate to Management category and verify that Fleet is set to `None`. 4. Click on "View privilege summary" and verify that Fleet is set to `None`. With `*All Spaces`: 1. Navigate to Creating a new Role and assign Kibana privileges. 2. Set the Spaces to `*All Spaces` and the privilege level to All. 3. Navigate to Management category and verify that Fleet is set to `All` 4. Click on "View privilege summary" and verify that Fleet is set to `All` ### Checklist Check the PR satisfies following conditions. - [x] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios - [x] The PR description includes the appropriate Release Notes section, and the correct `release_note:*` label is applied per the [guidelines](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process) __Fixes: https://github.com/elastic/kibana/issues/194686__ ## Release Note Fixed privileges display for features/subFeatures that require all spaces. --------- Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
This commit is contained in:
parent
13582aa458
commit
d4196cd902
8 changed files with 764 additions and 127 deletions
|
@ -132,6 +132,7 @@ export const FeatureTableExpandedRow = ({
|
|||
onChange={(updatedPrivileges) => onChange(feature.id, updatedPrivileges)}
|
||||
selectedFeaturePrivileges={selectedFeaturePrivileges}
|
||||
disabled={disabled || !isCustomizing || isDisabledDueToSpaceSelection}
|
||||
allSpacesSelected={allSpacesSelected}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
);
|
||||
|
|
|
@ -301,4 +301,66 @@ describe('SubFeatureForm', () => {
|
|||
|
||||
expect(wrapper.children()).toMatchInlineSnapshot(`null`);
|
||||
});
|
||||
|
||||
it('correctly renders privileges that require all spaces to be enabled', () => {
|
||||
const role = createRole([
|
||||
{
|
||||
base: [],
|
||||
feature: {
|
||||
with_sub_features: ['cool_all'],
|
||||
},
|
||||
spaces: [],
|
||||
},
|
||||
]);
|
||||
const feature = new KibanaFeature({
|
||||
id: 'test_feature',
|
||||
name: 'test feature',
|
||||
category: { id: 'test', label: 'test' },
|
||||
app: [],
|
||||
privileges: {
|
||||
all: {
|
||||
savedObject: { all: [], read: [] },
|
||||
ui: [],
|
||||
},
|
||||
read: {
|
||||
savedObject: { all: [], read: [] },
|
||||
ui: [],
|
||||
},
|
||||
},
|
||||
subFeatures: [
|
||||
{
|
||||
name: 'subFeature1',
|
||||
requireAllSpaces: true,
|
||||
privilegeGroups: [
|
||||
{
|
||||
groupType: 'independent',
|
||||
privileges: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
});
|
||||
const subFeature1 = new SecuredSubFeature(feature.toRaw().subFeatures![0]);
|
||||
const kibanaPrivileges = createKibanaPrivileges([feature]);
|
||||
const calculator = new PrivilegeFormCalculator(kibanaPrivileges, role);
|
||||
|
||||
const onChange = jest.fn();
|
||||
|
||||
const wrapper = mountWithIntl(
|
||||
<SubFeatureForm
|
||||
featureId={feature.id}
|
||||
subFeature={subFeature1}
|
||||
selectedFeaturePrivileges={['cool_all']}
|
||||
privilegeCalculator={calculator}
|
||||
privilegeIndex={0}
|
||||
onChange={onChange}
|
||||
disabled={true}
|
||||
allSpacesSelected={false}
|
||||
/>
|
||||
);
|
||||
|
||||
const buttonGroups = wrapper.find(EuiButtonGroup);
|
||||
|
||||
buttonGroups.every((button) => button.props().idSelected.id === 'none');
|
||||
});
|
||||
});
|
||||
|
|
|
@ -34,6 +34,7 @@ interface Props {
|
|||
onChange: (selectedPrivileges: string[]) => void;
|
||||
disabled?: boolean;
|
||||
categoryId?: string;
|
||||
allSpacesSelected?: boolean;
|
||||
}
|
||||
|
||||
export const SubFeatureForm = (props: Props) => {
|
||||
|
@ -157,12 +158,18 @@ export const SubFeatureForm = (props: Props) => {
|
|||
privilegeGroup: SubFeaturePrivilegeGroup,
|
||||
index: number
|
||||
) {
|
||||
const nonePrivilege = {
|
||||
id: NO_PRIVILEGE_VALUE,
|
||||
label: 'None',
|
||||
isDisabled: props.disabled,
|
||||
};
|
||||
|
||||
const firstSelectedPrivilege =
|
||||
props.privilegeCalculator.getSelectedMutuallyExclusiveSubFeaturePrivilege(
|
||||
props.featureId,
|
||||
privilegeGroup,
|
||||
props.privilegeIndex
|
||||
);
|
||||
) ?? nonePrivilege;
|
||||
|
||||
const options = [
|
||||
...privilegeGroup.privileges.map((privilege, privilegeIndex) => {
|
||||
|
@ -174,11 +181,12 @@ export const SubFeatureForm = (props: Props) => {
|
|||
}),
|
||||
];
|
||||
|
||||
options.push({
|
||||
id: NO_PRIVILEGE_VALUE,
|
||||
label: 'None',
|
||||
isDisabled: props.disabled,
|
||||
});
|
||||
options.push(nonePrivilege);
|
||||
|
||||
const idSelected =
|
||||
props.subFeature.requireAllSpaces && !props.allSpacesSelected
|
||||
? nonePrivilege.id
|
||||
: firstSelectedPrivilege.id;
|
||||
|
||||
return (
|
||||
<EuiButtonGroup
|
||||
|
@ -187,7 +195,7 @@ export const SubFeatureForm = (props: Props) => {
|
|||
data-test-subj="mutexSubFeaturePrivilegeControl"
|
||||
isFullWidth
|
||||
options={options}
|
||||
idSelected={firstSelectedPrivilege?.id ?? NO_PRIVILEGE_VALUE}
|
||||
idSelected={idSelected}
|
||||
isDisabled={props.disabled}
|
||||
onChange={(selectedPrivilegeId: string) => {
|
||||
// Deselect all privileges which belong to this mutually-exclusive group
|
||||
|
|
|
@ -6,23 +6,159 @@
|
|||
*/
|
||||
|
||||
import { EuiFlexGroup, EuiFlexItem, EuiIconTip, EuiText } from '@elastic/eui';
|
||||
import React from 'react';
|
||||
import React, { useCallback, useMemo } from 'react';
|
||||
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import type {
|
||||
SecuredFeature,
|
||||
SecuredSubFeature,
|
||||
SubFeaturePrivilege,
|
||||
SubFeaturePrivilegeGroup,
|
||||
} from '@kbn/security-role-management-model';
|
||||
|
||||
import type { EffectiveFeaturePrivileges } from './privilege_summary_calculator';
|
||||
import { ALL_SPACES_ID } from '../../../../../../../common/constants';
|
||||
|
||||
type EffectivePrivilegesTuple = [string[], EffectiveFeaturePrivileges['featureId']];
|
||||
|
||||
interface Props {
|
||||
feature: SecuredFeature;
|
||||
effectiveFeaturePrivileges: Array<EffectiveFeaturePrivileges['featureId']>;
|
||||
effectiveFeaturePrivileges: EffectivePrivilegesTuple[];
|
||||
}
|
||||
|
||||
export const PrivilegeSummaryExpandedRow = (props: Props) => {
|
||||
const allSpacesEffectivePrivileges = useMemo(
|
||||
() => props.effectiveFeaturePrivileges.find(([spaces]) => spaces.includes(ALL_SPACES_ID)),
|
||||
[props.effectiveFeaturePrivileges]
|
||||
);
|
||||
|
||||
const renderIndependentPrivilegeGroup = useCallback(
|
||||
(
|
||||
effectiveSubFeaturePrivileges: string[],
|
||||
privilegeGroup: SubFeaturePrivilegeGroup,
|
||||
index: number
|
||||
) => {
|
||||
return (
|
||||
<div key={index}>
|
||||
{privilegeGroup.privileges.map((privilege: SubFeaturePrivilege) => {
|
||||
const isGranted = effectiveSubFeaturePrivileges.includes(privilege.id);
|
||||
return (
|
||||
<EuiFlexGroup gutterSize="s" data-test-subj="independentPrivilege" key={privilege.id}>
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiIconTip
|
||||
type={isGranted ? 'check' : 'cross'}
|
||||
color={isGranted ? 'primary' : 'danger'}
|
||||
content={
|
||||
isGranted
|
||||
? i18n.translate(
|
||||
'xpack.security.management.editRole.privilegeSummary.privilegeGrantedIconTip',
|
||||
{ defaultMessage: 'Privilege is granted' }
|
||||
)
|
||||
: i18n.translate(
|
||||
'xpack.security.management.editRole.privilegeSummary.privilegeNotGrantedIconTip',
|
||||
{ defaultMessage: 'Privilege is not granted' }
|
||||
)
|
||||
}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem>
|
||||
<EuiText size="s" data-test-subj="privilegeName">
|
||||
{privilege.name}
|
||||
</EuiText>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
},
|
||||
[]
|
||||
);
|
||||
|
||||
const renderMutuallyExclusivePrivilegeGroup = useCallback(
|
||||
(
|
||||
effectiveSubFeaturePrivileges: string[],
|
||||
privilegeGroup: SubFeaturePrivilegeGroup,
|
||||
index: number,
|
||||
isDisabledDueToSpaceSelection: boolean
|
||||
) => {
|
||||
const firstSelectedPrivilege = !isDisabledDueToSpaceSelection
|
||||
? privilegeGroup.privileges.find((p) => effectiveSubFeaturePrivileges.includes(p.id))?.name
|
||||
: null;
|
||||
|
||||
return (
|
||||
<EuiFlexGroup gutterSize="s" key={index} data-test-subj="mutexPrivilege">
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiIconTip
|
||||
type={firstSelectedPrivilege ? 'check' : 'cross'}
|
||||
color={firstSelectedPrivilege ? 'primary' : 'danger'}
|
||||
content={firstSelectedPrivilege ? 'Privilege is granted' : 'Privilege is not granted'}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem>
|
||||
<EuiText size="s" data-test-subj="privilegeName">
|
||||
{firstSelectedPrivilege ?? 'None'}
|
||||
</EuiText>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
);
|
||||
},
|
||||
[]
|
||||
);
|
||||
|
||||
const renderPrivilegeGroup = useCallback(
|
||||
(
|
||||
effectiveSubFeaturePrivileges: string[],
|
||||
{ requireAllSpaces, spaces }: { requireAllSpaces: boolean; spaces: string[] }
|
||||
) => {
|
||||
return (privilegeGroup: SubFeaturePrivilegeGroup, index: number) => {
|
||||
const isDisabledDueToSpaceSelection = requireAllSpaces && !spaces.includes(ALL_SPACES_ID);
|
||||
|
||||
switch (privilegeGroup.groupType) {
|
||||
case 'independent':
|
||||
return renderIndependentPrivilegeGroup(
|
||||
effectiveSubFeaturePrivileges,
|
||||
privilegeGroup,
|
||||
index
|
||||
);
|
||||
case 'mutually_exclusive':
|
||||
return renderMutuallyExclusivePrivilegeGroup(
|
||||
effectiveSubFeaturePrivileges,
|
||||
privilegeGroup,
|
||||
index,
|
||||
isDisabledDueToSpaceSelection
|
||||
);
|
||||
default:
|
||||
throw new Error(`Unsupported privilege group type: ${privilegeGroup.groupType}`);
|
||||
}
|
||||
};
|
||||
},
|
||||
[renderIndependentPrivilegeGroup, renderMutuallyExclusivePrivilegeGroup]
|
||||
);
|
||||
|
||||
const getEffectiveFeaturePrivileges = useCallback(
|
||||
(subFeature: SecuredSubFeature) => {
|
||||
return props.effectiveFeaturePrivileges.map((entry, index) => {
|
||||
const [spaces, privs] =
|
||||
subFeature.requireAllSpaces && allSpacesEffectivePrivileges
|
||||
? allSpacesEffectivePrivileges
|
||||
: entry;
|
||||
|
||||
return (
|
||||
<EuiFlexItem key={index} data-test-subj={`entry-${index}`}>
|
||||
{subFeature.getPrivilegeGroups().map(
|
||||
renderPrivilegeGroup(privs.subFeature, {
|
||||
requireAllSpaces: subFeature.requireAllSpaces,
|
||||
spaces,
|
||||
})
|
||||
)}
|
||||
</EuiFlexItem>
|
||||
);
|
||||
});
|
||||
},
|
||||
[props.effectiveFeaturePrivileges, allSpacesEffectivePrivileges, renderPrivilegeGroup]
|
||||
);
|
||||
|
||||
return (
|
||||
<EuiFlexGroup direction="column">
|
||||
{props.feature.getSubFeatures().map((subFeature) => {
|
||||
|
@ -34,105 +170,11 @@ export const PrivilegeSummaryExpandedRow = (props: Props) => {
|
|||
{subFeature.name}
|
||||
</EuiText>
|
||||
</EuiFlexItem>
|
||||
{props.effectiveFeaturePrivileges.map((privs, index) => {
|
||||
return (
|
||||
<EuiFlexItem key={index} data-test-subj={`entry-${index}`}>
|
||||
{subFeature.getPrivilegeGroups().map(renderPrivilegeGroup(privs.subFeature))}
|
||||
</EuiFlexItem>
|
||||
);
|
||||
})}
|
||||
{getEffectiveFeaturePrivileges(subFeature)}
|
||||
</EuiFlexGroup>
|
||||
</EuiFlexItem>
|
||||
);
|
||||
})}
|
||||
</EuiFlexGroup>
|
||||
);
|
||||
|
||||
function renderPrivilegeGroup(effectiveSubFeaturePrivileges: string[]) {
|
||||
return (privilegeGroup: SubFeaturePrivilegeGroup, index: number) => {
|
||||
switch (privilegeGroup.groupType) {
|
||||
case 'independent':
|
||||
return renderIndependentPrivilegeGroup(
|
||||
effectiveSubFeaturePrivileges,
|
||||
privilegeGroup,
|
||||
index
|
||||
);
|
||||
case 'mutually_exclusive':
|
||||
return renderMutuallyExclusivePrivilegeGroup(
|
||||
effectiveSubFeaturePrivileges,
|
||||
privilegeGroup,
|
||||
index
|
||||
);
|
||||
default:
|
||||
throw new Error(`Unsupported privilege group type: ${privilegeGroup.groupType}`);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function renderIndependentPrivilegeGroup(
|
||||
effectiveSubFeaturePrivileges: string[],
|
||||
privilegeGroup: SubFeaturePrivilegeGroup,
|
||||
index: number
|
||||
) {
|
||||
return (
|
||||
<div key={index}>
|
||||
{privilegeGroup.privileges.map((privilege: SubFeaturePrivilege) => {
|
||||
const isGranted = effectiveSubFeaturePrivileges.includes(privilege.id);
|
||||
return (
|
||||
<EuiFlexGroup gutterSize="s" data-test-subj="independentPrivilege" key={privilege.id}>
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiIconTip
|
||||
type={isGranted ? 'check' : 'cross'}
|
||||
color={isGranted ? 'primary' : 'danger'}
|
||||
content={
|
||||
isGranted
|
||||
? i18n.translate(
|
||||
'xpack.security.management.editRole.privilegeSummary.privilegeGrantedIconTip',
|
||||
{ defaultMessage: 'Privilege is granted' }
|
||||
)
|
||||
: i18n.translate(
|
||||
'xpack.security.management.editRole.privilegeSummary.privilegeNotGrantedIconTip',
|
||||
{ defaultMessage: 'Privilege is not granted' }
|
||||
)
|
||||
}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem>
|
||||
<EuiText size="s" data-test-subj="privilegeName">
|
||||
{privilege.name}
|
||||
</EuiText>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function renderMutuallyExclusivePrivilegeGroup(
|
||||
effectiveSubFeaturePrivileges: string[],
|
||||
privilegeGroup: SubFeaturePrivilegeGroup,
|
||||
index: number
|
||||
) {
|
||||
const firstSelectedPrivilege = privilegeGroup.privileges.find((p) =>
|
||||
effectiveSubFeaturePrivileges.includes(p.id)
|
||||
)?.name;
|
||||
|
||||
return (
|
||||
<EuiFlexGroup gutterSize="s" key={index} data-test-subj="mutexPrivilege">
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiIconTip
|
||||
type={firstSelectedPrivilege ? 'check' : 'cross'}
|
||||
color={firstSelectedPrivilege ? 'primary' : 'danger'}
|
||||
content={firstSelectedPrivilege ? 'Privilege is granted' : 'Privilege is not granted'}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem>
|
||||
<EuiText size="s" data-test-subj="privilegeName">
|
||||
{firstSelectedPrivilege ?? 'None'}
|
||||
</EuiText>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -21,6 +21,7 @@ import { mountWithIntl } from '@kbn/test-jest-helpers';
|
|||
import { getDisplayedFeaturePrivileges } from './__fixtures__';
|
||||
import type { PrivilegeSummaryTableProps } from './privilege_summary_table';
|
||||
import { PrivilegeSummaryTable } from './privilege_summary_table';
|
||||
import { ALL_SPACES_ID } from '../../../../../../../common/constants';
|
||||
|
||||
const createRole = (roleKibanaPrivileges: RoleKibanaPrivilege[]) => ({
|
||||
name: 'some-role',
|
||||
|
@ -431,7 +432,7 @@ describe('PrivilegeSummaryTable', () => {
|
|||
hasCustomizedSubFeaturePrivileges: false,
|
||||
primaryFeaturePrivilege: 'All',
|
||||
...maybeExpectSubFeaturePrivileges(allowSubFeaturePrivileges, {
|
||||
'Require all spaces Sub Feature': ['Cool toggle 1'],
|
||||
'Require all spaces Sub Feature': [],
|
||||
}),
|
||||
},
|
||||
},
|
||||
|
@ -440,7 +441,7 @@ describe('PrivilegeSummaryTable', () => {
|
|||
hasCustomizedSubFeaturePrivileges: false,
|
||||
primaryFeaturePrivilege: 'None',
|
||||
...maybeExpectSubFeaturePrivileges(allowSubFeaturePrivileges, {
|
||||
'Require all spaces Sub Feature': ['Cool toggle 1'],
|
||||
'Require all spaces Sub Feature': [],
|
||||
}),
|
||||
},
|
||||
},
|
||||
|
@ -642,7 +643,7 @@ describe('PrivilegeSummaryTable', () => {
|
|||
hasCustomizedSubFeaturePrivileges: false,
|
||||
primaryFeaturePrivilege: 'None',
|
||||
...maybeExpectSubFeaturePrivileges(allowSubFeaturePrivileges, {
|
||||
'Require all spaces Sub Feature': ['Cool toggle 1'],
|
||||
'Require all spaces Sub Feature': [],
|
||||
}),
|
||||
},
|
||||
},
|
||||
|
@ -874,7 +875,7 @@ describe('PrivilegeSummaryTable', () => {
|
|||
hasCustomizedSubFeaturePrivileges: false,
|
||||
primaryFeaturePrivilege: 'Read',
|
||||
...maybeExpectSubFeaturePrivileges(allowSubFeaturePrivileges, {
|
||||
'Require all spaces Sub Feature': ['Cool toggle 1'],
|
||||
'Require all spaces Sub Feature': [],
|
||||
}),
|
||||
},
|
||||
},
|
||||
|
@ -1023,6 +1024,138 @@ describe('PrivilegeSummaryTable', () => {
|
|||
});
|
||||
});
|
||||
|
||||
it('renders effective privileges when all spaces option is selected', async () => {
|
||||
const kibanaPrivileges = createKibanaPrivileges(kibanaFeatures, {
|
||||
allowSubFeaturePrivileges,
|
||||
});
|
||||
|
||||
const role = createRole([
|
||||
{
|
||||
base: ['all'],
|
||||
feature: {
|
||||
with_sub_features: ['minimal_read', 'cool_all'],
|
||||
},
|
||||
spaces: ['*'],
|
||||
},
|
||||
{
|
||||
base: [],
|
||||
feature: {
|
||||
with_sub_features: ['all'],
|
||||
},
|
||||
spaces: ['default', 'space-1'],
|
||||
},
|
||||
]);
|
||||
|
||||
const wrapper = await setup({
|
||||
spaces: [
|
||||
{
|
||||
id: ALL_SPACES_ID,
|
||||
name: '*All Spaces',
|
||||
disabledFeatures: [],
|
||||
},
|
||||
],
|
||||
kibanaPrivileges,
|
||||
role,
|
||||
canCustomizeSubFeaturePrivileges: allowSubFeaturePrivileges,
|
||||
spacesApiUi,
|
||||
});
|
||||
|
||||
const displayedPrivileges = getDisplayedFeaturePrivileges(wrapper, role);
|
||||
|
||||
expect(displayedPrivileges).toEqual({
|
||||
excluded_from_base: {
|
||||
'*': {
|
||||
hasCustomizedSubFeaturePrivileges: false,
|
||||
primaryFeaturePrivilege: 'None',
|
||||
...maybeExpectSubFeaturePrivileges(allowSubFeaturePrivileges, {
|
||||
'Cool Sub Feature': [],
|
||||
}),
|
||||
},
|
||||
'default, space-1': {
|
||||
hasCustomizedSubFeaturePrivileges: false,
|
||||
primaryFeaturePrivilege: 'None',
|
||||
...maybeExpectSubFeaturePrivileges(allowSubFeaturePrivileges, {
|
||||
'Cool Sub Feature': [],
|
||||
}),
|
||||
},
|
||||
},
|
||||
no_sub_features: {
|
||||
'*': {
|
||||
hasCustomizedSubFeaturePrivileges: false,
|
||||
primaryFeaturePrivilege: 'All',
|
||||
},
|
||||
'default, space-1': {
|
||||
hasCustomizedSubFeaturePrivileges: false,
|
||||
primaryFeaturePrivilege: 'All',
|
||||
},
|
||||
},
|
||||
with_excluded_sub_features: {
|
||||
'*': {
|
||||
hasCustomizedSubFeaturePrivileges: false,
|
||||
primaryFeaturePrivilege: 'All',
|
||||
...maybeExpectSubFeaturePrivileges(allowSubFeaturePrivileges, {
|
||||
'Excluded Sub Feature': [],
|
||||
}),
|
||||
},
|
||||
'default, space-1': {
|
||||
hasCustomizedSubFeaturePrivileges: false,
|
||||
primaryFeaturePrivilege: 'All',
|
||||
...maybeExpectSubFeaturePrivileges(allowSubFeaturePrivileges, {
|
||||
'Excluded Sub Feature': [],
|
||||
}),
|
||||
},
|
||||
},
|
||||
with_sub_features: {
|
||||
'*': {
|
||||
hasCustomizedSubFeaturePrivileges: false,
|
||||
primaryFeaturePrivilege: 'All',
|
||||
...maybeExpectSubFeaturePrivileges(allowSubFeaturePrivileges, {
|
||||
'Cool Sub Feature': ['Cool toggle 1', 'Cool toggle 2', 'All'],
|
||||
}),
|
||||
},
|
||||
'default, space-1': {
|
||||
hasCustomizedSubFeaturePrivileges: false,
|
||||
primaryFeaturePrivilege: 'All',
|
||||
...maybeExpectSubFeaturePrivileges(allowSubFeaturePrivileges, {
|
||||
'Cool Sub Feature': ['Cool toggle 1', 'Cool toggle 2', 'All'],
|
||||
}),
|
||||
},
|
||||
},
|
||||
with_require_all_spaces_sub_features: {
|
||||
'*': {
|
||||
hasCustomizedSubFeaturePrivileges: false,
|
||||
primaryFeaturePrivilege: 'All',
|
||||
...maybeExpectSubFeaturePrivileges(allowSubFeaturePrivileges, {
|
||||
'Require all spaces Sub Feature': ['Cool toggle 1'],
|
||||
}),
|
||||
},
|
||||
'default, space-1': {
|
||||
hasCustomizedSubFeaturePrivileges: false,
|
||||
primaryFeaturePrivilege: 'All',
|
||||
...maybeExpectSubFeaturePrivileges(allowSubFeaturePrivileges, {
|
||||
'Require all spaces Sub Feature': ['Cool toggle 1'],
|
||||
}),
|
||||
},
|
||||
},
|
||||
with_require_all_spaces_for_feature_and_sub_features: {
|
||||
'*': {
|
||||
hasCustomizedSubFeaturePrivileges: false,
|
||||
primaryFeaturePrivilege: 'All',
|
||||
...maybeExpectSubFeaturePrivileges(allowSubFeaturePrivileges, {
|
||||
'Require all spaces Sub Feature': ['Cool toggle 1'],
|
||||
}),
|
||||
},
|
||||
'default, space-1': {
|
||||
hasCustomizedSubFeaturePrivileges: false,
|
||||
primaryFeaturePrivilege: 'All',
|
||||
...maybeExpectSubFeaturePrivileges(allowSubFeaturePrivileges, {
|
||||
'Require all spaces Sub Feature': ['Cool toggle 1'],
|
||||
}),
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('renders effective privileges for a complex setup', async () => {
|
||||
const kibanaPrivileges = createKibanaPrivileges(kibanaFeatures, {
|
||||
allowSubFeaturePrivileges,
|
||||
|
@ -1180,7 +1313,7 @@ describe('PrivilegeSummaryTable', () => {
|
|||
hasCustomizedSubFeaturePrivileges: false,
|
||||
primaryFeaturePrivilege: 'None',
|
||||
...maybeExpectSubFeaturePrivileges(allowSubFeaturePrivileges, {
|
||||
'Require all spaces Sub Feature': ['Cool toggle 1'],
|
||||
'Require all spaces Sub Feature': [],
|
||||
}),
|
||||
},
|
||||
'space-1, space-2': {
|
||||
|
@ -1193,6 +1326,360 @@ describe('PrivilegeSummaryTable', () => {
|
|||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('renders effective privileges for requireAllSpaces feature when all spaces is not selected', async () => {
|
||||
const kibanaPrivileges = createKibanaPrivileges(kibanaFeatures, {
|
||||
allowSubFeaturePrivileges,
|
||||
});
|
||||
|
||||
const role = createRole([
|
||||
{
|
||||
base: [],
|
||||
feature: {
|
||||
with_sub_features: ['all'],
|
||||
},
|
||||
spaces: ['default', 'space-1'],
|
||||
},
|
||||
]);
|
||||
|
||||
const wrapper = await setup({
|
||||
spaces,
|
||||
kibanaPrivileges,
|
||||
role,
|
||||
canCustomizeSubFeaturePrivileges: allowSubFeaturePrivileges,
|
||||
spacesApiUi,
|
||||
});
|
||||
|
||||
const displayedPrivileges = getDisplayedFeaturePrivileges(wrapper, role);
|
||||
|
||||
expect(displayedPrivileges.with_require_all_spaces_sub_features).toEqual({
|
||||
'default, space-1': {
|
||||
hasCustomizedSubFeaturePrivileges: false,
|
||||
primaryFeaturePrivilege: 'None',
|
||||
...maybeExpectSubFeaturePrivileges(allowSubFeaturePrivileges, {
|
||||
'Require all spaces Sub Feature': [],
|
||||
}),
|
||||
},
|
||||
});
|
||||
|
||||
expect(displayedPrivileges.with_require_all_spaces_for_feature_and_sub_features).toEqual({
|
||||
'default, space-1': {
|
||||
hasCustomizedSubFeaturePrivileges: false,
|
||||
primaryFeaturePrivilege: 'None',
|
||||
...maybeExpectSubFeaturePrivileges(allowSubFeaturePrivileges, {
|
||||
'Require all spaces Sub Feature': [],
|
||||
}),
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('renders effective privileges for requireAllSpaces feature when all spaces is selected without granting access', async () => {
|
||||
const kibanaPrivileges = createKibanaPrivileges(kibanaFeatures, {
|
||||
allowSubFeaturePrivileges,
|
||||
});
|
||||
|
||||
const role = createRole([
|
||||
{
|
||||
base: [],
|
||||
feature: {
|
||||
with_sub_features: ['all'],
|
||||
},
|
||||
spaces: ['*'],
|
||||
},
|
||||
{
|
||||
base: [],
|
||||
feature: {
|
||||
with_sub_features: ['all'],
|
||||
},
|
||||
spaces: ['default', 'space-1'],
|
||||
},
|
||||
]);
|
||||
|
||||
const wrapper = await setup({
|
||||
spaces: [
|
||||
{
|
||||
id: ALL_SPACES_ID,
|
||||
name: '*All Spaces',
|
||||
disabledFeatures: [],
|
||||
},
|
||||
...spaces,
|
||||
],
|
||||
kibanaPrivileges,
|
||||
role,
|
||||
canCustomizeSubFeaturePrivileges: allowSubFeaturePrivileges,
|
||||
spacesApiUi,
|
||||
});
|
||||
|
||||
const displayedPrivileges = getDisplayedFeaturePrivileges(wrapper, role);
|
||||
|
||||
expect(displayedPrivileges.with_require_all_spaces_sub_features).toEqual({
|
||||
'*': {
|
||||
hasCustomizedSubFeaturePrivileges: false,
|
||||
primaryFeaturePrivilege: 'None',
|
||||
...maybeExpectSubFeaturePrivileges(allowSubFeaturePrivileges, {
|
||||
'Require all spaces Sub Feature': [],
|
||||
}),
|
||||
},
|
||||
'default, space-1': {
|
||||
hasCustomizedSubFeaturePrivileges: false,
|
||||
primaryFeaturePrivilege: 'None',
|
||||
...maybeExpectSubFeaturePrivileges(allowSubFeaturePrivileges, {
|
||||
'Require all spaces Sub Feature': [],
|
||||
}),
|
||||
},
|
||||
});
|
||||
|
||||
expect(displayedPrivileges.with_require_all_spaces_for_feature_and_sub_features).toEqual({
|
||||
'*': {
|
||||
hasCustomizedSubFeaturePrivileges: false,
|
||||
primaryFeaturePrivilege: 'None',
|
||||
...maybeExpectSubFeaturePrivileges(allowSubFeaturePrivileges, {
|
||||
'Require all spaces Sub Feature': [],
|
||||
}),
|
||||
},
|
||||
'default, space-1': {
|
||||
hasCustomizedSubFeaturePrivileges: false,
|
||||
primaryFeaturePrivilege: 'None',
|
||||
...maybeExpectSubFeaturePrivileges(allowSubFeaturePrivileges, {
|
||||
'Require all spaces Sub Feature': [],
|
||||
}),
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('renders effective privileges for requireAllSpaces feature when all spaces grants read access', async () => {
|
||||
const kibanaPrivileges = createKibanaPrivileges(kibanaFeatures, {
|
||||
allowSubFeaturePrivileges,
|
||||
});
|
||||
|
||||
const role = createRole([
|
||||
{
|
||||
base: [],
|
||||
feature: {
|
||||
with_require_all_spaces_for_feature_and_sub_features: ['read'],
|
||||
},
|
||||
spaces: ['*'],
|
||||
},
|
||||
{
|
||||
base: ['all'],
|
||||
feature: {},
|
||||
spaces: ['default'],
|
||||
},
|
||||
]);
|
||||
|
||||
const wrapper = await setup({
|
||||
spaces: [
|
||||
{
|
||||
id: ALL_SPACES_ID,
|
||||
name: '*All Spaces',
|
||||
disabledFeatures: [],
|
||||
},
|
||||
...spaces,
|
||||
],
|
||||
kibanaPrivileges,
|
||||
role,
|
||||
canCustomizeSubFeaturePrivileges: allowSubFeaturePrivileges,
|
||||
spacesApiUi,
|
||||
});
|
||||
|
||||
const displayedPrivileges = getDisplayedFeaturePrivileges(wrapper, role);
|
||||
|
||||
expect(displayedPrivileges.with_require_all_spaces_for_feature_and_sub_features).toEqual({
|
||||
'*': {
|
||||
hasCustomizedSubFeaturePrivileges: false,
|
||||
primaryFeaturePrivilege: 'Read',
|
||||
...maybeExpectSubFeaturePrivileges(allowSubFeaturePrivileges, {
|
||||
'Require all spaces Sub Feature': [],
|
||||
}),
|
||||
},
|
||||
default: {
|
||||
hasCustomizedSubFeaturePrivileges: false,
|
||||
primaryFeaturePrivilege: 'Read',
|
||||
...maybeExpectSubFeaturePrivileges(allowSubFeaturePrivileges, {
|
||||
'Require all spaces Sub Feature': [],
|
||||
}),
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('renders effective privileges for requireAllSpaces feature when all spaces grants all access', async () => {
|
||||
const kibanaPrivileges = createKibanaPrivileges(kibanaFeatures, {
|
||||
allowSubFeaturePrivileges,
|
||||
});
|
||||
|
||||
const role = createRole([
|
||||
{
|
||||
base: [],
|
||||
feature: {
|
||||
with_require_all_spaces_for_feature_and_sub_features: ['all'],
|
||||
with_require_all_spaces_sub_features: ['all'],
|
||||
},
|
||||
spaces: ['*'],
|
||||
},
|
||||
{
|
||||
base: ['read'],
|
||||
feature: {},
|
||||
spaces: ['default'],
|
||||
},
|
||||
]);
|
||||
|
||||
const wrapper = await setup({
|
||||
spaces: [
|
||||
{
|
||||
id: ALL_SPACES_ID,
|
||||
name: '*All Spaces',
|
||||
disabledFeatures: [],
|
||||
},
|
||||
...spaces,
|
||||
],
|
||||
kibanaPrivileges,
|
||||
role,
|
||||
canCustomizeSubFeaturePrivileges: allowSubFeaturePrivileges,
|
||||
spacesApiUi,
|
||||
});
|
||||
|
||||
const displayedPrivileges = getDisplayedFeaturePrivileges(wrapper, role);
|
||||
|
||||
expect(displayedPrivileges.with_require_all_spaces_sub_features).toEqual({
|
||||
'*': {
|
||||
hasCustomizedSubFeaturePrivileges: false,
|
||||
primaryFeaturePrivilege: 'All',
|
||||
...maybeExpectSubFeaturePrivileges(allowSubFeaturePrivileges, {
|
||||
'Require all spaces Sub Feature': ['Cool toggle 1'],
|
||||
}),
|
||||
},
|
||||
default: {
|
||||
hasCustomizedSubFeaturePrivileges: false,
|
||||
primaryFeaturePrivilege: 'All',
|
||||
...maybeExpectSubFeaturePrivileges(allowSubFeaturePrivileges, {
|
||||
'Require all spaces Sub Feature': ['Cool toggle 1'],
|
||||
}),
|
||||
},
|
||||
});
|
||||
|
||||
expect(displayedPrivileges.with_require_all_spaces_for_feature_and_sub_features).toEqual({
|
||||
'*': {
|
||||
hasCustomizedSubFeaturePrivileges: false,
|
||||
primaryFeaturePrivilege: 'All',
|
||||
...maybeExpectSubFeaturePrivileges(allowSubFeaturePrivileges, {
|
||||
'Require all spaces Sub Feature': ['Cool toggle 1'],
|
||||
}),
|
||||
},
|
||||
default: {
|
||||
hasCustomizedSubFeaturePrivileges: false,
|
||||
primaryFeaturePrivilege: 'All',
|
||||
...maybeExpectSubFeaturePrivileges(allowSubFeaturePrivileges, {
|
||||
'Require all spaces Sub Feature': ['Cool toggle 1'],
|
||||
}),
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('renders effective privileges for requireAllSpaces feature when all spaces grants base read access', async () => {
|
||||
const kibanaPrivileges = createKibanaPrivileges(kibanaFeatures, {
|
||||
allowSubFeaturePrivileges,
|
||||
});
|
||||
|
||||
const role = createRole([
|
||||
{
|
||||
base: ['read'],
|
||||
feature: {},
|
||||
spaces: ['*'],
|
||||
},
|
||||
{
|
||||
base: ['all'],
|
||||
feature: {},
|
||||
spaces: ['default'],
|
||||
},
|
||||
]);
|
||||
|
||||
const wrapper = await setup({
|
||||
spaces: [
|
||||
{
|
||||
id: ALL_SPACES_ID,
|
||||
name: '*All Spaces',
|
||||
disabledFeatures: [],
|
||||
},
|
||||
...spaces,
|
||||
],
|
||||
kibanaPrivileges,
|
||||
role,
|
||||
canCustomizeSubFeaturePrivileges: allowSubFeaturePrivileges,
|
||||
spacesApiUi,
|
||||
});
|
||||
|
||||
const displayedPrivileges = getDisplayedFeaturePrivileges(wrapper, role);
|
||||
|
||||
expect(displayedPrivileges.with_require_all_spaces_for_feature_and_sub_features).toEqual({
|
||||
'*': {
|
||||
hasCustomizedSubFeaturePrivileges: false,
|
||||
primaryFeaturePrivilege: 'Read',
|
||||
...maybeExpectSubFeaturePrivileges(allowSubFeaturePrivileges, {
|
||||
'Require all spaces Sub Feature': [],
|
||||
}),
|
||||
},
|
||||
default: {
|
||||
hasCustomizedSubFeaturePrivileges: false,
|
||||
primaryFeaturePrivilege: 'Read',
|
||||
...maybeExpectSubFeaturePrivileges(allowSubFeaturePrivileges, {
|
||||
'Require all spaces Sub Feature': [],
|
||||
}),
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('renders effective privileges for requireAllSpaces feature when all spaces grants base all access', async () => {
|
||||
const kibanaPrivileges = createKibanaPrivileges(kibanaFeatures, {
|
||||
allowSubFeaturePrivileges,
|
||||
});
|
||||
|
||||
const role = createRole([
|
||||
{
|
||||
base: ['all'],
|
||||
feature: {},
|
||||
spaces: ['*'],
|
||||
},
|
||||
{
|
||||
base: ['read'],
|
||||
feature: {},
|
||||
spaces: ['default'],
|
||||
},
|
||||
]);
|
||||
|
||||
const wrapper = await setup({
|
||||
spaces: [
|
||||
{
|
||||
id: ALL_SPACES_ID,
|
||||
name: '*All Spaces',
|
||||
disabledFeatures: [],
|
||||
},
|
||||
...spaces,
|
||||
],
|
||||
kibanaPrivileges,
|
||||
role,
|
||||
canCustomizeSubFeaturePrivileges: allowSubFeaturePrivileges,
|
||||
spacesApiUi,
|
||||
});
|
||||
|
||||
const displayedPrivileges = getDisplayedFeaturePrivileges(wrapper, role);
|
||||
|
||||
expect(displayedPrivileges.with_require_all_spaces_for_feature_and_sub_features).toEqual({
|
||||
'*': {
|
||||
hasCustomizedSubFeaturePrivileges: false,
|
||||
primaryFeaturePrivilege: 'All',
|
||||
...maybeExpectSubFeaturePrivileges(allowSubFeaturePrivileges, {
|
||||
'Require all spaces Sub Feature': ['Cool toggle 1'],
|
||||
}),
|
||||
},
|
||||
default: {
|
||||
hasCustomizedSubFeaturePrivileges: false,
|
||||
primaryFeaturePrivilege: 'All',
|
||||
...maybeExpectSubFeaturePrivileges(allowSubFeaturePrivileges, {
|
||||
'Require all spaces Sub Feature': ['Cool toggle 1'],
|
||||
}),
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -48,14 +48,31 @@ function getColumnKey(entry: RoleKibanaPrivilege) {
|
|||
return `privilege_entry_${entry.spaces.join('|')}`;
|
||||
}
|
||||
|
||||
function showPrivilege(allSpacesSelected: boolean, primaryFeature?: PrimaryFeaturePrivilege) {
|
||||
function showPrivilege({
|
||||
allSpacesSelected,
|
||||
primaryFeature,
|
||||
globalPrimaryFeature,
|
||||
}: {
|
||||
allSpacesSelected: boolean;
|
||||
primaryFeature?: PrimaryFeaturePrivilege;
|
||||
globalPrimaryFeature?: PrimaryFeaturePrivilege;
|
||||
}) {
|
||||
if (
|
||||
primaryFeature?.name == null ||
|
||||
primaryFeature?.disabled ||
|
||||
(primaryFeature.requireAllSpaces && !allSpacesSelected)
|
||||
(primaryFeature?.requireAllSpaces && !allSpacesSelected)
|
||||
) {
|
||||
return 'None';
|
||||
}
|
||||
|
||||
// If primary feature requires all spaces we cannot rely on primaryFeature.name.
|
||||
// Example:
|
||||
// primaryFeature: feature with requireAllSpaces in space-a has all privileges set to All
|
||||
// globalPrimaryFeature: feature in *AllSpaces has privileges set to Read (this is the correct one to display)
|
||||
if (primaryFeature?.requireAllSpaces && allSpacesSelected) {
|
||||
return globalPrimaryFeature?.name ?? 'None';
|
||||
}
|
||||
|
||||
return primaryFeature?.name;
|
||||
}
|
||||
|
||||
|
@ -127,6 +144,15 @@ export const PrivilegeSummaryTable = (props: PrivilegeSummaryTableProps) => {
|
|||
}
|
||||
return 0;
|
||||
});
|
||||
|
||||
const globalRawPrivilege = rawKibanaPrivileges.find((entry) =>
|
||||
isGlobalPrivilegeDefinition(entry)
|
||||
);
|
||||
|
||||
const globalPrivilege = globalRawPrivilege
|
||||
? calculator.getEffectiveFeaturePrivileges(globalRawPrivilege)
|
||||
: null;
|
||||
|
||||
const privilegeColumns = rawKibanaPrivileges.map((entry) => {
|
||||
const key = getColumnKey(entry);
|
||||
return {
|
||||
|
@ -161,10 +187,11 @@ export const PrivilegeSummaryTable = (props: PrivilegeSummaryTableProps) => {
|
|||
hasCustomizedSubFeaturePrivileges ? 'additionalPrivilegesGranted' : ''
|
||||
}`}
|
||||
>
|
||||
{showPrivilege(
|
||||
props.spaces.some((space) => space.id === ALL_SPACES_ID),
|
||||
primary
|
||||
)}{' '}
|
||||
{showPrivilege({
|
||||
allSpacesSelected: props.spaces.some((space) => space.id === ALL_SPACES_ID),
|
||||
primaryFeature: primary,
|
||||
globalPrimaryFeature: globalPrivilege?.[record.featureId]?.primary,
|
||||
})}{' '}
|
||||
{iconTip}
|
||||
</span>
|
||||
);
|
||||
|
@ -178,12 +205,14 @@ export const PrivilegeSummaryTable = (props: PrivilegeSummaryTableProps) => {
|
|||
}
|
||||
columns.push(featureColumn, ...privilegeColumns);
|
||||
|
||||
const privileges = rawKibanaPrivileges.reduce((acc, entry) => {
|
||||
const privileges = rawKibanaPrivileges.reduce<
|
||||
Record<string, [string[], EffectiveFeaturePrivileges]>
|
||||
>((acc, entry) => {
|
||||
return {
|
||||
...acc,
|
||||
[getColumnKey(entry)]: calculator.getEffectiveFeaturePrivileges(entry),
|
||||
[getColumnKey(entry)]: [entry.spaces, calculator.getEffectiveFeaturePrivileges(entry)],
|
||||
};
|
||||
}, {} as Record<string, EffectiveFeaturePrivileges>);
|
||||
}, {});
|
||||
|
||||
const accordions: any[] = [];
|
||||
|
||||
|
@ -210,11 +239,15 @@ export const PrivilegeSummaryTable = (props: PrivilegeSummaryTableProps) => {
|
|||
</EuiFlexGroup>
|
||||
);
|
||||
|
||||
const categoryPrivileges = Object.fromEntries(
|
||||
Object.entries(privileges).map(([key, [, featurePrivileges]]) => [key, featurePrivileges])
|
||||
);
|
||||
|
||||
const categoryItems = featuresInCategory.map((feature) => {
|
||||
return {
|
||||
feature,
|
||||
featureId: feature.id,
|
||||
...privileges,
|
||||
...categoryPrivileges,
|
||||
};
|
||||
});
|
||||
|
||||
|
@ -241,7 +274,10 @@ export const PrivilegeSummaryTable = (props: PrivilegeSummaryTableProps) => {
|
|||
[featureId]: (
|
||||
<PrivilegeSummaryExpandedRow
|
||||
feature={props.kibanaPrivileges.getSecuredFeature(featureId)}
|
||||
effectiveFeaturePrivileges={Object.values(privileges).map((p) => p[featureId])}
|
||||
effectiveFeaturePrivileges={Object.values(privileges).map(([spaces, privs]) => [
|
||||
spaces,
|
||||
privs[featureId],
|
||||
])}
|
||||
/>
|
||||
),
|
||||
};
|
||||
|
|
|
@ -115,15 +115,11 @@ describe('PrivilegeSpaceForm', () => {
|
|||
},
|
||||
"with_require_all_spaces_for_feature_and_sub_features": Object {
|
||||
"primaryFeaturePrivilege": "none",
|
||||
"subFeaturePrivileges": Array [
|
||||
"cool_toggle_1",
|
||||
],
|
||||
"subFeaturePrivileges": Array [],
|
||||
},
|
||||
"with_require_all_spaces_sub_features": Object {
|
||||
"primaryFeaturePrivilege": "all",
|
||||
"subFeaturePrivileges": Array [
|
||||
"cool_toggle_1",
|
||||
],
|
||||
"subFeaturePrivileges": Array [],
|
||||
},
|
||||
"with_sub_features": Object {
|
||||
"primaryFeaturePrivilege": "all",
|
||||
|
|
|
@ -218,7 +218,7 @@ export class SpaceAwarePrivilegeSection extends Component<Props, State> {
|
|||
const viewMatrixButton = (
|
||||
<PrivilegeSummary
|
||||
role={this.props.role}
|
||||
spaces={this.getDisplaySpaces()}
|
||||
spaces={this.getSelectedSpaces()}
|
||||
kibanaPrivileges={this.props.kibanaPrivileges}
|
||||
canCustomizeSubFeaturePrivileges={this.props.canCustomizeSubFeaturePrivileges}
|
||||
spacesApiUi={this.props.spacesApiUi}
|
||||
|
@ -240,6 +240,11 @@ export class SpaceAwarePrivilegeSection extends Component<Props, State> {
|
|||
return [this.globalSpaceEntry, ...this.props.spaces];
|
||||
};
|
||||
|
||||
private getSelectedSpaces = () =>
|
||||
this.getDisplaySpaces().filter((space) =>
|
||||
this.props.role.kibana.some((entry) => entry.spaces.includes(space.id))
|
||||
);
|
||||
|
||||
private getAvailableSpaces = (includeSpacesFromPrivilegeIndex: number = -1) => {
|
||||
const spacesToExclude = _.uniq(
|
||||
_.flatten(
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue