Skip to content

Commit

Permalink
feat(bulk-import): create bulk-import frontend plugin (#1327)
Browse files Browse the repository at this point in the history
Co-authored-by: debsmita1 <[email protected]>
  • Loading branch information
invincibleJai and debsmita1 authored Mar 11, 2024
1 parent 81e79bf commit e03f47f
Show file tree
Hide file tree
Showing 23 changed files with 467 additions and 2 deletions.
1 change: 1 addition & 0 deletions plugins/bulk-import/.eslintrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module.exports = require('@backstage/cli/config/eslint-factory')(__dirname);
7 changes: 7 additions & 0 deletions plugins/bulk-import/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Bulk import frontend plugin for Backstage

This plugin allows bulk import of multiple catalog entities into the catalog.

## Getting started

Coming soon.
14 changes: 14 additions & 0 deletions plugins/bulk-import/app-config.janus-idp.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
dynamicPlugins:
frontend:
janus-idp.backstage-plugin-bulk-import:
appIcons:
- name: LibraryAddOutlinedIcon
module: BulkImportPlugin
importName: LibraryAddOutlinedIcon
dynamicRoutes:
- path: /bulk-import
importName: BulkImportPage
module: BulkImportPlugin
menuItem:
icon: LibraryAddOutlinedIcon
text: Bulk import
1 change: 1 addition & 0 deletions plugins/bulk-import/config.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export interface Config {}
14 changes: 14 additions & 0 deletions plugins/bulk-import/dev/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import React from 'react';

import { createDevApp } from '@backstage/dev-utils';

import { BulkImportPage, bulkImportPlugin } from '../src/plugin';

createDevApp()
.registerPlugin(bulkImportPlugin)
.addPage({
element: <BulkImportPage />,
title: 'Bulk import',
path: '/bulk-import',
})
.render();
72 changes: 72 additions & 0 deletions plugins/bulk-import/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
{
"name": "@janus-idp/backstage-plugin-bulk-import",
"version": "0.1.0",
"main": "src/index.ts",
"types": "src/index.ts",
"license": "Apache-2.0",
"publishConfig": {
"access": "public",
"main": "dist/index.esm.js",
"types": "dist/index.d.ts"
},
"backstage": {
"role": "frontend-plugin"
},
"scripts": {
"build": "backstage-cli package build",
"clean": "backstage-cli package clean",
"export-dynamic": "janus-cli package export-dynamic-plugin",
"lint": "backstage-cli package lint",
"postpack": "backstage-cli package postpack",
"postversion": "yarn run export-dynamic",
"prepack": "backstage-cli package prepack",
"start": "backstage-cli package start",
"test": "backstage-cli package test --passWithNoTests --coverage",
"tsc": "tsc",
"ui-test": "yarn playwright test"
},
"dependencies": {
"@backstage/core-components": "^0.14.0",
"@backstage/core-plugin-api": "^1.9.0",
"@backstage/theme": "^0.5.1",
"@material-ui/core": "^4.9.13",
"@material-ui/icons": "^4.9.1",
"@material-ui/lab": "^4.0.0-alpha.61",
"@mui/icons-material": "5.14.11",
"react-use": "^17.2.4"
},
"peerDependencies": {
"react": "16.13.1 || ^17.0.0 || ^18.0.0",
"react-router-dom": "^6.20.0"
},
"devDependencies": {
"@backstage/cli": "0.25.2",
"@backstage/core-app-api": "1.12.0",
"@backstage/dev-utils": "1.0.27",
"@backstage/test-utils": "1.5.0",
"@janus-idp/cli": "1.7.2",
"@testing-library/jest-dom": "6.0.0",
"@testing-library/react": "14.0.0",
"@testing-library/user-event": "14.0.0",
"@playwright/test": "1.41.2",
"msw": "1.0.0"
},
"scalprum": {
"name": "janus-idp.backstage-plugin-rbac",
"exposedModules": {
"RbacPlugin": "./src/index.ts"
}
},
"files": [
"dist",
"dist-scalprum",
"app-config.janus-idp.yaml"
],
"repository": "github:janus-idp/backstage-plugins",
"keywords": [
"backstage",
"plugin"
],
"homepage": "https://janus-idp.io/",
"bugs": "https://github.com/janus-idp/backstage-plugins/issues"
}
34 changes: 34 additions & 0 deletions plugins/bulk-import/playwright.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { defineConfig, devices } from '@playwright/test';

/**
* See https://playwright.dev/docs/test-configuration.
*/
export default defineConfig({
testDir: './tests',
/* Run tests in files in parallel */
fullyParallel: true,
/* Fail the build on CI if you accidentally left test.only in the source code. */
forbidOnly: !!process.env.CI,
/* Retry on CI only */
retries: process.env.CI ? 2 : 0,
/* Run tests in sequence. */
workers: 1,
/* Reporter to use. See https://playwright.dev/docs/test-reporters */
reporter: 'html',
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
use: {
baseURL: process.env.PLUGIN_BASE_URL || 'http://localhost:3000',
/* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
trace: 'on-first-retry',
screenshot: 'only-on-failure',
video: 'retain-on-failure',
},

/* Configure projects for major browsers */
projects: [
{
name: 'chromium',
use: { ...devices['Desktop Chrome'] },
},
],
});
18 changes: 18 additions & 0 deletions plugins/bulk-import/src/components/BulkImportIcon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import React from 'react';

import { SidebarItem } from '@backstage/core-components';
import { IconComponent } from '@backstage/core-plugin-api';

import LibraryAddOutlinedIcon from '@mui/icons-material/LibraryAddOutlined';

export const BulkImportIcon = () => {
// permission logic

return (
<SidebarItem
text="Bulk import"
to="bulk-import/repositories"
icon={LibraryAddOutlinedIcon as IconComponent}
/>
);
};
16 changes: 16 additions & 0 deletions plugins/bulk-import/src/components/BulkImportPage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import React from 'react';

import { Header, Page, TabbedLayout } from '@backstage/core-components';

import { RepositoriesList } from './Repositories/RepositoriesList';

export const BulkImportPage = () => (
<Page themeId="tool">
<Header title="Bulk import" />
<TabbedLayout>
<TabbedLayout.Route path="/repositories" title="Repositories">
<RepositoriesList />
</TabbedLayout.Route>
</TabbedLayout>
</Page>
);
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import React from 'react';

import { Table } from '@backstage/core-components';

import { makeStyles } from '@material-ui/core';

import { RepositoriesData } from '../../types';
import { columns } from './RepositoriesListColumns';

const useStyles = makeStyles(theme => ({
empty: {
padding: theme.spacing(2),
display: 'flex',
justifyContent: 'center',
},
}));

export const RepositoriesList = () => {
const classes = useStyles();
const data: RepositoriesData[] = [];

return (
<Table
title="Added repositories (0)"
options={{ padding: 'default', search: true, paging: true }}
data={data}
isLoading={false}
columns={columns}
emptyContent={
<div data-testid="repositories-table-empty" className={classes.empty}>
No records found
</div>
}
/>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import React from 'react';

import { Link, TableColumn } from '@backstage/core-components';

import { RepositoriesData } from '../../types';

export const columns: TableColumn<RepositoriesData>[] = [
{
title: 'Name',
field: 'name',
type: 'string',
},
{
title: 'Repo URL',
field: 'repoURL',
type: 'string',
align: 'left',
render: (props: RepositoriesData) => {
return <Link to={props.repoURL}>{props.repoURL}</Link>;
},
},
{
title: 'Organization',
field: 'organization',
type: 'string',
align: 'left',
render: (props: RepositoriesData) => {
return <Link to={props.organization}>{props.organization}</Link>;
},
},
{
title: 'Status',
field: 'status',
type: 'string',
align: 'left',
},
{
title: 'Last updated',
field: 'lastUpdated',
type: 'string',
align: 'left',
},
];
14 changes: 14 additions & 0 deletions plugins/bulk-import/src/components/Router.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import React from 'react';
import { Route, Routes } from 'react-router-dom';

import { BulkImportPage } from '../plugin';

/**
*
* @public
*/
export const Router = () => (
<Routes>
<Route path="/repositories" element={<BulkImportPage />} />
</Routes>
);
3 changes: 3 additions & 0 deletions plugins/bulk-import/src/components/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export { BulkImportPage } from './BulkImportPage';
export { BulkImportIcon } from './BulkImportIcon';
export { Router } from './Router';
3 changes: 3 additions & 0 deletions plugins/bulk-import/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export { bulkImportPlugin, BulkImportPage, BulkImportIcon } from './plugin';

export { default as LibraryAddOutlinedIcon } from '@mui/icons-material/LibraryAddOutlined';
7 changes: 7 additions & 0 deletions plugins/bulk-import/src/plugin.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { bulkImportPlugin } from './plugin';

describe('bulk-import', () => {
it('should export plugin', () => {
expect(bulkImportPlugin).toBeDefined();
});
});
31 changes: 31 additions & 0 deletions plugins/bulk-import/src/plugin.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import {
createComponentExtension,
createPlugin,
createRoutableExtension,
} from '@backstage/core-plugin-api';

import { rootRouteRef } from './routes';

export const bulkImportPlugin = createPlugin({
id: 'bulk-import',
routes: {
root: rootRouteRef,
},
});

export const BulkImportPage = bulkImportPlugin.provide(
createRoutableExtension({
name: 'BulkImportPage',
component: () => import('./components').then(m => m.BulkImportPage),
mountPoint: rootRouteRef,
}),
);

export const BulkImportIcon = bulkImportPlugin.provide(
createComponentExtension({
name: 'BulkImportIcon',
component: {
lazy: () => import('./components').then(m => m.BulkImportIcon),
},
}),
);
5 changes: 5 additions & 0 deletions plugins/bulk-import/src/routes.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { createRouteRef } from '@backstage/core-plugin-api';

export const rootRouteRef = createRouteRef({
id: 'bulk-import',
});
1 change: 1 addition & 0 deletions plugins/bulk-import/src/setupTests.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
import '@testing-library/jest-dom';
7 changes: 7 additions & 0 deletions plugins/bulk-import/src/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export type RepositoriesData = {
name: string;
repoURL: string;
organization: string;
status: string;
lastUpdated: string;
};
34 changes: 34 additions & 0 deletions plugins/bulk-import/tests/bulkImport.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { expect, Page, test } from '@playwright/test';

test.describe('Bulk import plugin', () => {
let page: Page;

test.beforeAll(async ({ browser }) => {
const context = await browser.newContext();
page = await context.newPage();
await page.goto('/');
await expect(page.getByRole('link', { name: 'Bulk import' })).toBeEnabled({
timeout: 20000,
});
});

test.afterAll(async ({ browser }) => {
await browser.close();
});

test('Repositories tab is shown', async () => {
await expect(page.getByText('Added repositories (0)')).toBeVisible();
const columns = [
'Name',
'Repo URL',
'Organization',
'Status',
'Last Updated',
];
const thead = page.locator('thead');

for (const col of columns) {
await expect(thead.getByText(col)).toBeVisible();
}
});
});
9 changes: 9 additions & 0 deletions plugins/bulk-import/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"extends": "@backstage/cli/config/tsconfig.json",
"include": ["src", "dev", "migrations"],
"exclude": ["node_modules"],
"compilerOptions": {
"outDir": "../../dist-types/plugins/bulk-import",
"rootDir": "."
}
}
Loading

0 comments on commit e03f47f

Please sign in to comment.