feat: Add StackStorm plugin
Signed-off-by: pamelin <pamelin@expediagroup.com>
This commit is contained in:
@@ -118,6 +118,11 @@ proxy:
|
||||
headers:
|
||||
Authorization: 'Api-Token ${DYNATRACE_ACCESS_TOKEN}'
|
||||
|
||||
'/stackstorm':
|
||||
target: https://your.stackstorm.instance.com/api
|
||||
headers:
|
||||
St2-Api-Key: ${ST2_API_KEY}
|
||||
|
||||
organization:
|
||||
name: My Company
|
||||
|
||||
@@ -443,3 +448,6 @@ gocd:
|
||||
|
||||
permission:
|
||||
enabled: true
|
||||
|
||||
stackstorm:
|
||||
webUrl: 'https://your.stackstorm.webui.com'
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
---
|
||||
title: StackStorm
|
||||
author: ExpediaGroup
|
||||
authorUrl: https://github.com/ExpediaGroup
|
||||
category: Automation
|
||||
description: Manage StackStorm workflow executions from within Backstage.
|
||||
documentation: https://github.com/backstage/backstage/tree/master/plugins/stackstorm
|
||||
npmPackageName: '@backstage/plugin-stackstorm'
|
||||
tags:
|
||||
- stackstorm
|
||||
- st2
|
||||
- automation
|
||||
- workflow
|
||||
@@ -56,6 +56,7 @@
|
||||
"@backstage/plugin-sentry": "workspace:^",
|
||||
"@backstage/plugin-shortcuts": "workspace:^",
|
||||
"@backstage/plugin-stack-overflow": "workspace:^",
|
||||
"@backstage/plugin-stackstorm": "workspace:^",
|
||||
"@backstage/plugin-tech-insights": "workspace:^",
|
||||
"@backstage/plugin-tech-radar": "workspace:^",
|
||||
"@backstage/plugin-techdocs": "workspace:^",
|
||||
|
||||
@@ -107,6 +107,7 @@ import { catalogEntityCreatePermission } from '@backstage/plugin-catalog-common'
|
||||
import { PlaylistIndexPage } from '@backstage/plugin-playlist';
|
||||
import { TwoColumnLayout } from './components/scaffolder/customScaffolderLayouts';
|
||||
import { ScoreBoardPage } from '@oriflame/backstage-plugin-score-card';
|
||||
import { StackstormPage } from '@backstage/plugin-stackstorm';
|
||||
|
||||
const app = createApp({
|
||||
apis,
|
||||
@@ -279,6 +280,7 @@ const routes = (
|
||||
<Route path="/apache-airflow" element={<ApacheAirflowPage />} />
|
||||
<Route path="/playlist" element={<PlaylistIndexPage />} />
|
||||
<Route path="/score-board" element={<ScoreBoardPage />} />
|
||||
<Route path="/stackstorm" element={<StackstormPage />} />
|
||||
</FlatRoutes>
|
||||
);
|
||||
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
module.exports = require('@backstage/cli/config/eslint-factory')(__dirname);
|
||||
@@ -0,0 +1,60 @@
|
||||
# StackStorm Plugin
|
||||
|
||||
Welcome to the StackStorm plugin!
|
||||
|
||||
A Backstage integration for the [StackStorm](https://docs.stackstorm.com/overview.html).
|
||||
This plugin allows you to display a list of executions, view execution details,
|
||||
browse installed packs, actions and more.
|
||||
|
||||
## Getting started
|
||||
|
||||
To get started, first you need a running instance of StackStorm.
|
||||
One of the quickest ways is [running StackStorm with Docker](https://docs.stackstorm.com/install/docker.html).
|
||||
|
||||
### Installation
|
||||
|
||||
1. Install the plugin with `yarn` in the root of your Backstage directory
|
||||
|
||||
```bash
|
||||
yarn --cwd packages/app add @backstage/plugin-stackstorm
|
||||
```
|
||||
|
||||
2. Import and use the plugin in `packages/app/src/App.tsx`
|
||||
|
||||
```tsx
|
||||
import { StackstormPage } from '@backstage/plugin-stackstorm';
|
||||
|
||||
const routes = (
|
||||
<FlatRoutes>
|
||||
{/* ...other routes */}
|
||||
<Route path="/stackstorm" element={<StackstormPage />} />
|
||||
</FlatRoutes>
|
||||
```
|
||||
|
||||
### Configuration
|
||||
|
||||
1. Configure `webUrl` for links to the StackStorm Web UI in `app-config.yaml`.
|
||||
|
||||
```yaml
|
||||
stackstorm:
|
||||
webUrl: 'https://your.stackstorm.webui.com'
|
||||
```
|
||||
|
||||
2. Configure `stackstorm` proxy
|
||||
This plugin uses the Backstage proxy to securely communicate with StackStorm API.
|
||||
Add the following to your `app-config.yaml` to enable this configuration:
|
||||
|
||||
```yaml
|
||||
proxy:
|
||||
'/stackstorm':
|
||||
target: https://your.stackstorm.instance.com/api
|
||||
headers:
|
||||
St2-Api-Key: ${ST2_API_KEY}
|
||||
```
|
||||
|
||||
In your production deployment of Backstage, you would also need to ensure that
|
||||
you've set the `ST2_API_KEY` environment variable before starting
|
||||
the backend.
|
||||
|
||||
Read more about how to find or generate this key in the
|
||||
[StackStorm Authentication Documentation](https://docs.stackstorm.com/authentication.html#api-keys).
|
||||
Vendored
+38
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright 2023 The Backstage Authors
|
||||
*
|
||||
* 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 interface Config {
|
||||
stackstorm?: {
|
||||
/**
|
||||
* StackStorm API base url
|
||||
* Used for local testing to bypass CORS
|
||||
* @visibility frontend
|
||||
*/
|
||||
baseUrl?: string;
|
||||
/**
|
||||
* StackStorm API key
|
||||
* Used for local testing to bypass CORS
|
||||
* Do not set this in production deployment
|
||||
* @visibility frontend
|
||||
*/
|
||||
key?: string;
|
||||
/**
|
||||
* StackStorm Web UI url
|
||||
* Used in links to StackStorm web UI
|
||||
* @visibility frontend
|
||||
*/
|
||||
webUrl?: string;
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright 2023 The Backstage Authors
|
||||
*
|
||||
* 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 from 'react';
|
||||
import { createDevApp } from '@backstage/dev-utils';
|
||||
import { stackstormPlugin, StackstormPage } from '../src/plugin';
|
||||
|
||||
createDevApp()
|
||||
.registerPlugin(stackstormPlugin)
|
||||
.addPage({
|
||||
element: <StackstormPage />,
|
||||
title: 'Root Page',
|
||||
path: '/stackstorm',
|
||||
})
|
||||
.render();
|
||||
@@ -0,0 +1,65 @@
|
||||
{
|
||||
"name": "@backstage/plugin-stackstorm",
|
||||
"description": "A Backstage plugin that integrates towards StackStorm",
|
||||
"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"
|
||||
},
|
||||
"homepage": "https://backstage.io",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/backstage/backstage",
|
||||
"directory": "plugins/stackstorm"
|
||||
},
|
||||
"keywords": [
|
||||
"backstage",
|
||||
"stackstorm",
|
||||
"st2"
|
||||
],
|
||||
"scripts": {
|
||||
"start": "backstage-cli package start",
|
||||
"build": "backstage-cli package build",
|
||||
"lint": "backstage-cli package lint",
|
||||
"test": "backstage-cli package test",
|
||||
"clean": "backstage-cli package clean",
|
||||
"prepack": "backstage-cli package prepack",
|
||||
"postpack": "backstage-cli package postpack"
|
||||
},
|
||||
"dependencies": {
|
||||
"@backstage/core-components": "workspace:^",
|
||||
"@backstage/core-plugin-api": "workspace:^",
|
||||
"@backstage/theme": "workspace:^",
|
||||
"@material-ui/core": "^4.12.2",
|
||||
"@material-ui/icons": "^4.9.1",
|
||||
"@material-ui/lab": "^4.0.0-alpha.57",
|
||||
"react-use": "^17.2.4"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^16.13.1 || ^17.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/cli": "workspace:^",
|
||||
"@backstage/core-app-api": "workspace:^",
|
||||
"@backstage/dev-utils": "workspace:^",
|
||||
"@backstage/test-utils": "workspace:^",
|
||||
"@testing-library/jest-dom": "^5.10.1",
|
||||
"@testing-library/react": "^12.1.3",
|
||||
"@testing-library/user-event": "^14.0.0",
|
||||
"@types/node": "*",
|
||||
"cross-fetch": "^3.1.5",
|
||||
"msw": "^0.49.0"
|
||||
},
|
||||
"files": [
|
||||
"dist",
|
||||
"config.d.ts"
|
||||
],
|
||||
"configSchema": "config.d.ts"
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Copyright 2023 The Backstage Authors
|
||||
*
|
||||
* 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 { Action, Execution, Pack, StackStormApi } from './types';
|
||||
import { DiscoveryApi, IdentityApi } from '@backstage/core-plugin-api';
|
||||
|
||||
export class StackStormClient implements StackStormApi {
|
||||
private readonly discoveryApi: DiscoveryApi;
|
||||
private readonly identityApi: IdentityApi;
|
||||
|
||||
constructor({
|
||||
discoveryApi,
|
||||
identityApi,
|
||||
}: {
|
||||
discoveryApi: DiscoveryApi;
|
||||
identityApi: IdentityApi;
|
||||
}) {
|
||||
this.discoveryApi = discoveryApi;
|
||||
this.identityApi = identityApi;
|
||||
}
|
||||
|
||||
private async get<T = any>(input: string): Promise<T> {
|
||||
const { token: idToken } = await this.identityApi.getCredentials();
|
||||
const apiUrl = `${await this.discoveryApi.getBaseUrl('proxy')}/stackstorm`;
|
||||
const response = await fetch(`${apiUrl}${input}`, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
...(idToken && { Authorization: `Bearer ${idToken}` }),
|
||||
},
|
||||
});
|
||||
|
||||
if (!response.ok) throw new Error(`Unable to get data: ${response.status}`);
|
||||
return await response.json();
|
||||
}
|
||||
|
||||
async getExecutions(limit?: number, offset?: number): Promise<Execution[]> {
|
||||
const params = {
|
||||
limit: limit?.toString() || '25',
|
||||
offset: offset?.toString() || '0',
|
||||
include_attributes:
|
||||
'id,status,start_timestamp,action.ref,action.name,rule.ref',
|
||||
parent: 'null',
|
||||
};
|
||||
const path = `/executions?${new URLSearchParams(params)}`;
|
||||
return this.get<Execution[]>(path);
|
||||
}
|
||||
|
||||
async getExecution(id: string): Promise<Execution> {
|
||||
const path = `/executions/${id}`;
|
||||
return this.get<Execution>(path);
|
||||
}
|
||||
|
||||
async getPacks(): Promise<Pack[]> {
|
||||
return this.get<Pack[]>('/packs');
|
||||
}
|
||||
|
||||
async getActions(pack: string): Promise<Action[]> {
|
||||
const params = {
|
||||
include_attributes: 'id,ref,name,pack,description,runner_type',
|
||||
pack: pack,
|
||||
};
|
||||
const path = `/actions?${new URLSearchParams(params)}`;
|
||||
return this.get<Action[]>(path);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright 2023 The Backstage Authors
|
||||
*
|
||||
* 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 { stackStormApiRef } from './types';
|
||||
export type {
|
||||
Action,
|
||||
Execution,
|
||||
ExecutionLog,
|
||||
Pack,
|
||||
StackStormApi,
|
||||
} from './types';
|
||||
export { StackStormClient } from './StackStormClient';
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright 2023 The Backstage Authors
|
||||
*
|
||||
* 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-plugin-api';
|
||||
|
||||
export const stackStormApiRef = createApiRef<StackStormApi>({
|
||||
id: 'plugin.stackstorm.service',
|
||||
});
|
||||
|
||||
export type Execution = {
|
||||
id: string;
|
||||
action: Action;
|
||||
status: string;
|
||||
start_timestamp: Date;
|
||||
end_timestamp: Date;
|
||||
result: object;
|
||||
parameters: object;
|
||||
elapsed_seconds: number;
|
||||
log: ExecutionLog[];
|
||||
};
|
||||
|
||||
export type ExecutionLog = {
|
||||
status: string;
|
||||
timestamp: Date;
|
||||
};
|
||||
|
||||
export type Action = {
|
||||
id: string;
|
||||
name: string;
|
||||
ref: string;
|
||||
pack: string;
|
||||
description: string;
|
||||
runner_type: string;
|
||||
};
|
||||
|
||||
export type Pack = {
|
||||
ref: string;
|
||||
description: string;
|
||||
version: string;
|
||||
};
|
||||
|
||||
export interface StackStormApi {
|
||||
getExecutions(limit: number, offset: number): Promise<Execution[]>;
|
||||
getExecution(id: string): Promise<Execution>;
|
||||
getPacks(): Promise<Pack[]>;
|
||||
getActions(pack: string): Promise<Action[]>;
|
||||
}
|
||||
@@ -0,0 +1,161 @@
|
||||
/*
|
||||
* Copyright 2023 The Backstage Authors
|
||||
*
|
||||
* 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, { useState } from 'react';
|
||||
import useAsync from 'react-use/lib/useAsync';
|
||||
import { Progress } from '@backstage/core-components';
|
||||
import { useApi, configApiRef } from '@backstage/core-plugin-api';
|
||||
import {
|
||||
List,
|
||||
ListItemText,
|
||||
Collapse,
|
||||
ListItem,
|
||||
ListItemSecondaryAction,
|
||||
ListItemIcon,
|
||||
} from '@material-ui/core';
|
||||
import { makeStyles } from '@material-ui/core/styles';
|
||||
import ExpandMore from '@material-ui/icons/ExpandMore';
|
||||
import ExpandLess from '@material-ui/icons/ExpandLess';
|
||||
import { Alert } from '@material-ui/lab';
|
||||
import { Action, Pack, stackStormApiRef } from '../../api';
|
||||
|
||||
const useStyles = makeStyles(theme => ({
|
||||
root: {
|
||||
width: '100%',
|
||||
backgroundColor: theme.palette.background.paper,
|
||||
},
|
||||
actions: {
|
||||
borderBottom: `2px solid ${theme.palette.divider}`,
|
||||
},
|
||||
nested: {
|
||||
paddingLeft: theme.spacing(8),
|
||||
paddingRight: theme.spacing(4),
|
||||
},
|
||||
icon: {
|
||||
minWidth: '34px',
|
||||
},
|
||||
}));
|
||||
|
||||
type ActionItemsProps = {
|
||||
pack: Pack;
|
||||
};
|
||||
|
||||
export const ActionItems = ({ pack }: ActionItemsProps) => {
|
||||
const classes = useStyles();
|
||||
const st2 = useApi(stackStormApiRef);
|
||||
const config = useApi(configApiRef);
|
||||
|
||||
const { value, loading, error } = useAsync(async (): Promise<Action[]> => {
|
||||
const data = await st2.getActions(pack.ref);
|
||||
return data;
|
||||
}, []);
|
||||
|
||||
if (loading) {
|
||||
return <Progress />;
|
||||
} else if (error) {
|
||||
return <Alert severity="error">{error.message}</Alert>;
|
||||
}
|
||||
|
||||
return (
|
||||
<List component="div" disablePadding className={classes.actions}>
|
||||
{(value || []).map(a => {
|
||||
return (
|
||||
<ListItem
|
||||
button
|
||||
className={classes.nested}
|
||||
onClick={() =>
|
||||
window.open(
|
||||
`${config.getString('stackstorm.webUrl')}/?#/actions/${a.ref}`,
|
||||
'_blank',
|
||||
)
|
||||
}
|
||||
>
|
||||
<ListItemText primary={a.name} secondary={a.description} />
|
||||
<ListItemSecondaryAction>{a.runner_type}</ListItemSecondaryAction>
|
||||
</ListItem>
|
||||
);
|
||||
})}
|
||||
</List>
|
||||
);
|
||||
};
|
||||
|
||||
type PackListItemProps = {
|
||||
pack: Pack;
|
||||
opened: boolean;
|
||||
onClick: (ref: string) => any;
|
||||
};
|
||||
|
||||
export const PackListItem = ({ pack, opened, onClick }: PackListItemProps) => {
|
||||
const classes = useStyles();
|
||||
|
||||
return (
|
||||
<>
|
||||
<ListItem button onClick={() => onClick(pack.ref)}>
|
||||
<ListItemIcon className={classes.icon}>
|
||||
{opened ? <ExpandLess /> : <ExpandMore />}
|
||||
</ListItemIcon>
|
||||
<ListItemText primary={pack.ref} secondary={pack.description} />
|
||||
<ListItemSecondaryAction>
|
||||
version: {pack.version}
|
||||
</ListItemSecondaryAction>
|
||||
</ListItem>
|
||||
<Collapse in={opened} timeout="auto" unmountOnExit>
|
||||
<ActionItems pack={pack} />
|
||||
</Collapse>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export const ActionsList = () => {
|
||||
const st2 = useApi(stackStormApiRef);
|
||||
|
||||
const classes = useStyles();
|
||||
const [expanded, setExpanded] = useState<string[]>([]);
|
||||
|
||||
const onClick = (ref: string) => {
|
||||
setExpanded(refs =>
|
||||
refs.includes(ref) ? refs.filter(r => r !== ref) : refs.concat(ref),
|
||||
);
|
||||
};
|
||||
|
||||
const { value, loading, error } = useAsync(async (): Promise<Pack[]> => {
|
||||
const data = await st2.getPacks();
|
||||
return data;
|
||||
}, []);
|
||||
|
||||
if (loading) {
|
||||
return <Progress />;
|
||||
} else if (error) {
|
||||
return <Alert severity="error">{error.message}</Alert>;
|
||||
}
|
||||
|
||||
return (
|
||||
<List
|
||||
component="nav"
|
||||
aria-labelledby="nested-list-subheader"
|
||||
className={classes.root}
|
||||
>
|
||||
{(value || []).map(p => {
|
||||
return (
|
||||
<PackListItem
|
||||
pack={p}
|
||||
opened={expanded.includes(p.ref)}
|
||||
onClick={onClick}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</List>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,16 @@
|
||||
/*
|
||||
* Copyright 2023 The Backstage Authors
|
||||
*
|
||||
* 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 { ActionsList } from './ActionsList';
|
||||
@@ -0,0 +1,165 @@
|
||||
/*
|
||||
* Copyright 2023 The Backstage Authors
|
||||
*
|
||||
* 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 from 'react';
|
||||
import { CodeSnippet, Progress } from '@backstage/core-components';
|
||||
import { configApiRef, useApi } from '@backstage/core-plugin-api';
|
||||
import { Execution, stackStormApiRef } from '../../api';
|
||||
import useAsync from 'react-use/lib/useAsync';
|
||||
import { Alert } from '@material-ui/lab';
|
||||
import {
|
||||
Button,
|
||||
Card,
|
||||
CardActions,
|
||||
CardContent,
|
||||
makeStyles,
|
||||
Table,
|
||||
TableBody,
|
||||
TableCell,
|
||||
TableRow,
|
||||
Typography,
|
||||
withStyles,
|
||||
} from '@material-ui/core';
|
||||
import { Status } from './Status';
|
||||
|
||||
const useStyles = makeStyles(theme => ({
|
||||
table: {
|
||||
maxWidth: '50%',
|
||||
flex: 'i',
|
||||
},
|
||||
title: {
|
||||
paddingTop: theme.spacing(2),
|
||||
fontSize: 14,
|
||||
fontWeight: 'bold',
|
||||
textTransform: 'uppercase',
|
||||
},
|
||||
card: {
|
||||
borderBottom: `2px solid ${theme.palette.divider}`,
|
||||
},
|
||||
}));
|
||||
|
||||
const THead = withStyles(() => ({
|
||||
root: {
|
||||
paddingLeft: 0,
|
||||
},
|
||||
}))(TableCell);
|
||||
|
||||
const TRow = withStyles(theme => ({
|
||||
root: {
|
||||
'&:nth-of-type(odd)': {
|
||||
backgroundColor: theme.palette.background.paper,
|
||||
},
|
||||
},
|
||||
}))(TableRow);
|
||||
|
||||
const ExecutionCard = ({ e }: { e: Execution }) => {
|
||||
const config = useApi(configApiRef);
|
||||
const classes = useStyles();
|
||||
|
||||
const webUrl = `${config.getString('stackstorm.webUrl')}/?#/history/${e.id}`;
|
||||
|
||||
return (
|
||||
<Card className={classes.card}>
|
||||
<CardContent>
|
||||
<Table className={classes.table} size="small">
|
||||
<TableBody>
|
||||
<TRow>
|
||||
<THead component="th" scope="row">
|
||||
Name
|
||||
</THead>
|
||||
<TableCell>{e.action.ref}</TableCell>
|
||||
</TRow>
|
||||
<TRow>
|
||||
<THead component="th" scope="row">
|
||||
Status
|
||||
</THead>
|
||||
<TableCell>
|
||||
<Status status={e.status} />
|
||||
</TableCell>
|
||||
</TRow>
|
||||
<TRow>
|
||||
<THead component="th" scope="row">
|
||||
Execution ID
|
||||
</THead>
|
||||
<TableCell>{e.id}</TableCell>
|
||||
</TRow>
|
||||
<TRow>
|
||||
<THead component="th" scope="row">
|
||||
Started
|
||||
</THead>
|
||||
<TableCell>{new Date(e.start_timestamp).toUTCString()}</TableCell>
|
||||
</TRow>
|
||||
<TRow>
|
||||
<THead component="th" scope="row">
|
||||
Finished
|
||||
</THead>
|
||||
<TableCell>{new Date(e.end_timestamp).toUTCString()}</TableCell>
|
||||
</TRow>
|
||||
<TRow>
|
||||
<THead component="th" scope="row">
|
||||
Execution Time
|
||||
</THead>
|
||||
<TableCell>{Math.round(e.elapsed_seconds)} s</TableCell>
|
||||
</TRow>
|
||||
<TRow>
|
||||
<THead component="th" scope="row">
|
||||
Runner
|
||||
</THead>
|
||||
<TableCell>{e.action.runner_type}</TableCell>
|
||||
</TRow>
|
||||
</TableBody>
|
||||
</Table>
|
||||
<Typography className={classes.title} gutterBottom>
|
||||
Action Output
|
||||
</Typography>
|
||||
<CodeSnippet
|
||||
text={JSON.stringify(e.result, null, 2)}
|
||||
language="json"
|
||||
customStyle={{ width: 800 }}
|
||||
/>
|
||||
<Typography className={classes.title} gutterBottom>
|
||||
Action Input
|
||||
</Typography>
|
||||
<CodeSnippet
|
||||
text={JSON.stringify(e.parameters, null, 2)}
|
||||
language="json"
|
||||
customStyle={{ width: 800 }}
|
||||
/>
|
||||
</CardContent>
|
||||
<CardActions>
|
||||
<Button size="small" href={webUrl} target="_blank">
|
||||
View in ST2
|
||||
</Button>
|
||||
</CardActions>
|
||||
</Card>
|
||||
);
|
||||
};
|
||||
|
||||
export const ExecutionPanel = ({ id }: { id: string }) => {
|
||||
const st2 = useApi(stackStormApiRef);
|
||||
|
||||
const { value, loading, error } = useAsync(async (): Promise<Execution> => {
|
||||
const data = await st2.getExecution(id);
|
||||
return data;
|
||||
}, []);
|
||||
|
||||
if (loading) {
|
||||
return <Progress />;
|
||||
} else if (error) {
|
||||
return <Alert severity="error">{error.message}</Alert>;
|
||||
}
|
||||
|
||||
return <ExecutionCard e={value!} />;
|
||||
};
|
||||
@@ -0,0 +1,130 @@
|
||||
/*
|
||||
* Copyright 2023 The Backstage Authors
|
||||
*
|
||||
* 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, { useEffect, useState } from 'react';
|
||||
import { Link, Table, TableColumn } from '@backstage/core-components';
|
||||
import { useApi, configApiRef, errorApiRef } from '@backstage/core-plugin-api';
|
||||
import { Execution, stackStormApiRef } from '../../api';
|
||||
import { Status } from './Status';
|
||||
import { ExecutionPanel } from './ExecutionPanel';
|
||||
|
||||
type DenseTableProps = {
|
||||
executions: Execution[];
|
||||
loading: boolean;
|
||||
page: number;
|
||||
pageSize: number;
|
||||
onPageChange: (page: number) => void;
|
||||
onRowsPerPageChange: (rows: number) => void;
|
||||
};
|
||||
|
||||
export const DenseTable = ({
|
||||
executions,
|
||||
loading,
|
||||
page,
|
||||
pageSize,
|
||||
onPageChange,
|
||||
onRowsPerPageChange,
|
||||
}: DenseTableProps) => {
|
||||
const config = useApi(configApiRef);
|
||||
|
||||
const columns: TableColumn<Execution>[] = [
|
||||
{
|
||||
title: 'Status',
|
||||
field: 'status',
|
||||
render: e => <Status status={e.status} />,
|
||||
},
|
||||
{
|
||||
title: 'Time',
|
||||
field: 'start_timestamp',
|
||||
render: e => `${new Date(e.start_timestamp).toUTCString()}`,
|
||||
},
|
||||
{ title: 'Name', field: 'action.ref' },
|
||||
{
|
||||
title: 'Execution ID',
|
||||
field: 'id',
|
||||
render: e => (
|
||||
<Link
|
||||
to={`${config.getString('stackstorm.webUrl')}/?#/history/${e.id}`}
|
||||
>
|
||||
{e.id}
|
||||
</Link>
|
||||
),
|
||||
},
|
||||
];
|
||||
|
||||
const count =
|
||||
pageSize > executions.length
|
||||
? (page + 1) * pageSize + executions.length - pageSize
|
||||
: (page + 1) * pageSize + 1;
|
||||
|
||||
return (
|
||||
<Table
|
||||
title="Executions"
|
||||
columns={columns}
|
||||
data={executions}
|
||||
page={page}
|
||||
totalCount={count}
|
||||
isLoading={loading}
|
||||
options={{
|
||||
paging: true,
|
||||
search: false,
|
||||
pageSize: pageSize,
|
||||
padding: 'dense',
|
||||
showFirstLastPageButtons: false,
|
||||
}}
|
||||
onPageChange={onPageChange}
|
||||
onRowsPerPageChange={onRowsPerPageChange}
|
||||
detailPanel={rowData => {
|
||||
return <ExecutionPanel id={rowData.rowData.id} />;
|
||||
}}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export const ExecutionsTable = () => {
|
||||
const st2 = useApi(stackStormApiRef);
|
||||
const errorApi = useApi(errorApiRef);
|
||||
const [page, setPage] = useState(0);
|
||||
const [rowsPerPage, setRowsPerPage] = useState(10);
|
||||
const [data, setData] = useState<Execution[]>([]);
|
||||
const [loading, setLoading] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
const getData = async () => {
|
||||
setLoading(true);
|
||||
await st2
|
||||
.getExecutions(rowsPerPage, page * rowsPerPage)
|
||||
.then(d => {
|
||||
setData(d);
|
||||
})
|
||||
.catch(err => {
|
||||
errorApi.post(err);
|
||||
});
|
||||
setLoading(false);
|
||||
};
|
||||
getData();
|
||||
}, [errorApi, page, rowsPerPage, st2]);
|
||||
|
||||
return (
|
||||
<DenseTable
|
||||
page={page}
|
||||
pageSize={rowsPerPage}
|
||||
loading={loading}
|
||||
executions={data}
|
||||
onRowsPerPageChange={setRowsPerPage}
|
||||
onPageChange={setPage}
|
||||
/>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright 2023 The Backstage Authors
|
||||
*
|
||||
* 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 {
|
||||
StatusOK,
|
||||
StatusError,
|
||||
StatusRunning,
|
||||
StatusWarning,
|
||||
} from '@backstage/core-components';
|
||||
import React from 'react';
|
||||
|
||||
export const Status = ({ status }: { status: string | undefined }) => {
|
||||
if (status === undefined) return null;
|
||||
const st = status.toLocaleLowerCase('en-US');
|
||||
switch (status) {
|
||||
case 'succeeded':
|
||||
case 'enabled':
|
||||
case 'complete':
|
||||
return (
|
||||
<>
|
||||
<StatusOK /> {st}
|
||||
</>
|
||||
);
|
||||
case 'scheduled':
|
||||
case 'running':
|
||||
return (
|
||||
<>
|
||||
<StatusRunning /> {st}
|
||||
</>
|
||||
);
|
||||
case 'failed':
|
||||
case 'error':
|
||||
return (
|
||||
<>
|
||||
<StatusError /> {st}
|
||||
</>
|
||||
);
|
||||
default:
|
||||
return (
|
||||
<>
|
||||
<StatusWarning /> {st}
|
||||
</>
|
||||
);
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,16 @@
|
||||
/*
|
||||
* Copyright 2023 The Backstage Authors
|
||||
*
|
||||
* 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 { ExecutionsTable } from './ExecutionsTable';
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright 2023 The Backstage Authors
|
||||
*
|
||||
* 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 from 'react';
|
||||
import { Progress, Table, TableColumn } from '@backstage/core-components';
|
||||
import { Alert } from '@material-ui/lab';
|
||||
import useAsync from 'react-use/lib/useAsync';
|
||||
import { useApi } from '@backstage/core-plugin-api';
|
||||
import { Pack, stackStormApiRef } from '../../api';
|
||||
|
||||
type DenseTableProps = {
|
||||
packs: Pack[];
|
||||
};
|
||||
|
||||
export const DenseTable = ({ packs }: DenseTableProps) => {
|
||||
const columns: TableColumn[] = [
|
||||
{ title: 'Name', field: 'ref' },
|
||||
{ title: 'Description', field: 'description' },
|
||||
{ title: 'Version', field: 'version' },
|
||||
];
|
||||
|
||||
return (
|
||||
<Table
|
||||
title="Packs"
|
||||
options={{ search: true, paging: false }}
|
||||
columns={columns}
|
||||
data={packs}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export const PacksTable = () => {
|
||||
const st2 = useApi(stackStormApiRef);
|
||||
|
||||
const { value, loading, error } = useAsync(async (): Promise<Pack[]> => {
|
||||
const data = await st2.getPacks();
|
||||
return data;
|
||||
}, []);
|
||||
|
||||
if (loading) {
|
||||
return <Progress />;
|
||||
} else if (error) {
|
||||
return <Alert severity="error">{error.message}</Alert>;
|
||||
}
|
||||
|
||||
return <DenseTable packs={value || []} />;
|
||||
};
|
||||
@@ -0,0 +1,16 @@
|
||||
/*
|
||||
* Copyright 2023 The Backstage Authors
|
||||
*
|
||||
* 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 { PacksTable } from './PacksTable';
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright 2023 The Backstage Authors
|
||||
*
|
||||
* 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 from 'react';
|
||||
import { StackStormHome } from './StackStormHome';
|
||||
import { screen } from '@testing-library/react';
|
||||
import { renderInTestApp, TestApiProvider } from '@backstage/test-utils';
|
||||
import { StackStormApi, stackStormApiRef } from '../../api';
|
||||
|
||||
describe('StackStormHome', () => {
|
||||
const mockApi: jest.Mocked<StackStormApi> = {
|
||||
getExecutions: jest.fn().mockResolvedValue([]),
|
||||
getExecution: jest.fn().mockResolvedValue({}),
|
||||
getPacks: jest.fn().mockResolvedValue([]),
|
||||
getActions: jest.fn().mockResolvedValue([]),
|
||||
} as any;
|
||||
|
||||
it('should render', async () => {
|
||||
await renderInTestApp(
|
||||
<TestApiProvider apis={[[stackStormApiRef, mockApi]]}>
|
||||
<StackStormHome />
|
||||
</TestApiProvider>,
|
||||
);
|
||||
expect(screen.getByText('Welcome to StackStorm!')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright 2023 The Backstage Authors
|
||||
*
|
||||
* 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 from 'react';
|
||||
import { Grid, IconButton } from '@material-ui/core';
|
||||
import {
|
||||
Header,
|
||||
Page,
|
||||
HeaderLabel,
|
||||
TabbedLayout,
|
||||
Content,
|
||||
} from '@backstage/core-components';
|
||||
import LibraryBooks from '@material-ui/icons/LibraryBooks';
|
||||
import { ExecutionsTable } from '../ExecutionsTable';
|
||||
import { PacksTable } from '../PacksTable/PacksTable';
|
||||
import { ActionsList } from '../ActionsList';
|
||||
|
||||
export const StackStormHome = () => (
|
||||
<Page themeId="tool">
|
||||
<Header title="Welcome to StackStorm!" subtitle="Event-driven automation">
|
||||
<IconButton aria-label="Docs" href="https://docs.stackstorm.com/">
|
||||
<LibraryBooks htmlColor="white" />
|
||||
</IconButton>
|
||||
<HeaderLabel label="Lifecycle" value="Alpha" />
|
||||
</Header>
|
||||
<TabbedLayout>
|
||||
<TabbedLayout.Route path="/history" title="Executions">
|
||||
<Content noPadding>
|
||||
<Grid container spacing={3} direction="column">
|
||||
<Grid>
|
||||
<ExecutionsTable />
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Content>
|
||||
</TabbedLayout.Route>
|
||||
<TabbedLayout.Route path="/packs" title="Packs">
|
||||
<Content noPadding>
|
||||
<Grid container spacing={3} direction="column">
|
||||
<Grid item>
|
||||
<PacksTable />
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Content>
|
||||
</TabbedLayout.Route>
|
||||
<TabbedLayout.Route path="/actions" title="Actions">
|
||||
<Content noPadding>
|
||||
<Grid container spacing={3} direction="column">
|
||||
<Grid item>
|
||||
<ActionsList />
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Content>
|
||||
</TabbedLayout.Route>
|
||||
</TabbedLayout>
|
||||
</Page>
|
||||
);
|
||||
@@ -0,0 +1,16 @@
|
||||
/*
|
||||
* Copyright 2023 The Backstage Authors
|
||||
*
|
||||
* 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 { StackStormHome } from './StackStormHome';
|
||||
@@ -0,0 +1,16 @@
|
||||
/*
|
||||
* Copyright 2023 The Backstage Authors
|
||||
*
|
||||
* 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 { stackstormPlugin, StackstormPage } from './plugin';
|
||||
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* Copyright 2023 The Backstage Authors
|
||||
*
|
||||
* 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 { stackstormPlugin } from './plugin';
|
||||
|
||||
describe('stackstorm', () => {
|
||||
it('should export plugin', () => {
|
||||
expect(stackstormPlugin).toBeDefined();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright 2023 The Backstage Authors
|
||||
*
|
||||
* 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 {
|
||||
createApiFactory,
|
||||
createPlugin,
|
||||
createRoutableExtension,
|
||||
discoveryApiRef,
|
||||
identityApiRef,
|
||||
} from '@backstage/core-plugin-api';
|
||||
import { stackStormApiRef, StackStormClient } from './api';
|
||||
|
||||
import { rootRouteRef } from './routes';
|
||||
|
||||
export const stackstormPlugin = createPlugin({
|
||||
id: 'stackstorm',
|
||||
apis: [
|
||||
createApiFactory({
|
||||
api: stackStormApiRef,
|
||||
deps: {
|
||||
discoveryApi: discoveryApiRef,
|
||||
identityApi: identityApiRef,
|
||||
},
|
||||
factory: ({ discoveryApi, identityApi }) =>
|
||||
new StackStormClient({
|
||||
discoveryApi,
|
||||
identityApi,
|
||||
}),
|
||||
}),
|
||||
],
|
||||
routes: {
|
||||
root: rootRouteRef,
|
||||
},
|
||||
});
|
||||
|
||||
export const StackstormPage = stackstormPlugin.provide(
|
||||
createRoutableExtension({
|
||||
name: 'StackstormPage',
|
||||
component: () =>
|
||||
import('./components/StackStormHome').then(m => m.StackStormHome),
|
||||
mountPoint: rootRouteRef,
|
||||
}),
|
||||
);
|
||||
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright 2023 The Backstage Authors
|
||||
*
|
||||
* 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 { createRouteRef } from '@backstage/core-plugin-api';
|
||||
|
||||
export const rootRouteRef = createRouteRef({
|
||||
id: 'stackstorm',
|
||||
});
|
||||
@@ -0,0 +1,17 @@
|
||||
/*
|
||||
* Copyright 2023 The Backstage Authors
|
||||
*
|
||||
* 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';
|
||||
import 'cross-fetch/polyfill';
|
||||
@@ -7955,6 +7955,32 @@ __metadata:
|
||||
languageName: unknown
|
||||
linkType: soft
|
||||
|
||||
"@backstage/plugin-stackstorm@workspace:^, @backstage/plugin-stackstorm@workspace:plugins/stackstorm":
|
||||
version: 0.0.0-use.local
|
||||
resolution: "@backstage/plugin-stackstorm@workspace:plugins/stackstorm"
|
||||
dependencies:
|
||||
"@backstage/cli": "workspace:^"
|
||||
"@backstage/core-app-api": "workspace:^"
|
||||
"@backstage/core-components": "workspace:^"
|
||||
"@backstage/core-plugin-api": "workspace:^"
|
||||
"@backstage/dev-utils": "workspace:^"
|
||||
"@backstage/test-utils": "workspace:^"
|
||||
"@backstage/theme": "workspace:^"
|
||||
"@material-ui/core": ^4.12.2
|
||||
"@material-ui/icons": ^4.9.1
|
||||
"@material-ui/lab": ^4.0.0-alpha.57
|
||||
"@testing-library/jest-dom": ^5.10.1
|
||||
"@testing-library/react": ^12.1.3
|
||||
"@testing-library/user-event": ^14.0.0
|
||||
"@types/node": "*"
|
||||
cross-fetch: ^3.1.5
|
||||
msw: ^0.49.0
|
||||
react-use: ^17.2.4
|
||||
peerDependencies:
|
||||
react: ^16.13.1 || ^17.0.0
|
||||
languageName: unknown
|
||||
linkType: soft
|
||||
|
||||
"@backstage/plugin-tech-insights-backend-module-jsonfc@workspace:^, @backstage/plugin-tech-insights-backend-module-jsonfc@workspace:plugins/tech-insights-backend-module-jsonfc":
|
||||
version: 0.0.0-use.local
|
||||
resolution: "@backstage/plugin-tech-insights-backend-module-jsonfc@workspace:plugins/tech-insights-backend-module-jsonfc"
|
||||
@@ -22492,6 +22518,7 @@ __metadata:
|
||||
"@backstage/plugin-sentry": "workspace:^"
|
||||
"@backstage/plugin-shortcuts": "workspace:^"
|
||||
"@backstage/plugin-stack-overflow": "workspace:^"
|
||||
"@backstage/plugin-stackstorm": "workspace:^"
|
||||
"@backstage/plugin-tech-insights": "workspace:^"
|
||||
"@backstage/plugin-tech-radar": "workspace:^"
|
||||
"@backstage/plugin-techdocs": "workspace:^"
|
||||
|
||||
Reference in New Issue
Block a user