Files
Jack Westbrook aa70a38391 Dashboards: hide playlist edit functionality from viewers and snapshots link from unauthenticated users (#28992)
* feat: hide snapshots menu item from viewers

* feat(playlists): prevent viewers from creating/editing playlists

* feat: prevent viewers seeing playlist nav link if no playlists

* refactor(playlist): rename isViewer property to canEditPlaylists

* revert(playlists): put back note if viewer and no playlists

* refactor(snapshots): consider admin/editor permission in folders/dashboards for displaying menu item

* feat(snapshots): only show snapshot nav item if user is signed in

* fix(snapshots): revert snapshots to previous state if delete snapshot api error
2020-12-02 15:51:22 +01:00

101 lines
3.1 KiB
TypeScript

import React, { FC, useState, useCallback, useEffect } from 'react';
import { ConfirmModal, Button, LinkButton } from '@grafana/ui';
import { getBackendSrv } from '@grafana/runtime';
import { Snapshot } from '../types';
interface Props {
url: string;
}
export const SnapshotListTable: FC<Props> = ({ url }) => {
const [snapshots, setSnapshots] = useState<Snapshot[]>([]);
const [removeSnapshot, setRemoveSnapshot] = useState<Snapshot | undefined>();
const getSnapshots = useCallback(async () => {
await getBackendSrv()
.get('/api/dashboard/snapshots')
.then((result: Snapshot[]) => {
const absUrl = window.location.href;
const baseUrl = absUrl.replace(url, '');
const snapshots = result.map(snapshot => ({
...snapshot,
url: snapshot.externalUrl || `${baseUrl}/dashboard/snapshot/${snapshot.key}`,
}));
setSnapshots(snapshots);
});
}, []);
const doRemoveSnapshot = useCallback(
async (snapshot: Snapshot) => {
const filteredSnapshots = snapshots.filter(ss => ss.key !== snapshot.key);
setSnapshots(filteredSnapshots);
await getBackendSrv()
.delete(`/api/snapshots/${snapshot.key}`)
.catch(() => {
setSnapshots(snapshots);
});
},
[snapshots]
);
useEffect(() => {
getSnapshots();
}, []);
return (
<div className="page-container page-body">
<table className="filter-table">
<thead>
<tr>
<th>
<strong>Name</strong>
</th>
<th>
<strong>Snapshot url</strong>
</th>
<th style={{ width: '70px' }}></th>
<th style={{ width: '30px' }}></th>
<th style={{ width: '25px' }}></th>
</tr>
</thead>
<tbody>
{snapshots.map(snapshot => {
return (
<tr key={snapshot.key}>
<td>
<a href={snapshot.url}>{snapshot.name}</a>
</td>
<td>
<a href={snapshot.url}>{snapshot.url}</a>
</td>
<td>{snapshot.external && <span className="query-keyword">External</span>}</td>
<td className="text-center">
<LinkButton href={snapshot.url} variant="secondary" size="sm" icon="eye">
View
</LinkButton>
</td>
<td className="text-right">
<Button variant="destructive" size="sm" icon="times" onClick={() => setRemoveSnapshot(snapshot)} />
</td>
</tr>
);
})}
</tbody>
</table>
<ConfirmModal
isOpen={!!removeSnapshot}
icon="trash-alt"
title="Delete"
body={`Are you sure you want to delete '${removeSnapshot?.name}'?`}
confirmText="Delete"
onDismiss={() => setRemoveSnapshot(undefined)}
onConfirm={() => {
doRemoveSnapshot(removeSnapshot!);
setRemoveSnapshot(undefined);
}}
/>
</div>
);
};