mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
parent
74cb1423c1
commit
9ab8292949
@ -5,7 +5,7 @@ import { getBackendSrv, isFetchError } from '@grafana/runtime';
|
|||||||
import { LinkButton } from '@grafana/ui';
|
import { LinkButton } from '@grafana/ui';
|
||||||
import { Page } from 'app/core/components/Page/Page';
|
import { Page } from 'app/core/components/Page/Page';
|
||||||
import { contextSrv } from 'app/core/services/context_srv';
|
import { contextSrv } from 'app/core/services/context_srv';
|
||||||
import { AccessControlAction } from 'app/types';
|
import { AccessControlAction, Organization } from 'app/types';
|
||||||
|
|
||||||
import { AdminOrgsTable } from './AdminOrgsTable';
|
import { AdminOrgsTable } from './AdminOrgsTable';
|
||||||
|
|
||||||
@ -14,7 +14,7 @@ const deleteOrg = async (orgId: number) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const getOrgs = async () => {
|
const getOrgs = async () => {
|
||||||
return await getBackendSrv().get('/api/orgs');
|
return await getBackendSrv().get<Organization[]>('/api/orgs');
|
||||||
};
|
};
|
||||||
|
|
||||||
const getErrorMessage = (error: Error) => {
|
const getErrorMessage = (error: Error) => {
|
||||||
@ -30,26 +30,25 @@ export default function AdminListOrgsPages() {
|
|||||||
}, [fetchOrgs]);
|
}, [fetchOrgs]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Page navId="global-orgs">
|
<Page
|
||||||
|
navId="global-orgs"
|
||||||
|
actions={
|
||||||
|
<LinkButton icon="plus" href="org/new" disabled={!canCreateOrg}>
|
||||||
|
New org
|
||||||
|
</LinkButton>
|
||||||
|
}
|
||||||
|
>
|
||||||
<Page.Contents>
|
<Page.Contents>
|
||||||
<>
|
{state.error && getErrorMessage(state.error)}
|
||||||
<div className="page-action-bar">
|
{state.loading && <AdminOrgsTable.Skeleton />}
|
||||||
<div className="page-action-bar__spacer" />
|
{state.value && (
|
||||||
<LinkButton icon="plus" href="org/new" disabled={!canCreateOrg}>
|
<AdminOrgsTable
|
||||||
New org
|
orgs={state.value}
|
||||||
</LinkButton>
|
onDelete={(orgId) => {
|
||||||
</div>
|
deleteOrg(orgId).then(() => fetchOrgs());
|
||||||
{state.error && getErrorMessage(state.error)}
|
}}
|
||||||
{state.loading && 'Fetching organizations'}
|
/>
|
||||||
{state.value && (
|
)}
|
||||||
<AdminOrgsTable
|
|
||||||
orgs={state.value}
|
|
||||||
onDelete={(orgId) => {
|
|
||||||
deleteOrg(orgId).then(() => fetchOrgs());
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</>
|
|
||||||
</Page.Contents>
|
</Page.Contents>
|
||||||
</Page>
|
</Page>
|
||||||
);
|
);
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
|
import { css } from '@emotion/css';
|
||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
|
import Skeleton from 'react-loading-skeleton';
|
||||||
|
|
||||||
import { Button, ConfirmModal } from '@grafana/ui';
|
import { GrafanaTheme2 } from '@grafana/data';
|
||||||
|
import { Button, ConfirmModal, useStyles2 } from '@grafana/ui';
|
||||||
import { contextSrv } from 'app/core/core';
|
import { contextSrv } from 'app/core/core';
|
||||||
import { AccessControlAction, Organization } from 'app/types';
|
import { AccessControlAction, Organization } from 'app/types';
|
||||||
|
|
||||||
@ -9,19 +12,23 @@ interface Props {
|
|||||||
onDelete: (orgId: number) => void;
|
onDelete: (orgId: number) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const getTableHeader = () => (
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>ID</th>
|
||||||
|
<th>Name</th>
|
||||||
|
<th style={{ width: '1%' }}></th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
);
|
||||||
|
|
||||||
export function AdminOrgsTable({ orgs, onDelete }: Props) {
|
export function AdminOrgsTable({ orgs, onDelete }: Props) {
|
||||||
const canDeleteOrgs = contextSrv.hasPermission(AccessControlAction.OrgsDelete);
|
const canDeleteOrgs = contextSrv.hasPermission(AccessControlAction.OrgsDelete);
|
||||||
|
|
||||||
const [deleteOrg, setDeleteOrg] = useState<Organization>();
|
const [deleteOrg, setDeleteOrg] = useState<Organization>();
|
||||||
return (
|
return (
|
||||||
<table className="filter-table form-inline filter-table--hover">
|
<table className="filter-table form-inline filter-table--hover">
|
||||||
<thead>
|
{getTableHeader()}
|
||||||
<tr>
|
|
||||||
<th>ID</th>
|
|
||||||
<th>Name</th>
|
|
||||||
<th style={{ width: '1%' }}></th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
<tbody>
|
||||||
{orgs.map((org) => (
|
{orgs.map((org) => (
|
||||||
<tr key={`${org.id}-${org.name}`}>
|
<tr key={`${org.id}-${org.name}`}>
|
||||||
@ -66,3 +73,38 @@ export function AdminOrgsTable({ orgs, onDelete }: Props) {
|
|||||||
</table>
|
</table>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const AdminOrgsTableSkeleton = () => {
|
||||||
|
const styles = useStyles2(getSkeletonStyles);
|
||||||
|
return (
|
||||||
|
<table className="filter-table">
|
||||||
|
{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>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
AdminOrgsTable.Skeleton = AdminOrgsTableSkeleton;
|
||||||
|
|
||||||
|
const getSkeletonStyles = (theme: GrafanaTheme2) => ({
|
||||||
|
deleteButton: css({
|
||||||
|
alignItems: 'center',
|
||||||
|
display: 'flex',
|
||||||
|
height: 30,
|
||||||
|
lineHeight: 1,
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
Loading…
Reference in New Issue
Block a user