Merge pull request #8868 from lykkeaxlin/minor-fixes

[Bazaar] Add to marketplace and some minor fixes
This commit is contained in:
Ben Lambert
2022-01-12 13:20:53 +01:00
committed by GitHub
18 changed files with 160 additions and 66 deletions
+6
View File
@@ -0,0 +1,6 @@
---
'@backstage/plugin-bazaar': patch
'@backstage/plugin-bazaar-backend': patch
---
Add Bazaar plugin to marketplace and some minor refactoring
+8
View File
@@ -0,0 +1,8 @@
title: Bazaar
author: Axis Communications AB
authorUrl: https://www.axis.com
category: Discovery
description: A marketplace where engineers can propose projects suitable for inner sourcing
documentation: https://github.com/backstage/backstage/blob/master/plugins/bazaar/README.md
iconUrl: img/bazaar.svg
npmPackageName: '@backstage/plugin-bazaar'
+1
View File
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" enable-background="new 0 0 24 24" height="24" viewBox="0 0 24 24" width="24"><g><rect fill="none" height="24" width="24"/></g><g><g/><g><path d="M21.9,8.89l-1.05-4.37c-0.22-0.9-1-1.52-1.91-1.52H5.05C4.15,3,3.36,3.63,3.15,4.52L2.1,8.89 c-0.24,1.02-0.02,2.06,0.62,2.88C2.8,11.88,2.91,11.96,3,12.06V19c0,1.1,0.9,2,2,2h14c1.1,0,2-0.9,2-2v-6.94 c0.09-0.09,0.2-0.18,0.28-0.28C21.92,10.96,22.15,9.91,21.9,8.89z M18.91,4.99l1.05,4.37c0.1,0.42,0.01,0.84-0.25,1.17 C19.57,10.71,19.27,11,18.77,11c-0.61,0-1.14-0.49-1.21-1.14L16.98,5L18.91,4.99z M13,5h1.96l0.54,4.52 c0.05,0.39-0.07,0.78-0.33,1.07C14.95,10.85,14.63,11,14.22,11C13.55,11,13,10.41,13,9.69V5z M8.49,9.52L9.04,5H11v4.69 C11,10.41,10.45,11,9.71,11c-0.34,0-0.65-0.15-0.89-0.41C8.57,10.3,8.45,9.91,8.49,9.52z M4.04,9.36L5.05,5h1.97L6.44,9.86 C6.36,10.51,5.84,11,5.23,11c-0.49,0-0.8-0.29-0.93-0.47C4.03,10.21,3.94,9.78,4.04,9.36z M5,19v-6.03C5.08,12.98,5.15,13,5.23,13 c0.87,0,1.66-0.36,2.24-0.95c0.6,0.6,1.4,0.95,2.31,0.95c0.87,0,1.65-0.36,2.23-0.93c0.59,0.57,1.39,0.93,2.29,0.93 c0.84,0,1.64-0.35,2.24-0.95c0.58,0.59,1.37,0.95,2.24,0.95c0.08,0,0.15-0.02,0.23-0.03V19H5z"/></g></g></svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

+8 -10
View File
@@ -69,21 +69,19 @@ export async function createRouter(
}
});
router.get('/projects/id/:id', async (request, response) => {
const id = decodeURIComponent(request.params.id);
router.get('/projects/:idOrRef', async (request, response) => {
const idOrRef = decodeURIComponent(request.params.idOrRef);
let data;
const data = await dbHandler.getMetadataById(parseInt(id, 10));
if (/^-?\d+$/.test(idOrRef)) {
data = await dbHandler.getMetadataById(parseInt(idOrRef, 10));
} else {
data = await dbHandler.getMetadataByRef(idOrRef);
}
response.json({ status: 'ok', data: data });
});
router.get('/projects/ref/:ref', async (request, response) => {
const ref = decodeURIComponent(request.params.ref);
const data = await dbHandler.getMetadataByRef(ref);
response.json({ status: 'ok', data: data });
});
router.get('/projects', async (_, response) => {
const data = await dbHandler.getProjects();
+1
View File
@@ -21,6 +21,7 @@
"clean": "backstage-cli clean"
},
"dependencies": {
"@backstage/catalog-client": "^0.5.3",
"@backstage/catalog-model": "^0.9.7",
"@backstage/cli": "^0.10.5",
"@backstage/core-components": "^0.8.3",
+36 -20
View File
@@ -85,9 +85,12 @@ export class BazaarClient implements BazaarApi {
async getProjectById(id: number): Promise<any> {
const baseUrl = await this.discoveryApi.getBaseUrl('bazaar');
const response = await fetch(`${baseUrl}/projects/id/${id}`, {
method: 'GET',
});
const response = await fetch(
`${baseUrl}/projects/${encodeURIComponent(id)}`,
{
method: 'GET',
},
);
return response.ok ? response : null;
}
@@ -96,7 +99,7 @@ export class BazaarClient implements BazaarApi {
const baseUrl = await this.discoveryApi.getBaseUrl('bazaar');
const response = await fetch(
`${baseUrl}/projects/ref/${encodeURIComponent(entityRef)}`,
`${baseUrl}/projects/${encodeURIComponent(entityRef)}`,
{
method: 'GET',
},
@@ -108,32 +111,45 @@ export class BazaarClient implements BazaarApi {
async getMembers(id: number): Promise<any> {
const baseUrl = await this.discoveryApi.getBaseUrl('bazaar');
return await fetch(`${baseUrl}/projects/${id}/members`, {
method: 'GET',
}).then(resp => resp.json());
return await fetch(
`${baseUrl}/projects/${encodeURIComponent(id)}/members`,
{
method: 'GET',
},
).then(resp => resp.json());
}
async addMember(id: number, userId: string): Promise<void> {
const baseUrl = await this.discoveryApi.getBaseUrl('bazaar');
await fetch(`${baseUrl}/projects/${id}/member/${userId}`, {
method: 'PUT',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
await fetch(
`${baseUrl}/projects/${encodeURIComponent(
id,
)}/member/${encodeURIComponent(userId)}`,
{
method: 'PUT',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({
picture: (await this.identityApi.getProfileInfo()).picture,
}),
},
body: JSON.stringify({
picture: this.identityApi.getProfile()?.picture,
}),
});
);
}
async deleteMember(id: number, userId: string): Promise<void> {
const baseUrl = await this.discoveryApi.getBaseUrl('bazaar');
await fetch(`${baseUrl}/projects/${id}/member/${userId}`, {
method: 'DELETE',
});
await fetch(
`${baseUrl}/projects/${encodeURIComponent(
id,
)}/member/${encodeURIComponent(userId)}`,
{
method: 'DELETE',
},
);
}
async getProjects(): Promise<any> {
@@ -147,7 +163,7 @@ export class BazaarClient implements BazaarApi {
async deleteProject(id: number): Promise<void> {
const baseUrl = await this.discoveryApi.getBaseUrl('bazaar');
await fetch(`${baseUrl}/projects/${id}`, {
await fetch(`${baseUrl}/projects/${encodeURIComponent(id)}`, {
method: 'DELETE',
});
}
@@ -15,8 +15,8 @@
*/
import React from 'react';
import { Grid, Typography, Link, makeStyles } from '@material-ui/core';
import { InfoCard } from '@backstage/core-components';
import { Grid, Typography, makeStyles } from '@material-ui/core';
import { InfoCard, Link } from '@backstage/core-components';
const useStyles = makeStyles({
subheader: {
@@ -39,7 +39,7 @@ export const About = () => {
internal projects suitable for{' '}
<Link
target="_blank"
href="https://en.wikipedia.org/wiki/Inner_source"
to="https://en.wikipedia.org/wiki/Inner_source"
>
Inner Sourcing
</Link>
@@ -57,7 +57,10 @@ export const AddProjectDialog = ({
setSelectedEntity(entity);
};
const handleSubmit: any = async (
const handleSubmit: (
getValues: UseFormGetValues<FormValues>,
reset: UseFormReset<FormValues>,
) => Promise<void> = async (
getValues: UseFormGetValues<FormValues>,
reset: UseFormReset<FormValues>,
) => {
@@ -21,10 +21,9 @@ import {
Card,
CardContent,
Typography,
Link,
GridSize,
} from '@material-ui/core';
import { Avatar } from '@backstage/core-components';
import { Avatar, Link } from '@backstage/core-components';
import { AboutField } from '@backstage/plugin-catalog';
import { StatusTag } from '../StatusTag';
import { Member, BazaarProject } from '../../types';
@@ -32,6 +31,7 @@ import { Member, BazaarProject } from '../../types';
const useStyles = makeStyles({
break: {
wordBreak: 'break-word',
textAlign: 'justify',
},
});
@@ -111,7 +111,7 @@ export const CardContentFields = ({
/>
<Link
className={classes.break}
href={`http://github.com/${member.userId}`}
to={`http://github.com/${member.userId}`}
target="_blank"
>
{member?.userId}
@@ -36,6 +36,11 @@ const useStyles = makeStyles({
marginLeft: '0',
marginRight: 'auto',
},
wordBreak: {
wordBreak: 'break-all',
whiteSpace: 'normal',
margin: '-0.25rem 0',
},
});
export const EditProjectDialog = ({
@@ -76,9 +81,9 @@ export const EditProjectDialog = ({
});
}, [bazaarProject]);
const handleEditSubmit: any = async (
const handleEditSubmit: (
getValues: UseFormGetValues<FormValues>,
) => {
) => Promise<void> = async (getValues: UseFormGetValues<FormValues>) => {
const formValues = getValues();
const updateResponse = await bazaarApi.updateProject({
@@ -101,7 +106,9 @@ export const EditProjectDialog = ({
handleClose={handleDeleteClose}
message={[
'Are you sure you want to delete ',
<b>{bazaarProject.name}</b>,
<b key={bazaarProject.name} className={classes.wordBreak}>
{bazaarProject.name}
</b>,
' from the Bazaar?',
]}
type="delete"
@@ -15,7 +15,7 @@
*/
import React, { useState, useEffect } from 'react';
import { CardHeader, Divider, IconButton } from '@material-ui/core';
import { CardHeader, Divider, IconButton, makeStyles } from '@material-ui/core';
import {
HeaderIconLinkRow,
IconLinkVerticalProps,
@@ -37,6 +37,14 @@ import { ConfirmationDialog } from '../ConfirmationDialog';
import { CardContentFields } from '../CardContentFields';
import { fetchProjectMembers } from '../../util/fetchMethods';
const useStyles = makeStyles({
wordBreak: {
wordBreak: 'break-all',
whiteSpace: 'normal',
margin: '-0.25rem 0',
},
});
type Props = {
bazaarProject: BazaarProject | null | undefined;
fetchBazaarProject: () => Promise<BazaarProject | null>;
@@ -46,6 +54,7 @@ export const EntityBazaarInfoContent = ({
bazaarProject,
fetchBazaarProject,
}: Props) => {
const classes = useStyles();
const bazaarApi = useApi(bazaarApiRef);
const identity = useApi(identityApiRef);
const [openEdit, setOpenEdit] = useState(false);
@@ -160,9 +169,11 @@ export const EntityBazaarInfoContent = ({
handleClose={handleUnlinkClose}
message={[
'Are you sure you want to unlink ',
<b>{parseEntityRef(bazaarProject.entityRef!).name}</b>,
<b className={classes.wordBreak}>
{parseEntityRef(bazaarProject.entityRef!).name}
</b>,
' from ',
<b>{bazaarProject.name}</b>,
<b className={classes.wordBreak}>{bazaarProject.name}</b>,
' ?',
]}
type="unlink"
@@ -171,7 +182,7 @@ export const EntityBazaarInfoContent = ({
)}
<CardHeader
title={bazaarProject?.name!}
title={<p className={classes.wordBreak}>{bazaarProject?.name!}</p>}
action={
<div>
<IconButton
@@ -15,7 +15,13 @@
*/
import React, { useState, useEffect } from 'react';
import { Card, CardHeader, Divider, IconButton } from '@material-ui/core';
import {
Card,
CardHeader,
Divider,
IconButton,
makeStyles,
} from '@material-ui/core';
import {
HeaderIconLinkRow,
IconLinkVerticalProps,
@@ -37,7 +43,7 @@ import {
import { Member, BazaarProject } from '../../types';
import { bazaarApiRef } from '../../api';
import { Alert } from '@material-ui/lab';
import useAsyncFn from 'react-use/lib/useAsyncFn';
import { useAsyncFn } from 'react-use';
import {
catalogApiRef,
catalogRouteRef,
@@ -59,6 +65,14 @@ import {
} from '../../util/fetchMethods';
import { parseBazaarResponse } from '../../util/parseMethods';
const useStyles = makeStyles({
wordBreak: {
wordBreak: 'break-all',
whiteSpace: 'normal',
margin: '-0.25rem 0',
},
});
type Props = {
initProject: BazaarProject;
handleClose: () => void;
@@ -70,6 +84,7 @@ export const HomePageBazaarInfoCard = ({
handleClose,
initEntity,
}: Props) => {
const classes = useStyles();
const catalogLink = useRouteRef(catalogRouteRef);
const bazaarApi = useApi(bazaarApiRef);
const identity = useApi(identityApiRef);
@@ -222,9 +237,11 @@ export const HomePageBazaarInfoCard = ({
handleClose={() => setOpenUnlink(false)}
message={[
'Are you sure you want to unlink ',
<b>{parseEntityRef(bazaarProject.value?.entityRef!).name}</b>,
<b className={classes.wordBreak}>
{parseEntityRef(bazaarProject.value?.entityRef!).name}
</b>,
' from ',
<b>{bazaarProject.value?.name}</b>,
<b className={classes.wordBreak}>{bazaarProject.value?.name}</b>,
' ?',
]}
type="unlink"
@@ -242,7 +259,11 @@ export const HomePageBazaarInfoCard = ({
/>
<CardHeader
title={bazaarProject.value?.name || initProject.name}
title={
<p className={classes.wordBreak}>
{bazaarProject.value?.name || initProject.name}
</p>
}
action={
<div>
<IconButton onClick={() => setOpenEdit(true)}>
@@ -15,13 +15,18 @@
*/
import React from 'react';
import { Controller, Control, FieldError } from 'react-hook-form';
import {
Controller,
Control,
FieldError,
ValidationRule,
} from 'react-hook-form';
import { TextField } from '@material-ui/core';
import { FormValues } from '../../types';
type Rules = {
required: boolean;
pattern?: any;
pattern?: ValidationRule<RegExp> | undefined;
};
type Props = {
@@ -41,12 +41,19 @@ const useStyles = makeStyles({
WebkitLineClamp: 7,
WebkitBoxOrient: 'vertical',
overflow: 'hidden',
backgroundColor: '',
textAlign: 'justify',
},
memberCount: {
float: 'right',
},
content: { height: '13rem', marginBottom: '-0.5rem' },
content: {
height: '13rem',
},
header: {
whiteSpace: 'nowrap',
overflow: 'hidden',
textOverflow: 'ellipsis',
},
});
type Props = {
@@ -82,7 +89,12 @@ export const ProjectCard = ({
<Card key={id}>
<CardActionArea onClick={() => setOpenCard(true)}>
<ItemCardHeader
title={name}
classes={{ root: classes.header }}
title={
<Typography noWrap variant="h6" component="h4">
{name}
</Typography>
}
subtitle={`updated ${DateTime.fromISO(
new Date(updatedAt!).toISOString(),
).toRelative({
@@ -16,12 +16,7 @@
import React from 'react';
import { Button, Dialog } from '@material-ui/core';
import {
useForm,
SubmitHandler,
UseFormReset,
UseFormGetValues,
} from 'react-hook-form';
import { useForm, UseFormReset, UseFormGetValues } from 'react-hook-form';
import { InputField } from '../InputField/InputField';
import { InputSelector } from '../InputSelector/InputSelector';
import { FormValues } from '../../types';
@@ -36,7 +31,7 @@ type Props = {
handleSave: (
getValues: UseFormGetValues<FormValues>,
reset: UseFormReset<FormValues>,
) => SubmitHandler<FormValues>;
) => Promise<void>;
isAddForm: boolean;
title: string;
defaultValues: FormValues;
@@ -14,7 +14,7 @@
* limitations under the License.
*/
import React from 'react';
import React, { ChangeEvent, ReactNode } from 'react';
import { FormControl, MenuItem, Select, makeStyles } from '@material-ui/core';
const useStyles = makeStyles({
@@ -27,7 +27,12 @@ const useStyles = makeStyles({
type Props = {
sortMethodNbr: number;
handleSortMethodChange: any;
handleSortMethodChange:
| ((
event: ChangeEvent<{ name?: string | undefined; value: unknown }>,
child: ReactNode,
) => void)
| undefined;
};
export const SortMethodSelector = ({
@@ -33,7 +33,7 @@ import { fetchCatalogItems } from '../../util/fetchMethods';
import { parseBazaarProject } from '../../util/parseMethods';
const useStyles = makeStyles({
button: { width: '12rem' },
button: { minWidth: '11rem' },
container: {
marginTop: '2rem',
},
@@ -141,7 +141,9 @@ export const SortView = () => {
}
}, [bazaarProjects, catalogEntities]);
const handleSortMethodChange = (event: ChangeEvent<HTMLInputElement>) => {
const handleSortMethodChange = (
event: ChangeEvent<{ name?: string | undefined; value: unknown }>,
) => {
setSortMethodNbr(
typeof event.target.value === 'number' ? event.target.value : 0,
);
+4 -1
View File
@@ -19,6 +19,7 @@ import { parseMember } from './parseMethods';
import { BazaarProject, Member } from '../types';
import { BazaarApi } from '../api';
import { Entity } from '@backstage/catalog-model';
import { CatalogApi } from '@backstage/plugin-catalog-react';
export const fetchProjectMembers = async (
bazaarApi: BazaarApi,
@@ -37,7 +38,9 @@ export const fetchProjectMembers = async (
return [];
};
export const fetchCatalogItems = async (catalogApi: any): Promise<Entity[]> => {
export const fetchCatalogItems = async (
catalogApi: CatalogApi,
): Promise<Entity[]> => {
const entities = await catalogApi.getEntities({
filter: {
kind: ['Component', 'Resource'],