UI updates to GCP-projects plugin
Adds the following to the project list page: * pagination * filtering * sorting * rows per page * show/hide columns Makes breadcrumb a link back to project list for the project details and new project views. In project list page, updates New project button to use RouterLink instead of href to avoid login prompt. In project details view, links to project details and logs now work, clicking on these will open the project or logs in GCP in new tab. Signed-off-by: Jeremy Guarini <jguarini@paloaltonetworks.com>
This commit is contained in:
@@ -28,6 +28,10 @@ import {
|
||||
StructuredMetadataTable,
|
||||
SupportButton,
|
||||
} from '@backstage/core-components';
|
||||
import { Link as RouterLink } from 'react-router-dom';
|
||||
|
||||
import { useRouteRef } from '@backstage/core-plugin-api';
|
||||
import { rootRouteRef } from '../../routes';
|
||||
|
||||
export const Project = () => {
|
||||
const [projectName, setProjectName] = useState('');
|
||||
@@ -79,18 +83,20 @@ export const Project = () => {
|
||||
</SimpleStepperStep>
|
||||
</SimpleStepper>
|
||||
<Button
|
||||
component={RouterLink}
|
||||
variant="text"
|
||||
data-testid="cancel-button"
|
||||
color="primary"
|
||||
href="/gcp-projects"
|
||||
to="/gcp-projects"
|
||||
>
|
||||
Cancel
|
||||
</Button>
|
||||
<Button
|
||||
component={RouterLink}
|
||||
variant="contained"
|
||||
color="primary"
|
||||
disabled={disabled}
|
||||
href={`newProject?projectName=${encodeURIComponent(
|
||||
to={`newProject?projectName=${encodeURIComponent(
|
||||
projectName,
|
||||
)},projectId=${encodeURIComponent(projectId)}`}
|
||||
>
|
||||
@@ -110,18 +116,21 @@ const labels = (
|
||||
</>
|
||||
);
|
||||
|
||||
export const NewProjectPage = () => (
|
||||
<Page themeId="service">
|
||||
<Header title="New GCP Project" type="tool">
|
||||
{labels}
|
||||
</Header>
|
||||
<Content>
|
||||
<ContentHeader title="">
|
||||
<SupportButton>
|
||||
This plugin allows you to view and interact with your gcp projects.
|
||||
</SupportButton>
|
||||
</ContentHeader>
|
||||
<Project />
|
||||
</Content>
|
||||
</Page>
|
||||
);
|
||||
export const NewProjectPage = () => {
|
||||
const docsRootLink = useRouteRef(rootRouteRef)();
|
||||
return (
|
||||
<Page themeId="tool">
|
||||
<Header title="New GCP Project" type="GCP" typeLink={docsRootLink}>
|
||||
{labels}
|
||||
</Header>
|
||||
<Content>
|
||||
<ContentHeader title="">
|
||||
<SupportButton>
|
||||
This plugin allows you to view and interact with your gcp projects.
|
||||
</SupportButton>
|
||||
</ContentHeader>
|
||||
<Project />
|
||||
</Content>
|
||||
</Page>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -40,7 +40,8 @@ import {
|
||||
WarningPanel,
|
||||
} from '@backstage/core-components';
|
||||
|
||||
import { useApi } from '@backstage/core-plugin-api';
|
||||
import { useApi, useRouteRef } from '@backstage/core-plugin-api';
|
||||
import { rootRouteRef } from '../../routes';
|
||||
|
||||
const useStyles = makeStyles<Theme>(theme => ({
|
||||
root: {
|
||||
@@ -81,6 +82,8 @@ const DetailsPage = () => {
|
||||
);
|
||||
}
|
||||
|
||||
const cloud_home_url = 'https://console.cloud.google.com';
|
||||
|
||||
return (
|
||||
<Table component={Paper} className={classes.table}>
|
||||
<Table>
|
||||
@@ -127,12 +130,24 @@ const DetailsPage = () => {
|
||||
>
|
||||
{details?.name && (
|
||||
<Button>
|
||||
<a href={details.name}>GCP</a>
|
||||
<a
|
||||
href={`${cloud_home_url}/home/dashboard?project=${details.name}&supportedpurview=project`}
|
||||
target="_blank"
|
||||
rel="noreferrer noopener"
|
||||
>
|
||||
GCP
|
||||
</a>
|
||||
</Button>
|
||||
)}
|
||||
{details?.name && (
|
||||
<Button>
|
||||
<a href={details.name}>Logs</a>
|
||||
<a
|
||||
href={`${cloud_home_url}/logs/query?project=${details.name}&supportedpurview=project`}
|
||||
target="_blank"
|
||||
rel="noreferrer noopener"
|
||||
>
|
||||
Logs
|
||||
</a>
|
||||
</Button>
|
||||
)}
|
||||
</ButtonGroup>
|
||||
@@ -151,16 +166,20 @@ const labels = (
|
||||
</>
|
||||
);
|
||||
|
||||
export const ProjectDetailsPage = () => (
|
||||
<Page themeId="service">
|
||||
<Header title="GCP Project Details" type="other">
|
||||
{labels}
|
||||
</Header>
|
||||
<Content>
|
||||
<ContentHeader title="">
|
||||
<SupportButton>Support Button</SupportButton>
|
||||
</ContentHeader>
|
||||
<DetailsPage />
|
||||
</Content>
|
||||
</Page>
|
||||
);
|
||||
export const ProjectDetailsPage = () => {
|
||||
const docsRootLink = useRouteRef(rootRouteRef)();
|
||||
|
||||
return (
|
||||
<Page themeId="service">
|
||||
<Header title="GCP Project Details" type="GCP" typeLink={docsRootLink}>
|
||||
{labels}
|
||||
</Header>
|
||||
<Content>
|
||||
<ContentHeader title="">
|
||||
<SupportButton>Support Button</SupportButton>
|
||||
</ContentHeader>
|
||||
<DetailsPage />
|
||||
</Content>
|
||||
</Page>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -15,18 +15,8 @@
|
||||
*/
|
||||
|
||||
// NEEDS WORK
|
||||
import {
|
||||
Button,
|
||||
LinearProgress,
|
||||
Paper,
|
||||
Table,
|
||||
TableBody,
|
||||
TableCell,
|
||||
TableHead,
|
||||
TableRow,
|
||||
Tooltip,
|
||||
Typography,
|
||||
} from '@material-ui/core';
|
||||
import { Button, LinearProgress, Tooltip, Typography } from '@material-ui/core';
|
||||
import { DataGrid, GridColDef, GridCellParams } from '@material-ui/data-grid';
|
||||
import React from 'react';
|
||||
import { useAsync } from 'react-use';
|
||||
import { gcpApiRef, Project } from '../../api';
|
||||
@@ -44,6 +34,8 @@ import {
|
||||
|
||||
import { useApi } from '@backstage/core-plugin-api';
|
||||
|
||||
import { Link as RouterLink } from 'react-router-dom';
|
||||
|
||||
const LongText = ({ text, max }: { text: string; max: number }) => {
|
||||
if (text.length < max) {
|
||||
return <span>{text}</span>;
|
||||
@@ -67,6 +59,18 @@ const PageContents = () => {
|
||||
|
||||
const { loading, error, value } = useAsync(() => api.listProjects());
|
||||
|
||||
const [page, setPage] = React.useState(0);
|
||||
const [rowsPerPage, setRowsPerPage] = React.useState(10);
|
||||
|
||||
const handleChangePage = (newPage: number) => {
|
||||
setPage(newPage);
|
||||
};
|
||||
|
||||
const handleChangeRowsPerPage = (pageSize: number) => {
|
||||
setRowsPerPage(pageSize);
|
||||
setPage(0);
|
||||
};
|
||||
|
||||
if (loading) {
|
||||
return <LinearProgress />;
|
||||
} else if (error) {
|
||||
@@ -77,60 +81,80 @@ const PageContents = () => {
|
||||
);
|
||||
}
|
||||
|
||||
function renderLink(params: GridCellParams) {
|
||||
return (
|
||||
<Link
|
||||
to={`project?projectId=${encodeURIComponent(params.value!.toString())}`}
|
||||
>
|
||||
<Typography color="primary">
|
||||
<LongText text={params.value!.toString()} max={60} />
|
||||
</Typography>
|
||||
</Link>
|
||||
);
|
||||
}
|
||||
|
||||
const columns: GridColDef[] = [
|
||||
{
|
||||
align: 'left',
|
||||
field: 'name',
|
||||
flex: 1,
|
||||
headerAlign: 'left',
|
||||
headerName: 'Name',
|
||||
},
|
||||
{
|
||||
align: 'left',
|
||||
field: 'projectNumber',
|
||||
flex: 0.6,
|
||||
headerAlign: 'left',
|
||||
headerName: 'Project Number',
|
||||
},
|
||||
{
|
||||
align: 'left',
|
||||
field: 'projectID',
|
||||
flex: 1,
|
||||
headerAlign: 'left',
|
||||
headerName: 'Project ID',
|
||||
renderCell: renderLink,
|
||||
},
|
||||
{
|
||||
align: 'left',
|
||||
field: 'state',
|
||||
flex: 0.6,
|
||||
headerAlign: 'left',
|
||||
headerName: 'State',
|
||||
},
|
||||
{
|
||||
align: 'left',
|
||||
field: 'creationTime',
|
||||
flex: 0.7,
|
||||
headerAlign: 'left',
|
||||
headerName: 'Creation Time',
|
||||
},
|
||||
];
|
||||
|
||||
const rows =
|
||||
value?.map((project: Project) => ({
|
||||
id: project.projectId,
|
||||
name: project.name,
|
||||
projectNumber: project?.projectNumber || 'Error',
|
||||
projectID: project.projectId,
|
||||
state: project?.lifecycleState || 'Error',
|
||||
creationTime: project?.createTime || 'Error',
|
||||
})) || [];
|
||||
|
||||
return (
|
||||
<Table component={Paper}>
|
||||
<Table aria-label="GCP Projects table">
|
||||
<TableHead>
|
||||
<TableRow>
|
||||
<TableCell>Name</TableCell>
|
||||
<TableCell>Project Number</TableCell>
|
||||
<TableCell>Project ID</TableCell>
|
||||
<TableCell>State</TableCell>
|
||||
<TableCell>Creation Time</TableCell>
|
||||
</TableRow>
|
||||
</TableHead>
|
||||
<TableBody>
|
||||
{value?.map((project: Project) => (
|
||||
<TableRow key={project.projectId}>
|
||||
<TableCell>
|
||||
<Typography>
|
||||
<LongText text={project.name} max={30} />
|
||||
</Typography>
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<Typography>
|
||||
<LongText text={project?.projectNumber || 'Error'} max={30} />
|
||||
</Typography>
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<Link
|
||||
to={`project?projectId=${encodeURIComponent(
|
||||
project.projectId,
|
||||
)}`}
|
||||
>
|
||||
<Typography color="primary">
|
||||
<LongText text={project.projectId} max={60} />
|
||||
</Typography>
|
||||
</Link>
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<Typography>
|
||||
<LongText
|
||||
text={project?.lifecycleState || 'Error'}
|
||||
max={30}
|
||||
/>
|
||||
</Typography>
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<Typography>
|
||||
<LongText text={project?.createTime || 'Error'} max={30} />
|
||||
</Typography>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
))}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</Table>
|
||||
<div style={{ height: '95%', width: '100%' }}>
|
||||
<DataGrid
|
||||
rows={rows}
|
||||
columns={columns}
|
||||
page={page}
|
||||
pageSize={rowsPerPage}
|
||||
rowsPerPageOptions={[10, 25, 50, 100]}
|
||||
onPageChange={handleChangePage}
|
||||
onPageSizeChange={handleChangeRowsPerPage}
|
||||
disableSelectionOnClick
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -141,7 +165,12 @@ export const ProjectListPage = () => (
|
||||
</Header>
|
||||
<Content>
|
||||
<ContentHeader title="">
|
||||
<Button variant="contained" color="primary" href="/gcp-projects/new">
|
||||
<Button
|
||||
component={RouterLink}
|
||||
variant="contained"
|
||||
color="primary"
|
||||
to="new"
|
||||
>
|
||||
New Project
|
||||
</Button>
|
||||
<SupportButton>All your software catalog entities</SupportButton>
|
||||
|
||||
Reference in New Issue
Block a user