grafana/public/app/features/admin/AdminOrgsTable.tsx
Ashley Harrison ffda25f4a3
Skeleton: Abstract out attach/animation logic (#79309)
* apply styles globally to skeleton

* use abstraction everywhere

* just use withSkeleton

* add comment

* update docs

* use it in News as well

* rename withSkeleton to attachSkeleton

* move to @grafana/ui/src/unstable

* rename skeletonProps to rootProps
2023-12-12 11:05:36 +00:00

112 lines
3.1 KiB
TypeScript

import { css } from '@emotion/css';
import React, { useState } from 'react';
import Skeleton from 'react-loading-skeleton';
import { GrafanaTheme2 } from '@grafana/data';
import { Button, ConfirmModal, useStyles2 } from '@grafana/ui';
import { SkeletonComponent, attachSkeleton } from '@grafana/ui/src/unstable';
import { contextSrv } from 'app/core/core';
import { AccessControlAction, Organization } from 'app/types';
interface Props {
orgs: Organization[];
onDelete: (orgId: number) => void;
}
const getTableHeader = () => (
<thead>
<tr>
<th>ID</th>
<th>Name</th>
<th style={{ width: '1%' }}></th>
</tr>
</thead>
);
function AdminOrgsTableComponent({ orgs, onDelete }: Props) {
const canDeleteOrgs = contextSrv.hasPermission(AccessControlAction.OrgsDelete);
const [deleteOrg, setDeleteOrg] = useState<Organization>();
return (
<table className="filter-table form-inline filter-table--hover">
{getTableHeader()}
<tbody>
{orgs.map((org) => (
<tr key={`${org.id}-${org.name}`}>
<td className="link-td">
<a href={`admin/orgs/edit/${org.id}`}>{org.id}</a>
</td>
<td className="link-td">
<a href={`admin/orgs/edit/${org.id}`}>{org.name}</a>
</td>
<td className="text-right">
<Button
variant="destructive"
size="sm"
icon="times"
onClick={() => setDeleteOrg(org)}
aria-label="Delete org"
disabled={!canDeleteOrgs}
/>
</td>
</tr>
))}
</tbody>
{deleteOrg && (
<ConfirmModal
isOpen
icon="trash-alt"
title="Delete"
body={
<div>
Are you sure you want to delete &apos;{deleteOrg.name}&apos;?
<br /> <small>All dashboards for this organization will be removed!</small>
</div>
}
confirmText="Delete"
onDismiss={() => setDeleteOrg(undefined)}
onConfirm={() => {
onDelete(deleteOrg.id);
setDeleteOrg(undefined);
}}
/>
)}
</table>
);
}
const AdminOrgsTableSkeleton: SkeletonComponent = ({ rootProps }) => {
const styles = useStyles2(getSkeletonStyles);
return (
<table className="filter-table" {...rootProps}>
{getTableHeader()}
<tbody>
{new Array(3).fill(null).map((_, index) => (
<tr key={index}>
<td>
<Skeleton width={16} />
</td>
<td>
<Skeleton width={240} />
</td>
<td>
<Skeleton containerClassName={styles.deleteButton} width={22} height={24} />
</td>
</tr>
))}
</tbody>
</table>
);
};
export const AdminOrgsTable = attachSkeleton(AdminOrgsTableComponent, AdminOrgsTableSkeleton);
const getSkeletonStyles = (theme: GrafanaTheme2) => ({
deleteButton: css({
alignItems: 'center',
display: 'flex',
height: 30,
lineHeight: 1,
}),
});