-
Notifications
You must be signed in to change notification settings - Fork 8.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Cases] RBAC Bugs #101325
[Cases] RBAC Bugs #101325
Changes from 130 commits
7f1a7dd
164582d
7eaf41e
f8e62c6
09589c3
eb75eb0
a930f03
d6f3b09
b82e686
4d05175
75d72ae
e65838b
1fd66af
4560d42
ef9b3b2
b22a032
ddc2280
9d008d8
7bb23dd
65d4c6b
59e4045
4092733
311e3f4
f2a50d3
00d89ca
40cfcce
644a7ac
9bb1b86
12d6e2e
84d9167
4bed458
ecb3135
fe1d8c8
22e7752
96f81a4
e3ae097
06d7c64
2ca4134
17110b1
bc06264
a04e0d7
7fe4e40
2847861
a2e1da8
9263d7d
afff0cc
7cf9172
0a95e55
1a895e5
9ffc3db
4f3c37e
36781db
73a4bfc
ae918cc
e59602c
34f2d86
613e859
676173e
6cdfa84
7b21b7a
103388e
18e75d9
d99d9f8
b121662
42162e3
298ba34
c0fb868
21d173d
b910889
78dfac4
bf583a8
3fd893f
86568ed
952e2a3
e26de43
2d8601b
570cddb
3c7670b
dafb4fe
b7c5ebd
698e8e2
22abf1f
71225eb
f7a816b
2ed0a99
fd39b25
a193138
1f9059c
2085a3b
66c1d43
018dcb5
34b16c5
9ba1243
315a6e4
02ad6a4
e8c3532
8881899
dd62656
acf550b
148623e
7acf83a
b03fa4c
445c846
c08ac43
373cd68
d59dbad
7ef02f4
739fd6f
86f5540
599ddb9
eadbfd8
c32dc14
56a9a3d
d5bd11b
dee17f5
bca5793
ab2632c
4f28947
60efdf0
b46a94e
f80b88d
7c27b47
b7cf87a
5dea976
4ba1123
1296193
22e35e1
c4dfebd
423286a
1a84ed5
187a2bf
301c191
c5c6e49
c0b9c7c
fa5d183
5f816fc
7c965c9
4f8ac35
320621e
0b6b50c
be52548
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -15,7 +15,7 @@ import { Router, routeData, mockHistory, mockLocation } from '../__mock__/router | |
|
||
import { CommentRequest, CommentType, SECURITY_SOLUTION_OWNER } from '../../../common'; | ||
import { usePostComment } from '../../containers/use_post_comment'; | ||
import { AddComment, AddCommentRefObject } from '.'; | ||
import { AddComment, AddCommentProps, AddCommentRefObject } from '.'; | ||
import { CasesTimelineIntegrationProvider } from '../timeline_context'; | ||
import { timelineIntegrationMock } from '../__mock__/timeline'; | ||
|
||
|
@@ -26,10 +26,9 @@ const onCommentSaving = jest.fn(); | |
const onCommentPosted = jest.fn(); | ||
const postComment = jest.fn(); | ||
|
||
const addCommentProps = { | ||
const addCommentProps: AddCommentProps = { | ||
caseId: '1234', | ||
disabled: false, | ||
insertQuote: null, | ||
userCanCrud: true, | ||
onCommentSaving, | ||
onCommentPosted, | ||
showLoading: false, | ||
|
@@ -100,12 +99,12 @@ describe('AddComment ', () => { | |
).toBeTruthy(); | ||
}); | ||
|
||
it('should disable submit button when disabled prop passed', () => { | ||
it('should disable submit button when isLoading is true', () => { | ||
usePostCommentMock.mockImplementation(() => ({ ...defaultPostComment, isLoading: true })); | ||
const wrapper = mount( | ||
<TestProviders> | ||
<Router history={mockHistory}> | ||
<AddComment {...{ ...addCommentProps, disabled: true }} /> | ||
<AddComment {...{ ...addCommentProps }} /> | ||
</Router> | ||
</TestProviders> | ||
); | ||
|
@@ -115,6 +114,19 @@ describe('AddComment ', () => { | |
).toBeTruthy(); | ||
}); | ||
|
||
it('should hide the component when the user does not have crud permissions', () => { | ||
usePostCommentMock.mockImplementation(() => ({ ...defaultPostComment, isLoading: true })); | ||
const wrapper = mount( | ||
<TestProviders> | ||
<Router history={mockHistory}> | ||
<AddComment {...{ ...addCommentProps, userCanCrud: false }} /> | ||
</Router> | ||
</TestProviders> | ||
); | ||
|
||
expect(wrapper.find(`[data-test-subj="sadd-comment"]`).exists()).toBeFalsy(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: What There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nice catch! that data-test-subj definitely wouldn't have existed 😆 should be |
||
}); | ||
|
||
it('should insert a quote', async () => { | ||
const sampleQuote = 'what a cool quote'; | ||
const ref = React.createRef<AddCommentRefObject>(); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -33,9 +33,9 @@ export interface AddCommentRefObject { | |
addQuote: (quote: string) => void; | ||
} | ||
|
||
interface AddCommentProps { | ||
export interface AddCommentProps { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Exporting so I can use it in the test above to ensure that the props stay inline with the definition. |
||
caseId: string; | ||
disabled?: boolean; | ||
userCanCrud?: boolean; | ||
onCommentSaving?: () => void; | ||
onCommentPosted: (newCase: Case) => void; | ||
showLoading?: boolean; | ||
|
@@ -45,7 +45,7 @@ interface AddCommentProps { | |
export const AddComment = React.memo( | ||
forwardRef<AddCommentRefObject, AddCommentProps>( | ||
( | ||
{ caseId, disabled, onCommentPosted, onCommentSaving, showLoading = true, subCaseId }, | ||
{ caseId, userCanCrud, onCommentPosted, onCommentSaving, showLoading = true, subCaseId }, | ||
ref | ||
) => { | ||
const owner = useOwnerContext(); | ||
|
@@ -91,31 +91,33 @@ export const AddComment = React.memo( | |
return ( | ||
<span id="add-comment-permLink"> | ||
{isLoading && showLoading && <MySpinner data-test-subj="loading-spinner" size="xl" />} | ||
<Form form={form}> | ||
<UseField | ||
path={fieldName} | ||
component={MarkdownEditorForm} | ||
componentProps={{ | ||
idAria: 'caseComment', | ||
isDisabled: isLoading, | ||
dataTestSubj: 'add-comment', | ||
placeholder: i18n.ADD_COMMENT_HELP_TEXT, | ||
bottomRightContent: ( | ||
<EuiButton | ||
data-test-subj="submit-comment" | ||
iconType="plusInCircle" | ||
isDisabled={isLoading || disabled} | ||
isLoading={isLoading} | ||
onClick={onSubmit} | ||
size="s" | ||
> | ||
{i18n.ADD_COMMENT} | ||
</EuiButton> | ||
), | ||
}} | ||
/> | ||
<InsertTimeline fieldName="comment" /> | ||
</Form> | ||
{userCanCrud && ( | ||
<Form form={form}> | ||
<UseField | ||
path={fieldName} | ||
component={MarkdownEditorForm} | ||
componentProps={{ | ||
idAria: 'caseComment', | ||
isDisabled: isLoading, | ||
dataTestSubj: 'add-comment', | ||
placeholder: i18n.ADD_COMMENT_HELP_TEXT, | ||
bottomRightContent: ( | ||
<EuiButton | ||
data-test-subj="submit-comment" | ||
iconType="plusInCircle" | ||
isDisabled={isLoading} | ||
isLoading={isLoading} | ||
onClick={onSubmit} | ||
size="s" | ||
> | ||
{i18n.ADD_COMMENT} | ||
</EuiButton> | ||
), | ||
}} | ||
/> | ||
<InsertTimeline fieldName="comment" /> | ||
</Form> | ||
)} | ||
</span> | ||
); | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -17,7 +17,6 @@ interface OwnProps { | |
actionsErrors: ErrorMessage[]; | ||
configureCasesNavigation: CasesNavigation; | ||
createCaseNavigation: CasesNavigation; | ||
userCanCrud: boolean; | ||
} | ||
|
||
type Props = OwnProps; | ||
|
@@ -26,22 +25,20 @@ export const NavButtons: FunctionComponent<Props> = ({ | |
actionsErrors, | ||
configureCasesNavigation, | ||
createCaseNavigation, | ||
userCanCrud, | ||
}) => ( | ||
<EuiFlexGroup> | ||
<EuiFlexItem grow={false}> | ||
<ConfigureCaseButton | ||
configureCasesNavigation={configureCasesNavigation} | ||
label={i18n.CONFIGURE_CASES_BUTTON} | ||
isDisabled={!isEmpty(actionsErrors) || !userCanCrud} | ||
isDisabled={!isEmpty(actionsErrors)} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We don't need to rely on |
||
showToolTip={!isEmpty(actionsErrors)} | ||
msgTooltip={!isEmpty(actionsErrors) ? actionsErrors[0].description : <></>} | ||
titleTooltip={!isEmpty(actionsErrors) ? actionsErrors[0].title : ''} | ||
/> | ||
</EuiFlexItem> | ||
<EuiFlexItem grow={false}> | ||
<LinkButton | ||
isDisabled={!userCanCrud} | ||
fill | ||
onClick={createCaseNavigation.onClick} | ||
href={createCaseNavigation.href} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -121,19 +121,21 @@ export const CasesTable: FunctionComponent<CasesTableProps> = ({ | |
<EuiEmptyPrompt | ||
title={<h3>{i18n.NO_CASES}</h3>} | ||
titleSize="xs" | ||
body={i18n.NO_CASES_BODY} | ||
body={userCanCrud ? i18n.NO_CASES_BODY : i18n.NO_CASES_BODY_READ_ONLY} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The |
||
actions={ | ||
<LinkButton | ||
isDisabled={!userCanCrud} | ||
fill | ||
size="s" | ||
onClick={goToCreateCase} | ||
href={createCaseNavigation.href} | ||
iconType="plusInCircle" | ||
data-test-subj="cases-table-add-case" | ||
> | ||
{i18n.ADD_NEW_CASE} | ||
</LinkButton> | ||
userCanCrud && ( | ||
<LinkButton | ||
isDisabled={!userCanCrud} | ||
fill | ||
size="s" | ||
onClick={goToCreateCase} | ||
href={createCaseNavigation.href} | ||
iconType="plusInCircle" | ||
data-test-subj="cases-table-add-case" | ||
> | ||
{i18n.ADD_NEW_CASE} | ||
</LinkButton> | ||
) | ||
} | ||
/> | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,18 +5,7 @@ | |
* 2.0. | ||
*/ | ||
|
||
import React from 'react'; | ||
import md5 from 'md5'; | ||
|
||
import * as i18n from './translations'; | ||
import { ErrorMessage } from './types'; | ||
|
||
export const permissionsReadOnlyErrorMessage: ErrorMessage = { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No longer referenced. |
||
id: 'read-only-privileges-error', | ||
title: i18n.READ_ONLY_FEATURE_TITLE, | ||
description: <>{i18n.READ_ONLY_FEATURE_MSG}</>, | ||
errorType: 'warning', | ||
}; | ||
|
||
export const createCalloutId = (ids: string[], delimiter: string = '|'): string => | ||
md5(ids.join(delimiter)); |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,15 +7,6 @@ | |
|
||
import { i18n } from '@kbn/i18n'; | ||
|
||
export const READ_ONLY_FEATURE_TITLE = i18n.translate('xpack.cases.readOnlyFeatureTitle', { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. heads up, we're going to have a few conflicts between this and my Cases Cleanup PR #102103 |
||
defaultMessage: 'You cannot open new or update existing cases', | ||
}); | ||
|
||
export const READ_ONLY_FEATURE_MSG = i18n.translate('xpack.cases.readOnlyFeatureDescription', { | ||
defaultMessage: | ||
'You only have privileges to view cases. If you need to open and update cases, contact your Kibana administrator.', | ||
}); | ||
|
||
export const DISMISS_CALLOUT = i18n.translate('xpack.cases.dismissErrorsPushServiceCallOutTitle', { | ||
defaultMessage: 'Dismiss', | ||
}); |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -19,14 +19,12 @@ interface CaseViewActions { | |
allCasesNavigation: CasesNavigation; | ||
caseData: Case; | ||
currentExternalIncident: CaseService | null; | ||
disabled?: boolean; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is hidden by the parent component if it is a readonly user. |
||
} | ||
|
||
const ActionsComponent: React.FC<CaseViewActions> = ({ | ||
allCasesNavigation, | ||
caseData, | ||
currentExternalIncident, | ||
disabled = false, | ||
}) => { | ||
// Delete case | ||
const { | ||
|
@@ -39,7 +37,6 @@ const ActionsComponent: React.FC<CaseViewActions> = ({ | |
const propertyActions = useMemo( | ||
() => [ | ||
{ | ||
disabled, | ||
iconType: 'trash', | ||
label: i18n.DELETE_CASE, | ||
onClick: handleToggleModal, | ||
|
@@ -54,7 +51,7 @@ const ActionsComponent: React.FC<CaseViewActions> = ({ | |
] | ||
: []), | ||
], | ||
[disabled, handleToggleModal, currentExternalIncident] | ||
[handleToggleModal, currentExternalIncident] | ||
); | ||
|
||
if (isDeleted) { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -40,7 +40,7 @@ interface CaseActionBarProps { | |
allCasesNavigation: CasesNavigation; | ||
caseData: Case; | ||
currentExternalIncident: CaseService | null; | ||
disabled?: boolean; | ||
userCanCrud?: boolean; | ||
disableAlerting: boolean; | ||
isLoading: boolean; | ||
onRefresh: () => void; | ||
|
@@ -50,8 +50,8 @@ const CaseActionBarComponent: React.FC<CaseActionBarProps> = ({ | |
allCasesNavigation, | ||
caseData, | ||
currentExternalIncident, | ||
disabled = false, | ||
disableAlerting, | ||
userCanCrud = true, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I see that There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We could probably just make it a required parameter. I think for this component it's only used in one place 👍 |
||
isLoading, | ||
onRefresh, | ||
onUpdateField, | ||
|
@@ -87,7 +87,7 @@ const CaseActionBarComponent: React.FC<CaseActionBarProps> = ({ | |
<EuiDescriptionListDescription> | ||
<StatusContextMenu | ||
currentStatus={caseData.status} | ||
disabled={disabled || isLoading} | ||
disabled={!userCanCrud || isLoading} | ||
onStatusChanged={onStatusChanged} | ||
/> | ||
</EuiDescriptionListDescription> | ||
|
@@ -108,7 +108,7 @@ const CaseActionBarComponent: React.FC<CaseActionBarProps> = ({ | |
<EuiFlexItem grow={false}> | ||
<EuiDescriptionList compressed> | ||
<EuiFlexGroup gutterSize="l" alignItems="center"> | ||
{!disableAlerting && ( | ||
{userCanCrud && !disableAlerting && ( | ||
<EuiFlexItem> | ||
<EuiDescriptionListTitle> | ||
<EuiFlexGroup component="span" alignItems="center" gutterSize="xs"> | ||
|
@@ -122,7 +122,7 @@ const CaseActionBarComponent: React.FC<CaseActionBarProps> = ({ | |
</EuiDescriptionListTitle> | ||
<EuiDescriptionListDescription> | ||
<SyncAlertsSwitch | ||
disabled={disabled || isLoading} | ||
disabled={isLoading} | ||
isSynced={caseData.settings.syncAlerts} | ||
onSwitchChange={onSyncAlertsChanged} | ||
/> | ||
|
@@ -134,14 +134,15 @@ const CaseActionBarComponent: React.FC<CaseActionBarProps> = ({ | |
{i18n.CASE_REFRESH} | ||
</EuiButtonEmpty> | ||
</EuiFlexItem> | ||
<EuiFlexItem grow={false} data-test-subj="case-view-actions"> | ||
<Actions | ||
allCasesNavigation={allCasesNavigation} | ||
caseData={caseData} | ||
currentExternalIncident={currentExternalIncident} | ||
disabled={disabled} | ||
/> | ||
</EuiFlexItem> | ||
{userCanCrud && ( | ||
<EuiFlexItem grow={false} data-test-subj="case-view-actions"> | ||
<Actions | ||
allCasesNavigation={allCasesNavigation} | ||
caseData={caseData} | ||
currentExternalIncident={currentExternalIncident} | ||
/> | ||
</EuiFlexItem> | ||
)} | ||
</EuiFlexGroup> | ||
</EuiDescriptionList> | ||
</EuiFlexItem> | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can delete the double spread