From 9ab8292949670c32ccb8c425f4908168ee49add3 Mon Sep 17 00:00:00 2001 From: Ashley Harrison Date: Wed, 6 Dec 2023 16:07:32 +0000 Subject: [PATCH] Orgs: Add skeleton loader (#79141) add skeleton for orgs list --- .../app/features/admin/AdminListOrgsPage.tsx | 41 +++++++------ public/app/features/admin/AdminOrgsTable.tsx | 58 ++++++++++++++++--- 2 files changed, 70 insertions(+), 29 deletions(-) diff --git a/public/app/features/admin/AdminListOrgsPage.tsx b/public/app/features/admin/AdminListOrgsPage.tsx index 486c6a37d1f..6423924c004 100644 --- a/public/app/features/admin/AdminListOrgsPage.tsx +++ b/public/app/features/admin/AdminListOrgsPage.tsx @@ -5,7 +5,7 @@ import { getBackendSrv, isFetchError } from '@grafana/runtime'; import { LinkButton } from '@grafana/ui'; import { Page } from 'app/core/components/Page/Page'; import { contextSrv } from 'app/core/services/context_srv'; -import { AccessControlAction } from 'app/types'; +import { AccessControlAction, Organization } from 'app/types'; import { AdminOrgsTable } from './AdminOrgsTable'; @@ -14,7 +14,7 @@ const deleteOrg = async (orgId: number) => { }; const getOrgs = async () => { - return await getBackendSrv().get('/api/orgs'); + return await getBackendSrv().get('/api/orgs'); }; const getErrorMessage = (error: Error) => { @@ -30,26 +30,25 @@ export default function AdminListOrgsPages() { }, [fetchOrgs]); return ( - + + New org + + } + > - <> -
-
- - New org - -
- {state.error && getErrorMessage(state.error)} - {state.loading && 'Fetching organizations'} - {state.value && ( - { - deleteOrg(orgId).then(() => fetchOrgs()); - }} - /> - )} - + {state.error && getErrorMessage(state.error)} + {state.loading && } + {state.value && ( + { + deleteOrg(orgId).then(() => fetchOrgs()); + }} + /> + )} ); diff --git a/public/app/features/admin/AdminOrgsTable.tsx b/public/app/features/admin/AdminOrgsTable.tsx index 6a042ca6af2..225800056f8 100644 --- a/public/app/features/admin/AdminOrgsTable.tsx +++ b/public/app/features/admin/AdminOrgsTable.tsx @@ -1,6 +1,9 @@ +import { css } from '@emotion/css'; 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 { AccessControlAction, Organization } from 'app/types'; @@ -9,19 +12,23 @@ interface Props { onDelete: (orgId: number) => void; } +const getTableHeader = () => ( + + + ID + Name + + + +); + export function AdminOrgsTable({ orgs, onDelete }: Props) { const canDeleteOrgs = contextSrv.hasPermission(AccessControlAction.OrgsDelete); const [deleteOrg, setDeleteOrg] = useState(); return ( - - - - - - - + {getTableHeader()} {orgs.map((org) => ( @@ -66,3 +73,38 @@ export function AdminOrgsTable({ orgs, onDelete }: Props) {
IDName
); } + +const AdminOrgsTableSkeleton = () => { + const styles = useStyles2(getSkeletonStyles); + return ( + + {getTableHeader()} + + {new Array(3).fill(null).map((_, index) => ( + + + + + + ))} + +
+ + + + + +
+ ); +}; + +AdminOrgsTable.Skeleton = AdminOrgsTableSkeleton; + +const getSkeletonStyles = (theme: GrafanaTheme2) => ({ + deleteButton: css({ + alignItems: 'center', + display: 'flex', + height: 30, + lineHeight: 1, + }), +});