Merge pull request #1612 from ebarriosjr/ebarriosjr/Creating-gcp-projects-plugin
Ebarriosjr/creating gcp projects plugin
This commit is contained in:
@@ -0,0 +1,3 @@
|
||||
module.exports = {
|
||||
extends: [require.resolve('@backstage/cli/config/eslint')],
|
||||
};
|
||||
@@ -0,0 +1,13 @@
|
||||
# gcp-projects
|
||||
|
||||
Welcome to the gcp-projects plugin!
|
||||
|
||||
_This plugin was created through the Backstage CLI_
|
||||
|
||||
## Getting started
|
||||
|
||||
Your plugin has been added to the example app in this repository, meaning you'll be able to access it by running `yarn start` in the root directory, and then navigating to [/gcp-projects](http://localhost:3000/gcp-projects).
|
||||
|
||||
You can also serve the plugin in isolation by running `yarn start` in the plugin directory.
|
||||
This method of serving the plugin provides quicker iteration speed and a faster startup and hot reloads.
|
||||
It is only meant for local development, and the setup for it can be found inside the [/dev](./dev) directory.
|
||||
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* Copyright 2020 Spotify AB
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { createDevApp } from '@backstage/dev-utils';
|
||||
import { plugin } from '../src/plugin';
|
||||
|
||||
createDevApp()
|
||||
.registerPlugin(plugin)
|
||||
.render();
|
||||
@@ -0,0 +1,47 @@
|
||||
{
|
||||
"name": "@backstage/plugin-gcp-projects",
|
||||
"version": "0.1.1-alpha.21",
|
||||
"main": "src/index.ts",
|
||||
"types": "src/index.ts",
|
||||
"license": "Apache-2.0",
|
||||
"private": true,
|
||||
"publishConfig": {
|
||||
"access": "public",
|
||||
"main": "dist/index.esm.js",
|
||||
"types": "dist/index.d.ts"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "backstage-cli plugin:build",
|
||||
"start": "backstage-cli plugin:serve",
|
||||
"lint": "backstage-cli lint",
|
||||
"test": "backstage-cli test",
|
||||
"diff": "backstage-cli plugin:diff",
|
||||
"prepack": "backstage-cli prepack",
|
||||
"postpack": "backstage-cli postpack",
|
||||
"clean": "backstage-cli clean"
|
||||
},
|
||||
"dependencies": {
|
||||
"@backstage/core": "^0.1.1-alpha.21",
|
||||
"@backstage/theme": "^0.1.1-alpha.21",
|
||||
"@material-ui/core": "^4.9.1",
|
||||
"@material-ui/icons": "^4.9.1",
|
||||
"@material-ui/lab": "4.0.0-alpha.45",
|
||||
"react": "^16.13.1",
|
||||
"react-dom": "^16.13.1",
|
||||
"react-router-dom": "^5.2.0",
|
||||
"react-use": "^15.3.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/cli": "^0.1.1-alpha.21",
|
||||
"@backstage/dev-utils": "^0.1.1-alpha.21",
|
||||
"@testing-library/jest-dom": "^5.10.1",
|
||||
"@testing-library/react": "^10.4.1",
|
||||
"@testing-library/user-event": "^12.0.7",
|
||||
"@types/jest": "^26.0.7",
|
||||
"@types/node": "^12.0.0",
|
||||
"jest-fetch-mock": "^3.0.3"
|
||||
},
|
||||
"files": [
|
||||
"dist"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright 2020 Spotify AB
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { createApiRef } from '@backstage/core';
|
||||
import { Project, Operation } from './types';
|
||||
|
||||
export const GCPApiRef = createApiRef<GCPApi>({
|
||||
id: 'plugin.gcpprojects.service',
|
||||
description: 'Used by the GCP Projects plugin to make requests',
|
||||
});
|
||||
|
||||
export type GCPApi = {
|
||||
listProjects: ({ token }: { token: string }) => Promise<Project[]>;
|
||||
getProject: (projectId: string, token: Promise<string>) => Promise<Project>;
|
||||
createProject: (
|
||||
projectName: string,
|
||||
projectId: string,
|
||||
owner: string,
|
||||
token: string,
|
||||
) => Promise<Operation>;
|
||||
};
|
||||
@@ -0,0 +1,124 @@
|
||||
/*
|
||||
* Copyright 2020 Spotify AB
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { GCPApi } from './GCPApi';
|
||||
import { Project, Operation, Status } from './types';
|
||||
|
||||
const BaseURL =
|
||||
'https://content-cloudresourcemanager.googleapis.com/v1/projects';
|
||||
|
||||
export class GCPClient implements GCPApi {
|
||||
async listProjects({ token }: { token: string }): Promise<Project[]> {
|
||||
const response = await fetch(BaseURL, {
|
||||
headers: new Headers({
|
||||
Accept: '*/*',
|
||||
Authorization: `Bearer ${token}`,
|
||||
}),
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
return [
|
||||
{
|
||||
name: 'Error',
|
||||
projectNumber: 'Response status is not OK',
|
||||
projectId: 'Error',
|
||||
lifecycleState: 'error',
|
||||
createTime: 'Error',
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
return data.projects;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
async getProject(
|
||||
projectId: string,
|
||||
token: Promise<string>,
|
||||
): Promise<Project> {
|
||||
const url = `${BaseURL}/${projectId}`;
|
||||
const response = await fetch(url, {
|
||||
headers: new Headers({
|
||||
Authorization: `Bearer ${await token}`,
|
||||
}),
|
||||
});
|
||||
|
||||
const dataBlank: Project = {
|
||||
name: 'Error',
|
||||
projectNumber: `Response status is ${response.status}`,
|
||||
projectId: 'Error',
|
||||
lifecycleState: 'error',
|
||||
createTime: 'Error',
|
||||
};
|
||||
|
||||
if (!response.ok) {
|
||||
return dataBlank;
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
const newData: Project = data;
|
||||
|
||||
return newData;
|
||||
}
|
||||
|
||||
async createProject(
|
||||
projectName: string,
|
||||
projectId: string,
|
||||
token: string,
|
||||
): Promise<Operation> {
|
||||
const status: Status = {
|
||||
code: 0,
|
||||
message: '',
|
||||
details: [],
|
||||
};
|
||||
|
||||
const op: Operation = {
|
||||
name: '',
|
||||
metadata: '',
|
||||
done: true,
|
||||
error: status,
|
||||
response: '',
|
||||
};
|
||||
|
||||
const newProject: Project = {
|
||||
name: projectName,
|
||||
projectId: projectId,
|
||||
};
|
||||
|
||||
const body = JSON.stringify(newProject);
|
||||
|
||||
const response = await fetch(BaseURL, {
|
||||
headers: new Headers({
|
||||
Accept: '*/*',
|
||||
Authorization: `Bearer ${token}`,
|
||||
}),
|
||||
body: body,
|
||||
method: 'POST',
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
status.code = response.status;
|
||||
return op;
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
return data;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
* Copyright 2020 Spotify AB
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
export * from './GCPApi';
|
||||
export * from './GCPClient';
|
||||
export * from './types';
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright 2020 Spotify AB
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
export type Project = {
|
||||
name: string;
|
||||
projectNumber?: string;
|
||||
projectId: string;
|
||||
lifecycleState?: string;
|
||||
createTime?: string;
|
||||
};
|
||||
|
||||
export type ProjectDetails = {
|
||||
details: string;
|
||||
};
|
||||
|
||||
export type Operation = {
|
||||
name: string;
|
||||
metadata: string;
|
||||
done: boolean;
|
||||
error: Status;
|
||||
response: string;
|
||||
};
|
||||
|
||||
export type Status = {
|
||||
code: number;
|
||||
message: string;
|
||||
details: string[];
|
||||
};
|
||||
@@ -0,0 +1,131 @@
|
||||
/*
|
||||
* Copyright 2020 Spotify AB
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import React, { FC, useState } from 'react';
|
||||
import { Grid, Button, TextField } from '@material-ui/core';
|
||||
|
||||
import {
|
||||
InfoCard,
|
||||
Content,
|
||||
ContentHeader,
|
||||
SimpleStepper,
|
||||
SimpleStepperStep,
|
||||
StructuredMetadataTable,
|
||||
HeaderLabel,
|
||||
Page,
|
||||
Header,
|
||||
pageTheme,
|
||||
SupportButton,
|
||||
} from '@backstage/core';
|
||||
|
||||
export const Project: FC<{}> = () => {
|
||||
const [projectName, setProjectName] = useState('');
|
||||
const [projectId, setProjectId] = useState('');
|
||||
const [disabled, setDisabled] = useState(true);
|
||||
|
||||
const metadata = {
|
||||
ProjectName: projectName,
|
||||
ProjectId: projectId,
|
||||
};
|
||||
|
||||
return (
|
||||
<Content>
|
||||
<Grid container spacing={3}>
|
||||
<Grid item xs={12} md={6}>
|
||||
<InfoCard title="Create new GCP Project">
|
||||
<SimpleStepper>
|
||||
<SimpleStepperStep title="Project Name">
|
||||
<TextField
|
||||
variant="outlined"
|
||||
name="projectName"
|
||||
label="Project Name"
|
||||
helperText="The name of the new project."
|
||||
inputProps={{ 'aria-label': 'Project Name' }}
|
||||
onChange={e => setProjectName(e.target.value)}
|
||||
value={projectName}
|
||||
fullWidth
|
||||
/>
|
||||
</SimpleStepperStep>
|
||||
<SimpleStepperStep title="Project ID">
|
||||
<TextField
|
||||
variant="outlined"
|
||||
name="projectId"
|
||||
label="projectId"
|
||||
onChange={e => setProjectId(e.target.value)}
|
||||
value={projectId}
|
||||
fullWidth
|
||||
/>
|
||||
</SimpleStepperStep>
|
||||
|
||||
<SimpleStepperStep
|
||||
title="Review"
|
||||
actions={{
|
||||
nextText: 'Confirm',
|
||||
onNext: () => setDisabled(false),
|
||||
}}
|
||||
>
|
||||
<StructuredMetadataTable metadata={metadata} />
|
||||
</SimpleStepperStep>
|
||||
</SimpleStepper>
|
||||
<Button
|
||||
variant="text"
|
||||
data-testid="cancel-button"
|
||||
color="primary"
|
||||
href="/gcp-projects"
|
||||
>
|
||||
Cancel
|
||||
</Button>
|
||||
<Button
|
||||
variant="contained"
|
||||
color="primary"
|
||||
disabled={disabled}
|
||||
href={`newProject?projectName=${encodeURIComponent(
|
||||
projectName,
|
||||
)},projectId=${encodeURIComponent(projectId)}`}
|
||||
>
|
||||
Create
|
||||
</Button>
|
||||
</InfoCard>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Content>
|
||||
);
|
||||
};
|
||||
|
||||
const labels = (
|
||||
<>
|
||||
<HeaderLabel label="Owner" value="Spotify" />
|
||||
<HeaderLabel label="Lifecycle" value="Production" />
|
||||
</>
|
||||
);
|
||||
|
||||
export const NewProjectPage = () => {
|
||||
return (
|
||||
<Page theme={pageTheme.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>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,17 @@
|
||||
/*
|
||||
* Copyright 2020 Spotify AB
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
export { NewProjectPage } from './NewProjectPage';
|
||||
@@ -0,0 +1,171 @@
|
||||
/*
|
||||
* Copyright 2020 Spotify AB
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import {
|
||||
Button,
|
||||
ButtonGroup,
|
||||
LinearProgress,
|
||||
makeStyles,
|
||||
Paper,
|
||||
Table,
|
||||
TableBody,
|
||||
TableCell,
|
||||
TableRow,
|
||||
Theme,
|
||||
Typography,
|
||||
} from '@material-ui/core';
|
||||
import {
|
||||
useApi,
|
||||
googleAuthApiRef,
|
||||
HeaderLabel,
|
||||
Page,
|
||||
Header,
|
||||
pageTheme,
|
||||
SupportButton,
|
||||
Content,
|
||||
ContentHeader,
|
||||
} from '@backstage/core';
|
||||
import React from 'react';
|
||||
import { useAsync } from 'react-use';
|
||||
import { GCPApiRef } from '../../api';
|
||||
|
||||
const useStyles = makeStyles<Theme>(theme => ({
|
||||
root: {
|
||||
maxWidth: 720,
|
||||
margin: theme.spacing(2),
|
||||
},
|
||||
title: {
|
||||
padding: theme.spacing(1, 0, 2, 0),
|
||||
},
|
||||
table: {
|
||||
padding: theme.spacing(1),
|
||||
},
|
||||
}));
|
||||
|
||||
const DetailsPage = () => {
|
||||
const api = useApi(GCPApiRef);
|
||||
const googleApi = useApi(googleAuthApiRef);
|
||||
const token = googleApi.getAccessToken(
|
||||
'https://www.googleapis.com/auth/cloud-platform.read-only',
|
||||
);
|
||||
|
||||
const classes = useStyles();
|
||||
const status = useAsync(
|
||||
() =>
|
||||
api.getProject(
|
||||
decodeURIComponent(location.search.split('projectId=')[1]),
|
||||
token,
|
||||
),
|
||||
[location.search],
|
||||
);
|
||||
|
||||
if (status.loading) {
|
||||
return <LinearProgress />;
|
||||
} else if (status.error) {
|
||||
return (
|
||||
<Typography variant="h6" color="error">
|
||||
Failed to load build, {status.error.message}
|
||||
</Typography>
|
||||
);
|
||||
}
|
||||
|
||||
const details = status.value;
|
||||
|
||||
return (
|
||||
<Table component={Paper} className={classes.table}>
|
||||
<Table>
|
||||
<TableBody>
|
||||
<TableRow>
|
||||
<TableCell>
|
||||
<Typography noWrap>Name</Typography>
|
||||
</TableCell>
|
||||
<TableCell>{details?.name}</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableCell>
|
||||
<Typography noWrap>Project Number</Typography>
|
||||
</TableCell>
|
||||
<TableCell>{details?.projectNumber}</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableCell>
|
||||
<Typography noWrap>Project ID</Typography>
|
||||
</TableCell>
|
||||
<TableCell>{details?.projectId}</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableCell>
|
||||
<Typography noWrap>State</Typography>
|
||||
</TableCell>
|
||||
<TableCell>{details?.lifecycleState}</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableCell>
|
||||
<Typography noWrap>Creation Time</Typography>
|
||||
</TableCell>
|
||||
<TableCell>{details?.createTime}</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableCell>
|
||||
<Typography noWrap>Links</Typography>
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<ButtonGroup
|
||||
variant="text"
|
||||
color="primary"
|
||||
aria-label="text primary button group"
|
||||
>
|
||||
{details?.name && (
|
||||
<Button>
|
||||
<a href={details.name}>GCP</a>
|
||||
</Button>
|
||||
)}
|
||||
{details?.name && (
|
||||
<Button>
|
||||
<a href={details.name}>Logs</a>
|
||||
</Button>
|
||||
)}
|
||||
</ButtonGroup>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
</TableBody>
|
||||
</Table>
|
||||
</Table>
|
||||
);
|
||||
};
|
||||
|
||||
const labels = (
|
||||
<>
|
||||
<HeaderLabel label="Owner" value="Spotify" />
|
||||
<HeaderLabel label="Lifecycle" value="Production" />
|
||||
</>
|
||||
);
|
||||
|
||||
export const ProjectDetailsPage = () => {
|
||||
return (
|
||||
<Page theme={pageTheme.service}>
|
||||
<Header title="GCP Project Details" type="other">
|
||||
{labels}
|
||||
</Header>
|
||||
<Content>
|
||||
<ContentHeader title="">
|
||||
<SupportButton>Support Button</SupportButton>
|
||||
</ContentHeader>
|
||||
<DetailsPage />
|
||||
</Content>
|
||||
</Page>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,17 @@
|
||||
/*
|
||||
* Copyright 2020 Spotify AB
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
export { ProjectDetailsPage } from './ProjectDetailsPage';
|
||||
@@ -0,0 +1,164 @@
|
||||
/*
|
||||
* Copyright 2020 Spotify AB
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
// NEEDS WORK
|
||||
|
||||
import {
|
||||
Link,
|
||||
useApi,
|
||||
googleAuthApiRef,
|
||||
HeaderLabel,
|
||||
Page,
|
||||
Header,
|
||||
pageTheme,
|
||||
SupportButton,
|
||||
Content,
|
||||
ContentHeader,
|
||||
} from '@backstage/core';
|
||||
import {
|
||||
LinearProgress,
|
||||
Paper,
|
||||
Table,
|
||||
TableBody,
|
||||
TableCell,
|
||||
TableHead,
|
||||
TableRow,
|
||||
Tooltip,
|
||||
Typography,
|
||||
Button,
|
||||
} from '@material-ui/core';
|
||||
import React from 'react';
|
||||
import { useAsync } from 'react-use';
|
||||
import { GCPApiRef, Project } from '../../api';
|
||||
|
||||
const LongText = ({ text, max }: { text: string; max: number }) => {
|
||||
if (text.length < max) {
|
||||
return <span>{text}</span>;
|
||||
}
|
||||
return (
|
||||
<Tooltip title={text}>
|
||||
<span>{text.slice(0, max)}...</span>
|
||||
</Tooltip>
|
||||
);
|
||||
};
|
||||
|
||||
const labels = (
|
||||
<>
|
||||
<HeaderLabel label="Owner" value="Spotify" />
|
||||
<HeaderLabel label="Lifecycle" value="Production" />
|
||||
</>
|
||||
);
|
||||
|
||||
const PageContents = () => {
|
||||
const api = useApi(GCPApiRef);
|
||||
const googleApi = useApi(googleAuthApiRef);
|
||||
|
||||
const { loading, error, value } = useAsync(async () => {
|
||||
const token = await googleApi.getAccessToken(
|
||||
'https://www.googleapis.com/auth/cloud-platform.read-only',
|
||||
);
|
||||
|
||||
const projects = api.listProjects({ token });
|
||||
return projects;
|
||||
});
|
||||
|
||||
if (loading) {
|
||||
return <LinearProgress />;
|
||||
}
|
||||
|
||||
if (error) {
|
||||
return (
|
||||
<Typography variant="h2" color="error">
|
||||
{error.message}{' '}
|
||||
</Typography>
|
||||
);
|
||||
}
|
||||
|
||||
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>
|
||||
);
|
||||
};
|
||||
|
||||
export const ProjectListPage = () => {
|
||||
return (
|
||||
<Page theme={pageTheme.service}>
|
||||
<Header title="GCP Projects" type="tool">
|
||||
{labels}
|
||||
</Header>
|
||||
<Content>
|
||||
<ContentHeader title="">
|
||||
<Button variant="contained" color="primary" href="/gcp-projects/new">
|
||||
New Project
|
||||
</Button>
|
||||
<SupportButton>All your software catalog entities</SupportButton>
|
||||
</ContentHeader>
|
||||
<PageContents />
|
||||
</Content>
|
||||
</Page>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,17 @@
|
||||
/*
|
||||
* Copyright 2020 Spotify AB
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
export { ProjectListPage } from './ProjectListPage';
|
||||
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
* Copyright 2020 Spotify AB
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
export { plugin } from './plugin';
|
||||
export * from './api';
|
||||
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* Copyright 2020 Spotify AB
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { plugin } from './plugin';
|
||||
|
||||
describe('gcp-projects', () => {
|
||||
it('should export plugin', () => {
|
||||
expect(plugin).toBeDefined();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright 2020 Spotify AB
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { createPlugin, createRouteRef } from '@backstage/core';
|
||||
import { ProjectListPage } from './components/ProjectListPage';
|
||||
import { ProjectDetailsPage } from './components/ProjectDetailsPage';
|
||||
import { NewProjectPage } from './components/NewProjectPage';
|
||||
|
||||
export const rootRouteRef = createRouteRef({
|
||||
path: '/gcp-projects',
|
||||
title: 'GCP Projects',
|
||||
});
|
||||
export const ProjectRouteRef = createRouteRef({
|
||||
path: '/gcp-projects/project',
|
||||
title: 'GCP Project Page',
|
||||
});
|
||||
export const NewProjectRouteRef = createRouteRef({
|
||||
path: '/gcp-projects/new',
|
||||
title: 'GCP Project Page',
|
||||
});
|
||||
|
||||
export const plugin = createPlugin({
|
||||
id: 'gcp-projects',
|
||||
register({ router }) {
|
||||
router.addRoute(rootRouteRef, ProjectListPage);
|
||||
router.addRoute(ProjectRouteRef, ProjectDetailsPage);
|
||||
router.addRoute(NewProjectRouteRef, NewProjectPage);
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
* Copyright 2020 Spotify AB
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import '@testing-library/jest-dom';
|
||||
|
||||
require('jest-fetch-mock').enableMocks();
|
||||
Reference in New Issue
Block a user