diff --git a/plugins/bazaar-backend/package.json b/plugins/bazaar-backend/package.json index 1f20bc4ac4..11af15e6f8 100644 --- a/plugins/bazaar-backend/package.json +++ b/plugins/bazaar-backend/package.json @@ -4,6 +4,7 @@ "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", + "private": false, "publishConfig": { "access": "public", "main": "dist/index.cjs.js", diff --git a/plugins/bazaar-backend/src/service/router.ts b/plugins/bazaar-backend/src/service/router.ts index b6f1ba10b3..1319e93c03 100644 --- a/plugins/bazaar-backend/src/service/router.ts +++ b/plugins/bazaar-backend/src/service/router.ts @@ -50,11 +50,6 @@ export async function createRouter( const router = Router(); router.use(express.json()); - router.get('/health', (_, response) => { - logger.info('PONG!'); - response.send({ status: 'ok' }); - }); - router.get('/members', async (request, response) => { const entityRef = request.headers.entity_ref; @@ -64,9 +59,9 @@ export async function createRouter( .where({ entity_ref: entityRef }); if (data?.length) { - response.send({ status: 'ok', data: data }); + response.json({ status: 'ok', data: data }); } else { - response.send({ status: 'ok', data: [] }); + response.json({ status: 'ok', data: [] }); } }); @@ -80,22 +75,20 @@ export async function createRouter( user_id: userId, }) .into('public.members'); - response.send({ status: 'ok' }); + response.json({ status: 'ok' }); }); router.delete('/member', async (request, response) => { const userId = request.headers.user_id; const entityRef = request.headers.entity_ref; - console.log('------- user id ----- ', userId, entityRef); - const count = await db?.('public.members') .where({ entity_ref: entityRef }) .andWhere('user_id', userId) .del(); if (count) { - response.send({ status: 'ok' }); + response.json({ status: 'ok' }); } else { response.status(404).json({ message: 'Record not found' }); } @@ -109,7 +102,7 @@ export async function createRouter( .del(); if (count) { - response.send({ status: 'ok' }); + response.json({ status: 'ok' }); } else { response.status(404).json({ message: 'Record not found' }); } @@ -124,16 +117,32 @@ export async function createRouter( .where({ entity_ref: entityRef }); if (data?.length) { - response.send({ status: 'ok', data: data }); + response.json({ status: 'ok', data: data }); } else { response.status(404).json({ message: 'Record not found' }); } }); router.get('/entities', async (_, response) => { - const data = await db?.select('*').from('public.metadata'); + const columns = [ + 'members.entity_ref', + 'metadata.name', + 'metadata.announcement', + 'metadata.status', + 'metadata.updated_at', + ]; + const data = await db?.('public.members as members') + .select(columns) + .count('members.entity_ref as members_count') + .groupBy(columns) + .join( + 'public.metadata as metadata', + 'metadata.entity_ref', + '=', + 'members.entity_ref', + ); - response.send({ status: 'ok', data: data }); + response.json({ status: 'ok', data: data }); }); router.put('/metadata', async (request, response) => { @@ -149,7 +158,7 @@ export async function createRouter( }); if (count) { - response.send({ status: 'ok' }); + response.json({ status: 'ok' }); } else { await db ?.insert({ @@ -160,7 +169,7 @@ export async function createRouter( status: status, }) .into('public.metadata'); - response.send({ status: 'ok' }); + response.json({ status: 'ok' }); } }); @@ -172,7 +181,7 @@ export async function createRouter( .del(); if (count) { - response.send({ status: 'ok' }); + response.json({ status: 'ok' }); } else { response.status(404).json({ message: 'Record not found' }); } diff --git a/plugins/bazaar/media/add_project.gif b/plugins/bazaar/media/add_project.gif deleted file mode 100644 index 203fd20aca..0000000000 Binary files a/plugins/bazaar/media/add_project.gif and /dev/null differ diff --git a/plugins/bazaar/media/demo.gif b/plugins/bazaar/media/demo.gif deleted file mode 100644 index 52891ece33..0000000000 Binary files a/plugins/bazaar/media/demo.gif and /dev/null differ diff --git a/plugins/bazaar/media/edit_project.gif b/plugins/bazaar/media/edit_project.gif deleted file mode 100644 index 3b8665890e..0000000000 Binary files a/plugins/bazaar/media/edit_project.gif and /dev/null differ diff --git a/plugins/bazaar/media/home.png b/plugins/bazaar/media/home.png deleted file mode 100644 index d3422489ff..0000000000 Binary files a/plugins/bazaar/media/home.png and /dev/null differ diff --git a/plugins/bazaar/media/home_placeholder.png b/plugins/bazaar/media/home_placeholder.png deleted file mode 100644 index 7d0c18eda4..0000000000 Binary files a/plugins/bazaar/media/home_placeholder.png and /dev/null differ diff --git a/plugins/bazaar/media/project.png b/plugins/bazaar/media/project.png deleted file mode 100644 index d1bf28d469..0000000000 Binary files a/plugins/bazaar/media/project.png and /dev/null differ diff --git a/plugins/bazaar/media/project_placeholder.png b/plugins/bazaar/media/project_placeholder.png deleted file mode 100644 index f3ef815e8a..0000000000 Binary files a/plugins/bazaar/media/project_placeholder.png and /dev/null differ diff --git a/plugins/bazaar/media/tab_placeholder.png b/plugins/bazaar/media/tab_placeholder.png deleted file mode 100644 index 6da9eb9ea5..0000000000 Binary files a/plugins/bazaar/media/tab_placeholder.png and /dev/null differ diff --git a/plugins/bazaar/package.json b/plugins/bazaar/package.json index d626a0ddcf..5d4415d570 100644 --- a/plugins/bazaar/package.json +++ b/plugins/bazaar/package.json @@ -4,6 +4,7 @@ "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", + "private": false, "publishConfig": { "access": "public", "main": "dist/index.esm.js", @@ -30,6 +31,7 @@ "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.45", "@testing-library/jest-dom": "^5.14.1", + "luxon": "^2.0.2", "moment": "^2.29.1", "react": "^16.13.1", "react-dom": "^16.13.1", diff --git a/plugins/bazaar/src/api.ts b/plugins/bazaar/src/api.ts index fb133b5a28..ca082c69c6 100644 --- a/plugins/bazaar/src/api.ts +++ b/plugins/bazaar/src/api.ts @@ -14,17 +14,13 @@ * limitations under the License. */ -import { - Entity, - EntityRef, - stringifyEntityRef, -} from '@backstage/catalog-model'; +import { Entity, stringifyEntityRef } from '@backstage/catalog-model'; import { createApiRef, DiscoveryApi, IdentityApi, } from '@backstage/core-plugin-api'; -import { BazaarProject, Status } from './types'; +import { Status } from './types'; export const bazaarApiRef = createApiRef({ id: 'bazaar', @@ -42,10 +38,6 @@ export interface BazaarApi { getMetadata(entity: Entity): Promise; - getMemberCounts( - bazaarProjects: BazaarProject[], - ): Promise>; - getMembers(entity: Entity): Promise; deleteMember(entity: Entity): Promise; @@ -107,27 +99,6 @@ export class BazaarClient implements BazaarApi { }); } - async getMemberCounts( - bazaarProjects: BazaarProject[], - ): Promise> { - const baseUrl = await this.discoveryApi.getBaseUrl('bazaar'); - - const members = new Map(); - for (const project of bazaarProjects) { - const response = await fetch(`${baseUrl}/members`, { - method: 'GET', - headers: { - entity_ref: project.entityRef as string, - }, - }); - - const json = await response.json(); - const nbrOfMembers = await json.data.length; - members.set(project.entityRef, nbrOfMembers); - } - return members; - } - async getMembers(entity: Entity): Promise { const baseUrl = await this.discoveryApi.getBaseUrl('bazaar'); diff --git a/plugins/bazaar/src/components/AddProjectDialog/AddProjectDialog.tsx b/plugins/bazaar/src/components/AddProjectDialog/AddProjectDialog.tsx index 2cac8521f6..8aeff2e997 100644 --- a/plugins/bazaar/src/components/AddProjectDialog/AddProjectDialog.tsx +++ b/plugins/bazaar/src/components/AddProjectDialog/AddProjectDialog.tsx @@ -71,6 +71,7 @@ export const AddProjectDialog = ({ announcement: formValues.announcement, status: formValues.status, updatedAt: new Date().toISOString(), + membersCount: 0, }; setBazaarProjects((oldProjects: BazaarProject[]) => { diff --git a/plugins/bazaar/src/components/EntityBazaarInfoCard/EntityBazaarInfoCard.tsx b/plugins/bazaar/src/components/EntityBazaarInfoCard/EntityBazaarInfoCard.tsx index efd0339d9e..eb6b3763ce 100644 --- a/plugins/bazaar/src/components/EntityBazaarInfoCard/EntityBazaarInfoCard.tsx +++ b/plugins/bazaar/src/components/EntityBazaarInfoCard/EntityBazaarInfoCard.tsx @@ -47,11 +47,16 @@ import DeleteIcon from '@material-ui/icons/Delete'; import { EditProjectDialog } from '../EditProjectDialog'; import { DeleteProjectDialog } from '../DeleteProjectDialog'; import ExitToAppIcon from '@material-ui/icons/ExitToApp'; -import { useApi, identityApiRef } from '@backstage/core-plugin-api'; +import { + useApi, + identityApiRef, + useRouteRef, +} from '@backstage/core-plugin-api'; import { useAsync } from 'react-use'; import { Member, BazaarProject } from '../../types'; import { bazaarApiRef } from '../../api'; import { stringifyEntityRef } from '@backstage/catalog-model'; +import { rootRouteRef } from '../../routes'; const useStyles = makeStyles({ description: { @@ -73,7 +78,7 @@ const useStyles = makeStyles({ }); const sortMembers = (m1: Member, m2: Member) => { - return new Date(m2.joinDate).getTime() - new Date(m1.joinDate).getTime(); + return new Date(m2.joinDate!).getTime() - new Date(m1.joinDate!).getTime(); }; export const EntityBazaarInfoCard = () => { @@ -95,8 +100,10 @@ export const EntityBazaarInfoCard = () => { announcement: '', status: 'proposed', updatedAt: '', + membersCount: 0, }); const [isBazaar, setIsBazaar] = useState(false); + const routeRef = useRouteRef(rootRouteRef); const getInitMemberStatus = async () => { const response = await bazaarApi.getMembers(entity); @@ -134,6 +141,7 @@ export const EntityBazaarInfoCard = () => { announcement: data[0].announcement, status: data[0].status, updatedAt: data[0].updatedAt, + membersCount: data[0].membersCount, }); } }; @@ -166,12 +174,12 @@ export const EntityBazaarInfoCard = () => { const newMember: Member = { userId: identity.getUserId(), entityRef: stringifyEntityRef(entity), - joinDate: new Date().toISOString(), }; if (!isMember) { setMembers((prevMembers: Member[]) => { - const newMembers: Member[] = [...prevMembers, newMember]; + const newMembers: Member[] = [newMember, ...prevMembers]; + newMembers.sort(sortMembers); return newMembers; }); @@ -213,11 +221,11 @@ export const EntityBazaarInfoCard = () => { This project is not in the Bazaar. Go to the{' '} - + Bazaar {' '} to add the project or to{' '} - + read more . @@ -287,16 +295,18 @@ export const EntityBazaarInfoCard = () => { {bazaarProject.announcement - ? bazaarProject.announcement.split('\n').map((str: string) => ( - - {str} - - )) + ? bazaarProject.announcement + .split('\n') + .map((str: string, i: number) => ( + + {str} + + )) : 'No announcement'} diff --git a/plugins/bazaar/src/components/ProjectCard/ProjectCard.tsx b/plugins/bazaar/src/components/ProjectCard/ProjectCard.tsx index b23f3d5d6f..8c9bc17208 100644 --- a/plugins/bazaar/src/components/ProjectCard/ProjectCard.tsx +++ b/plugins/bazaar/src/components/ProjectCard/ProjectCard.tsx @@ -25,11 +25,11 @@ import { } from '@material-ui/core'; import { StatusTag } from '../StatusTag/StatusTag'; import { Link as RouterLink } from 'react-router-dom'; -import moment from 'moment'; import { catalogRouteRef } from '@backstage/plugin-catalog-react'; import { useRouteRef } from '@backstage/core-plugin-api'; import { BazaarProject } from '../../types'; import { parseEntityName } from '@backstage/catalog-model'; +import { DateTime } from 'luxon'; const useStyles = makeStyles({ statusTag: { @@ -51,12 +51,12 @@ const useStyles = makeStyles({ type Props = { bazaarProject: BazaarProject; - memberCount: number; }; -export const ProjectCard = ({ bazaarProject, memberCount }: Props) => { +export const ProjectCard = ({ bazaarProject }: Props) => { const classes = useStyles(); - const { entityRef, name, status, updatedAt, announcement } = bazaarProject; + const { entityRef, name, status, updatedAt, announcement, membersCount } = + bazaarProject; const catalogLink = useRouteRef(catalogRouteRef); const { namespace, kind } = parseEntityName(entityRef); @@ -73,14 +73,16 @@ export const ProjectCard = ({ bazaarProject, memberCount }: Props) => { > - {memberCount === 1 - ? `${memberCount} member` - : `${memberCount} members`} + {membersCount === 1 + ? `${membersCount} member` + : `${membersCount} members`}
diff --git a/plugins/bazaar/src/components/ProjectPreview/ProjectPreview.tsx b/plugins/bazaar/src/components/ProjectPreview/ProjectPreview.tsx index 0f12541bee..0b01b86088 100644 --- a/plugins/bazaar/src/components/ProjectPreview/ProjectPreview.tsx +++ b/plugins/bazaar/src/components/ProjectPreview/ProjectPreview.tsx @@ -20,12 +20,10 @@ import { ProjectCard } from '../ProjectCard/ProjectCard'; import { makeStyles, Grid } from '@material-ui/core'; import Pagination from '@material-ui/lab/Pagination'; import { BazaarProject } from '../../types'; -import { EntityRef } from '@backstage/catalog-model'; type Props = { bazaarProjects: BazaarProject[]; sortingMethod: (arg0: BazaarProject, arg1: BazaarProject) => number; - bazaarMembers: Map; }; const useStyles = makeStyles({ @@ -42,11 +40,7 @@ const useStyles = makeStyles({ }, }); -export const ProjectPreview = ({ - bazaarProjects, - sortingMethod, - bazaarMembers, -}: Props) => { +export const ProjectPreview = ({ bazaarProjects, sortingMethod }: Props) => { const classes = useStyles(); const [currentPage, setCurrentPage] = useState(1); const pageSize = 10; @@ -92,7 +86,6 @@ export const ProjectPreview = ({ ); diff --git a/plugins/bazaar/src/components/SortView/SortView.tsx b/plugins/bazaar/src/components/SortView/SortView.tsx index 1eaf598c99..1b1ff43bd0 100644 --- a/plugins/bazaar/src/components/SortView/SortView.tsx +++ b/plugins/bazaar/src/components/SortView/SortView.tsx @@ -26,16 +26,9 @@ import { AlertBanner } from '../AlertBanner'; import { ProjectPreview } from '../ProjectPreview/ProjectPreview'; import { Button, makeStyles, Link } from '@material-ui/core'; import { useAsync } from 'react-use'; -import { - Entity, - EntityRef, - stringifyEntityRef, -} from '@backstage/catalog-model'; +import { Entity, stringifyEntityRef } from '@backstage/catalog-model'; import { useApi } from '@backstage/core-plugin-api'; -import { - catalogApiRef, - CATALOG_FILTER_EXISTS, -} from '@backstage/plugin-catalog-react'; +import { catalogApiRef } from '@backstage/plugin-catalog-react'; import { BazaarProject } from '../../types'; import { bazaarApiRef } from '../../api'; @@ -50,9 +43,6 @@ export const SortView = () => { const [openAdd, setOpenAdd] = useState(false); const [openNoProjects, setOpenNoProjects] = useState(false); const [catalogEntities, setCatalogEntities] = useState([]); - const [bazaarMembers, setBazaarMembers] = useState>( - new Map(), - ); const [bazaarProjects, setBazaarProjects] = useState([]); const bazaarApi = useApi(bazaarApiRef); const catalogApi = useApi(catalogApiRef); @@ -61,8 +51,8 @@ export const SortView = () => { a: BazaarProject, b: BazaarProject, ): number => { - const dateA = new Date(a.updatedAt).getTime(); - const dateB = new Date(b.updatedAt).getTime(); + const dateA = new Date(a.updatedAt!).getTime(); + const dateB = new Date(b.updatedAt!).getTime(); return dateB - dateA; }; @@ -73,10 +63,9 @@ export const SortView = () => { const { loading } = useAsync(async () => { const entities = await catalogApi.getEntities({ filter: { - kind: 'Component', - 'metadata.annotations.backstage.io/edit-url': CATALOG_FILTER_EXISTS, + kind: ['Component', 'API', 'Resource', 'System', 'Domain'], }, - fields: ['apiVersion', 'kind', 'metadata', 'spec'], + fields: ['kind', 'metadata.name', 'metadata.namespace'], }); const response = await bazaarApi.getEntities(); @@ -91,12 +80,12 @@ export const SortView = () => { announcement: project.announcement, community: project.community, updatedAt: project.updated_at, + membersCount: project.members_count, }); bazaarProjectRefs.push(project.entity_ref); }); - setBazaarMembers(await bazaarApi.getMemberCounts(dbProjects)); setBazaarProjects(dbProjects); setCatalogEntities( entities.items.filter((entity: Entity) => { @@ -155,7 +144,6 @@ export const SortView = () => { diff --git a/plugins/bazaar/src/tsdoc-metadata.json b/plugins/bazaar/src/tsdoc-metadata.json deleted file mode 100644 index 94dccf8f51..0000000000 --- a/plugins/bazaar/src/tsdoc-metadata.json +++ /dev/null @@ -1,11 +0,0 @@ -// This file is read by tools that parse documentation comments conforming to the TSDoc standard. -// It should be published with your NPM package. It should not be tracked by Git. -{ - "tsdocVersion": "0.12", - "toolPackages": [ - { - "packageName": "@microsoft/api-extractor", - "packageVersion": "7.18.9" - } - ] -} diff --git a/plugins/bazaar/src/types.ts b/plugins/bazaar/src/types.ts index d04859db93..9e902747aa 100644 --- a/plugins/bazaar/src/types.ts +++ b/plugins/bazaar/src/types.ts @@ -19,7 +19,7 @@ import { EntityRef } from '@backstage/catalog-model'; export type Member = { entityRef: EntityRef; userId: string; - joinDate: string; + joinDate?: string; }; export type Status = 'ongoing' | 'proposed'; @@ -30,7 +30,8 @@ export type BazaarProject = { community: string; status: Status; announcement: string; - updatedAt: string; + updatedAt?: string; + membersCount: number; }; export type FormValues = {