mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Access Control: hiding add annotation button without permissions (#47223)
* Access Control: hiding add annotation button without permissions
This commit is contained in:
parent
bf9e0e8bc8
commit
6a059dcb4d
@ -202,7 +202,13 @@ func (hs *HTTPServer) GetDashboard(c *models.ReqContext) response.Response {
|
||||
func (hs *HTTPServer) getAnnotationPermissionsByScope(c *models.ReqContext, actions *dtos.AnnotationActions, scope string) {
|
||||
var err error
|
||||
|
||||
evaluate := accesscontrol.EvalPermission(accesscontrol.ActionAnnotationsDelete, scope)
|
||||
evaluate := accesscontrol.EvalPermission(accesscontrol.ActionAnnotationsCreate, scope)
|
||||
actions.CanAdd, err = hs.AccessControl.Evaluate(c.Req.Context(), c.SignedInUser, evaluate)
|
||||
if err != nil {
|
||||
hs.log.Warn("Failed to evaluate permission", "err", err, "action", accesscontrol.ActionAnnotationsCreate, "scope", scope)
|
||||
}
|
||||
|
||||
evaluate = accesscontrol.EvalPermission(accesscontrol.ActionAnnotationsDelete, scope)
|
||||
actions.CanDelete, err = hs.AccessControl.Evaluate(c.Req.Context(), c.SignedInUser, evaluate)
|
||||
if err != nil {
|
||||
hs.log.Warn("Failed to evaluate permission", "err", err, "action", accesscontrol.ActionAnnotationsDelete, "scope", scope)
|
||||
|
@ -40,6 +40,7 @@ type AnnotationPermission struct {
|
||||
}
|
||||
|
||||
type AnnotationActions struct {
|
||||
CanAdd bool `json:"canAdd"`
|
||||
CanEdit bool `json:"canEdit"`
|
||||
CanDelete bool `json:"canDelete"`
|
||||
}
|
||||
|
@ -88,7 +88,7 @@ export class PanelChrome extends PureComponent<Props, State> {
|
||||
onAnnotationCreate: this.onAnnotationCreate,
|
||||
onAnnotationUpdate: this.onAnnotationUpdate,
|
||||
onAnnotationDelete: this.onAnnotationDelete,
|
||||
canAddAnnotations: () => Boolean(props.dashboard.meta.canEdit || props.dashboard.meta.canMakeEditable),
|
||||
canAddAnnotations: this.canAddAnnotation,
|
||||
onInstanceStateChange: this.onInstanceStateChange,
|
||||
onToggleLegendSort: this.onToggleLegendSort,
|
||||
canEditAnnotations: this.canEditAnnotation,
|
||||
@ -98,6 +98,17 @@ export class PanelChrome extends PureComponent<Props, State> {
|
||||
};
|
||||
}
|
||||
|
||||
canEditDashboard = () => Boolean(this.props.dashboard.meta.canEdit || this.props.dashboard.meta.canMakeEditable);
|
||||
|
||||
canAddAnnotation = () => {
|
||||
let canAdd = true;
|
||||
|
||||
if (contextSrv.accessControlEnabled()) {
|
||||
canAdd = !!this.props.dashboard.meta.annotationsPermissions?.dashboard.canAdd;
|
||||
}
|
||||
return canAdd && this.canEditDashboard();
|
||||
};
|
||||
|
||||
canEditAnnotation = (dashboardId: number) => {
|
||||
let canEdit = true;
|
||||
|
||||
@ -108,7 +119,7 @@ export class PanelChrome extends PureComponent<Props, State> {
|
||||
canEdit = !!this.props.dashboard.meta.annotationsPermissions?.organization.canEdit;
|
||||
}
|
||||
}
|
||||
return canEdit && Boolean(this.props.dashboard.meta.canEdit || this.props.dashboard.meta.canMakeEditable);
|
||||
return canEdit && this.canEditDashboard();
|
||||
};
|
||||
|
||||
canDeleteAnnotation = (dashboardId: number) => {
|
||||
@ -121,7 +132,7 @@ export class PanelChrome extends PureComponent<Props, State> {
|
||||
canDelete = !!this.props.dashboard.meta.annotationsPermissions?.organization.canDelete;
|
||||
}
|
||||
}
|
||||
return canDelete && Boolean(this.props.dashboard.meta.canEdit || this.props.dashboard.meta.canMakeEditable);
|
||||
return canDelete && this.canEditDashboard();
|
||||
};
|
||||
|
||||
// Due to a mutable panel model we get the sync settings via function that proactively reads from the model
|
||||
|
@ -863,7 +863,7 @@ describe('DashboardModel', () => {
|
||||
dashboard.meta.canEdit = canEdit;
|
||||
dashboard.meta.canMakeEditable = canMakeEditable;
|
||||
|
||||
const result = dashboard.canAddAnnotations();
|
||||
const result = dashboard.canEditDashboard();
|
||||
|
||||
expect(result).toBe(expected);
|
||||
}
|
||||
|
@ -1189,10 +1189,21 @@ export class DashboardModel implements TimeModel {
|
||||
canEdit = !!this.meta.annotationsPermissions?.dashboard.canEdit;
|
||||
}
|
||||
}
|
||||
return this.canAddAnnotations() && canEdit;
|
||||
return this.canEditDashboard() && canEdit;
|
||||
}
|
||||
|
||||
canAddAnnotations() {
|
||||
let canAdd = true;
|
||||
|
||||
// if FGAC is enabled there are additional conditions to check
|
||||
if (contextSrv.accessControlEnabled()) {
|
||||
canAdd = !!this.meta.annotationsPermissions?.dashboard.canAdd;
|
||||
}
|
||||
|
||||
return this.canEditDashboard() && canAdd;
|
||||
}
|
||||
|
||||
canEditDashboard() {
|
||||
return this.meta.canEdit || this.meta.canMakeEditable;
|
||||
}
|
||||
|
||||
|
@ -244,39 +244,49 @@ export const CandlestickPanel: React.FC<CandlestickPanelProps> = ({
|
||||
<AnnotationsPlugin annotations={data.annotations} config={config} timeZone={timeZone} />
|
||||
)}
|
||||
{/* Enables annotations creation*/}
|
||||
<AnnotationEditorPlugin data={alignedDataFrame} timeZone={timeZone} config={config}>
|
||||
{({ startAnnotating }) => {
|
||||
return (
|
||||
<ContextMenuPlugin
|
||||
data={alignedDataFrame}
|
||||
config={config}
|
||||
timeZone={timeZone}
|
||||
replaceVariables={replaceVariables}
|
||||
defaultItems={
|
||||
enableAnnotationCreation
|
||||
? [
|
||||
{
|
||||
items: [
|
||||
{
|
||||
label: 'Add annotation',
|
||||
ariaLabel: 'Add annotation',
|
||||
icon: 'comment-alt',
|
||||
onClick: (e, p) => {
|
||||
if (!p) {
|
||||
return;
|
||||
}
|
||||
startAnnotating({ coords: p.coords });
|
||||
{enableAnnotationCreation ? (
|
||||
<AnnotationEditorPlugin data={alignedDataFrame} timeZone={timeZone} config={config}>
|
||||
{({ startAnnotating }) => {
|
||||
return (
|
||||
<ContextMenuPlugin
|
||||
data={alignedDataFrame}
|
||||
config={config}
|
||||
timeZone={timeZone}
|
||||
replaceVariables={replaceVariables}
|
||||
defaultItems={
|
||||
enableAnnotationCreation
|
||||
? [
|
||||
{
|
||||
items: [
|
||||
{
|
||||
label: 'Add annotation',
|
||||
ariaLabel: 'Add annotation',
|
||||
icon: 'comment-alt',
|
||||
onClick: (e, p) => {
|
||||
if (!p) {
|
||||
return;
|
||||
}
|
||||
startAnnotating({ coords: p.coords });
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
]
|
||||
: []
|
||||
}
|
||||
/>
|
||||
);
|
||||
}}
|
||||
</AnnotationEditorPlugin>
|
||||
],
|
||||
},
|
||||
]
|
||||
: []
|
||||
}
|
||||
/>
|
||||
);
|
||||
}}
|
||||
</AnnotationEditorPlugin>
|
||||
) : (
|
||||
<ContextMenuPlugin
|
||||
data={alignedDataFrame}
|
||||
config={config}
|
||||
timeZone={timeZone}
|
||||
replaceVariables={replaceVariables}
|
||||
defaultItems={[]}
|
||||
/>
|
||||
)}
|
||||
{data.annotations && (
|
||||
<ExemplarsPlugin
|
||||
config={config}
|
||||
|
@ -39,6 +39,7 @@ export interface DashboardMeta {
|
||||
}
|
||||
|
||||
export interface AnnotationActions {
|
||||
canAdd: boolean;
|
||||
canEdit: boolean;
|
||||
canDelete: boolean;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user