rename azure-functions to azure-sites

add drop down for actions
show kind on table

Signed-off-by: Wesley Pattison <wesley.pattison@friss.com>
This commit is contained in:
Wesley Pattison
2022-10-09 19:08:39 +02:00
parent 89d1a0b9eb
commit 86cf4307c8
44 changed files with 513 additions and 185 deletions
+4 -4
View File
@@ -1,7 +1,7 @@
---
'@backstage/plugin-azure-functions': minor
'@backstage/plugin-azure-functions-backend': minor
'@backstage/plugin-azure-functions-common': minor
'@backstage/plugin-azure-sites': minor
'@backstage/plugin-azure-sites-backend': minor
'@backstage/plugin-azure-sites-common': minor
---
Basic Azure Functions support for a given entity. View the current status of the function app, quickly jump to Function's Overview page, or Log Stream page.
Azure Sites (Apps & Functions) support for a given entity. View the current status of the site, quickly jump to site's Overview page, or Log Stream page.
@@ -4,6 +4,6 @@ author: FRISS
authorUrl: https://friss.com
category: Infrastructure
description: View related Azure information for your components in Backstage.
documentation: https://github.com/backstage/backstage/tree/master/plugins/azure-functions
iconUrl: img/azurefunctions-icon.svg
npmPackageName: '@backstage/plugin-azure-functions'
documentation: https://github.com/backstage/backstage/tree/master/plugins/azure-sites
iconUrl: img/azure-icon.svg
npmPackageName: '@backstage/plugin-azure-sites'
+1 -1
View File
@@ -19,7 +19,7 @@
"@backstage/plugin-apache-airflow": "workspace:^",
"@backstage/plugin-api-docs": "workspace:^",
"@backstage/plugin-azure-devops": "workspace:^",
"@backstage/plugin-azure-functions": "workspace:^",
"@backstage/plugin-azure-sites": "workspace:^",
"@backstage/plugin-badges": "workspace:^",
"@backstage/plugin-catalog-common": "workspace:^",
"@backstage/plugin-catalog-graph": "workspace:^",
+1 -1
View File
@@ -36,7 +36,7 @@
"@backstage/plugin-auth-backend": "workspace:^",
"@backstage/plugin-auth-node": "workspace:^",
"@backstage/plugin-azure-devops-backend": "workspace:^",
"@backstage/plugin-azure-functions-backend": "workspace:^",
"@backstage/plugin-azure-sites-backend": "workspace:^",
"@backstage/plugin-badges-backend": "workspace:^",
"@backstage/plugin-catalog-backend": "workspace:^",
"@backstage/plugin-code-coverage-backend": "workspace:^",
@@ -1,125 +0,0 @@
/*
* Copyright 2022 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 { Box, Card, Link, LinearProgress } from '@material-ui/core';
import { AzureSite } from '@backstage/plugin-azure-functions-common';
import { Table, TableColumn } from '@backstage/core-components';
import FlashOnIcon from '@material-ui/icons/FlashOn';
import { DateTime } from 'luxon';
type States = 'Waiting' | 'Running' | 'Paused' | 'Failed';
const State = ({ value }: { value: States }) => {
const colorMap = {
Waiting: '#dcbc21',
Running: 'green',
Paused: 'black',
Failed: 'red',
};
return (
<Box display="flex" alignItems="center">
<span
style={{
display: 'block',
width: '8px',
height: '8px',
borderRadius: '50%',
backgroundColor: colorMap[value],
marginRight: '5px',
}}
/>
{value}
</Box>
);
};
type TableProps = {
data: AzureSite[];
loading: boolean;
};
const DEFAULT_COLUMNS: TableColumn<AzureSite>[] = [
{
title: 'name',
highlight: true,
render: (func: AzureSite) => {
return (
<Link href={func.href} target="_blank">
{func.name}
</Link>
);
},
},
{
title: 'kind',
render: (func: AzureSite) => func.kind ?? 'unknown',
},
{
title: 'location',
render: (func: AzureSite) => func.location ?? 'unknown',
},
{
title: 'status',
render: (func: AzureSite) => <State value={func.state as States} />,
},
{
title: 'last modified',
render: (func: AzureSite) =>
DateTime.fromISO(func.lastModifiedDate).toLocaleString(
DateTime.DATETIME_MED,
),
},
{
title: 'logs',
align: 'right',
render: (func: AzureSite) => {
return (
<Link href={func.logstreamHref} target="_blank">
View Logs
</Link>
);
},
},
];
/** @public */
export const AzureSitesOverviewTable = ({ data, loading }: TableProps) => {
const columns: TableColumn<AzureSite>[] = [...DEFAULT_COLUMNS];
const tableStyle = {
minWidth: '0',
width: '100%',
};
return (
<Card style={tableStyle}>
<Table
title={
<Box display="flex" alignItems="center">
<FlashOnIcon style={{ fontSize: 30 }} />
<Box mr={1} />
Azure Sites
</Box>
}
options={{ paging: true, search: false, pageSize: 10 }}
data={data}
emptyContent={<LinearProgress />}
isLoading={loading}
columns={columns}
/>
</Card>
);
};
@@ -33,11 +33,11 @@ Configuration Details:
Here's how to get the backend plugin up and running:
1. First we need to add the `@backstage/plugin-azure-functions-backend` package to your backend:
1. First we need to add the `@backstage/plugin-azure-sites-backend` package to your backend:
```sh
# From the Backstage root directory
yarn add --cwd packages/backend @backstage/plugin-azure-functions-backend
yarn add --cwd packages/backend @backstage/plugin-azure-sites-backend
```
2. Then we will create a new file named `packages/backend/src/plugins/azure.ts`, and add the following to it:
@@ -46,7 +46,7 @@ Here's how to get the backend plugin up and running:
import {
createRouter,
AzureSitesApi,
} from '@backstage/plugin-azure-functions-backend';
} from '@backstage/plugin-azure-sites-backend';
import { Router } from 'express';
import { PluginEnvironment } from '../types';
@@ -1,10 +1,11 @@
## API Report File for "@backstage/plugin-azure-functions-backend"
## API Report File for "@backstage/plugin-azure-sites-backend"
> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/).
```ts
import { AzureSiteListRequest } from '@backstage/plugin-azure-functions-common';
import { AzureSiteListResponse } from '@backstage/plugin-azure-functions-common';
import { AzureSiteListRequest } from '@backstage/plugin-azure-sites-common';
import { AzureSiteListResponse } from '@backstage/plugin-azure-sites-common';
import { AzureSiteStartStopRequest } from '@backstage/plugin-azure-sites-common';
import { Config } from '@backstage/config';
import express from 'express';
import { Logger } from 'winston';
@@ -39,6 +40,10 @@ export class AzureSitesApi {
static fromConfig(config: Config): AzureSitesApi;
// (undocumented)
list(request: AzureSiteListRequest): Promise<AzureSiteListResponse>;
// (undocumented)
start(request: AzureSiteStartStopRequest): Promise<void>;
// (undocumented)
stop(request: AzureSiteStartStopRequest): Promise<void>;
}
// @public (undocumented)
@@ -1,5 +1,5 @@
{
"name": "@backstage/plugin-azure-functions-backend",
"name": "@backstage/plugin-azure-sites-backend",
"version": "0.0.0",
"main": "src/index.ts",
"types": "src/index.ts",
@@ -17,7 +17,7 @@
"repository": {
"type": "git",
"url": "https://github.com/backstage/backstage",
"directory": "plugins/azure-functions-backend"
"directory": "plugins/azure-sites-backend"
},
"keywords": [
"backstage",
@@ -33,11 +33,12 @@
"postpack": "backstage-cli package postpack"
},
"dependencies": {
"@azure/arm-appservice": "^13.0.1",
"@azure/arm-resourcegraph": "^4.2.1",
"@azure/identity": "^2.1.0",
"@backstage/backend-common": "workspace:^",
"@backstage/config": "workspace:^",
"@backstage/plugin-azure-functions-common": "workspace:^",
"@backstage/plugin-azure-sites-common": "workspace:^",
"@types/express": "^4.17.6",
"express": "^4.17.1",
"express-promise-router": "^4.1.0",
@@ -20,11 +20,13 @@ import {
ClientSecretCredential,
} from '@azure/identity';
import { ResourceGraphClient } from '@azure/arm-resourcegraph';
import { WebSiteManagementClient } from '@azure/arm-appservice';
import {
AzureSite,
AzureSiteListRequest,
AzureSiteListResponse,
} from '@backstage/plugin-azure-functions-common';
AzureSiteStartStopRequest,
} from '@backstage/plugin-azure-sites-common';
import { AzureFunctionsConfig } from '../config';
/** @public */
@@ -34,22 +36,41 @@ export class AzureSitesApi {
private readonly client: ResourceGraphClient;
constructor(private readonly config: AzureFunctionsConfig) {
const creds =
config.clientId && config.clientSecret
? new ClientSecretCredential(
config.tenantId,
config.clientId,
config.clientSecret,
)
: new DefaultAzureCredential({ tenantId: config.tenantId });
const creds = this.getCredentials(config);
this.client = new ResourceGraphClient(creds);
}
private getCredentials(config: AzureFunctionsConfig) {
return config.clientId && config.clientSecret
? new ClientSecretCredential(
config.tenantId,
config.clientId,
config.clientSecret,
)
: new DefaultAzureCredential({ tenantId: config.tenantId });
}
static fromConfig(config: Config): AzureSitesApi {
return new AzureSitesApi(AzureFunctionsConfig.fromConfig(config));
}
async start(request: AzureSiteStartStopRequest): Promise<void> {
const client = new WebSiteManagementClient(
this.getCredentials(this.config),
request.subscription,
);
await client.webApps.start(request.resourceGroup, request.name);
}
async stop(request: AzureSiteStartStopRequest): Promise<void> {
const client = new WebSiteManagementClient(
this.getCredentials(this.config),
request.subscription,
);
await client.webApps.stop(request.resourceGroup, request.name);
}
async list(request: AzureSiteListRequest): Promise<AzureSiteListResponse> {
const items: AzureSite[] = [];
try {
@@ -66,6 +87,7 @@ export class AzureSitesApi {
name: v.name!,
kind: v.kind!,
resourceGroup: v.resourceGroup!,
subscription: v.id!.match(/\w{8}\-\w{4}\-\w{4}\-\w{4}\-\w{12}/)[0],
location: v.location!,
lastModifiedDate: v.properties.lastModifiedTimeUtc!,
usageState: v.properties.usageState!,
@@ -48,6 +48,34 @@ export async function createRouter(
}),
);
});
router.post(
'/:subscription/:resourceGroup/:name/start',
async (request, response) => {
const { subscription, resourceGroup, name } = request.params;
console.log('starting...');
response.json(
await azureSitesApi.start({
subscription,
resourceGroup,
name,
}),
);
},
);
router.post(
'/:subscription/:resourceGroup/:name/stop',
async (request, response) => {
const { subscription, resourceGroup, name } = request.params;
console.log('stopping...');
response.json(
await azureSitesApi.stop({
subscription,
resourceGroup,
name,
}),
);
},
);
router.use(errorHandler());
return router;
}
@@ -1,4 +1,4 @@
## API Report File for "@backstage/plugin-azure-functions-common"
## API Report File for "@backstage/plugin-azure-sites-common"
> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/).
@@ -11,6 +11,7 @@ export type AzureSite = {
kind: string;
location: string;
resourceGroup: string;
subscription: string;
state: string;
usageState: string;
containerSize: number;
@@ -28,5 +29,12 @@ export type AzureSiteListResponse = {
items: AzureSite[];
};
// @public (undocumented)
export type AzureSiteStartStopRequest = {
subscription: string;
resourceGroup: string;
name: string;
};
// (No @packageDocumentation comment for this package)
```
@@ -1,5 +1,5 @@
{
"name": "@backstage/plugin-azure-functions-common",
"name": "@backstage/plugin-azure-sites-common",
"description": "Common functionalities for the azure plugin",
"version": "0.0.0",
"main": "src/index.ts",
@@ -18,7 +18,7 @@
"repository": {
"type": "git",
"url": "https://github.com/backstage/backstage",
"directory": "plugins/azure-functions-common"
"directory": "plugins/azure-sites-common"
},
"keywords": [
"backstage"
@@ -22,6 +22,7 @@ export type AzureSite = {
kind: string;
location: string;
resourceGroup: string;
subscription: string;
state: string;
usageState: string;
containerSize: number;
@@ -38,3 +39,10 @@ export type AzureSiteListRequest = {
export type AzureSiteListResponse = {
items: AzureSite[];
};
/** @public */
export type AzureSiteStartStopRequest = {
subscription: string;
resourceGroup: string;
name: string;
};
@@ -47,14 +47,14 @@ azure.com/microsoft-web-sites: func-testapp
1. Install the plugin in the `packages/app` directory
```sh
yarn add @backstage/plugin-azure-functions
yarn add @backstage/plugin-azure-sites
```
2. Add widget component to your Backstage instance:
```ts
// In packages/app/src/components/catalog/EntityPage.tsx
import { EntityAzureSitesOverviewWidget, isAzureWebSiteNameAvailable } from '@backstage/plugin-azure-functions';
import { EntityAzureSitesOverviewWidget, isAzureWebSiteNameAvailable } from '@backstage/plugin-azure-sites';
...
@@ -1,4 +1,4 @@
## API Report File for "@backstage/plugin-azure-functions"
## API Report File for "@backstage/plugin-azure-sites"
> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/).
@@ -6,8 +6,9 @@
/// <reference types="react" />
import { ApiRef } from '@backstage/core-plugin-api';
import { AzureSiteListRequest } from '@backstage/plugin-azure-functions-common';
import { AzureSiteListResponse } from '@backstage/plugin-azure-functions-common';
import { AzureSiteListRequest } from '@backstage/plugin-azure-sites-common';
import { AzureSiteListResponse } from '@backstage/plugin-azure-sites-common';
import { AzureSiteStartStopRequest } from '@backstage/plugin-azure-sites-common';
import { BackstagePlugin } from '@backstage/core-plugin-api';
import { DiscoveryApi } from '@backstage/core-plugin-api';
import { Entity } from '@backstage/catalog-model';
@@ -20,6 +21,8 @@ export const azureSiteApiRef: ApiRef<AzureSitesApi>;
// @public (undocumented)
export type AzureSitesApi = {
list: (request: AzureSiteListRequest) => Promise<AzureSiteListResponse>;
start: (request: AzureSiteStartStopRequest) => Promise<void>;
stop: (request: AzureSiteStartStopRequest) => Promise<void>;
};
// @public (undocumented)
@@ -30,6 +33,10 @@ export class AzureSitesApiBackendClient implements AzureSitesApi {
});
// (undocumented)
list(request: AzureSiteListRequest): Promise<AzureSiteListResponse>;
// (undocumented)
start(request: AzureSiteStartStopRequest): Promise<void>;
// (undocumented)
stop(request: AzureSiteStartStopRequest): Promise<void>;
}
// @public (undocumented)

Before

Width:  |  Height:  |  Size: 57 KiB

After

Width:  |  Height:  |  Size: 57 KiB

@@ -1,5 +1,5 @@
{
"name": "@backstage/plugin-azure-functions",
"name": "@backstage/plugin-azure-sites",
"version": "0.0.0",
"main": "src/index.ts",
"types": "src/index.ts",
@@ -17,7 +17,7 @@
"repository": {
"type": "git",
"url": "https://github.com/backstage/backstage",
"directory": "plugins/azure-functions"
"directory": "plugins/azure-sites"
},
"keywords": [
"backstage",
@@ -36,7 +36,7 @@
"@backstage/catalog-model": "workspace:^",
"@backstage/core-components": "workspace:^",
"@backstage/core-plugin-api": "workspace:^",
"@backstage/plugin-azure-functions-common": "workspace:^",
"@backstage/plugin-azure-sites-common": "workspace:^",
"@backstage/plugin-catalog-react": "workspace:^",
"@backstage/theme": "workspace:^",
"@material-ui/core": "^4.12.2",
@@ -18,14 +18,17 @@ import { createApiRef } from '@backstage/core-plugin-api';
import {
AzureSiteListRequest,
AzureSiteListResponse,
} from '@backstage/plugin-azure-functions-common';
AzureSiteStartStopRequest,
} from '@backstage/plugin-azure-sites-common';
/** @public */
export const azureSiteApiRef = createApiRef<AzureSitesApi>({
id: 'plugin.azure-functions.service',
id: 'plugin.azure-sites.service',
});
/** @public */
export type AzureSitesApi = {
list: (request: AzureSiteListRequest) => Promise<AzureSiteListResponse>;
start: (request: AzureSiteStartStopRequest) => Promise<void>;
stop: (request: AzureSiteStartStopRequest) => Promise<void>;
};
@@ -18,7 +18,8 @@ import { AzureSitesApi } from './AzureSitesApi';
import {
AzureSiteListRequest,
AzureSiteListResponse,
} from '@backstage/plugin-azure-functions-common';
AzureSiteStartStopRequest,
} from '@backstage/plugin-azure-sites-common';
import { DiscoveryApi, IdentityApi } from '@backstage/core-plugin-api';
/** @public */
@@ -33,11 +34,46 @@ export class AzureSitesApiBackendClient implements AzureSitesApi {
this.identityApi = options.identityApi;
}
async stop(request: AzureSiteStartStopRequest): Promise<void> {
try {
const url = `${await this.discoveryApi.getBaseUrl('azure-functions')}/${
request.subscription
}/${request.resourceGroup}/${request.name}/stop`;
const { token: accessToken } = await this.identityApi.getCredentials();
await fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
...(accessToken && { Authorization: `Bearer ${accessToken}` }),
},
});
} catch (e: any) {
throw new Error(e);
}
}
async start(request: AzureSiteStartStopRequest): Promise<void> {
try {
const url = `${await this.discoveryApi.getBaseUrl('azure-functions')}/${
request.subscription
}/${request.resourceGroup}/${request.name}/start`;
const { token: accessToken } = await this.identityApi.getCredentials();
await fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
...(accessToken && { Authorization: `Bearer ${accessToken}` }),
},
});
} catch (e: any) {
throw new Error(e);
}
}
async list(request: AzureSiteListRequest): Promise<AzureSiteListResponse> {
try {
const url = `${await this.discoveryApi.getBaseUrl(
'azure-functions',
)}/list/${request.name}`;
const url = `${await this.discoveryApi.getBaseUrl('azure-sites')}/list/${
request.name
}`;
const { token: accessToken } = await this.identityApi.getCredentials();
const response = await fetch(url, {
method: 'GET',
@@ -73,7 +73,7 @@ describe('AzureSitesOverviewWidget', () => {
);
expect(await rendered.findByText(siteMock.name)).toBeInTheDocument();
expect(await rendered.findByText(siteMock.kind)).toBeInTheDocument();
expect(await rendered.findByText(siteMock.location)).toBeInTheDocument();
expect(await rendered.findByText(siteMock.state)).toBeInTheDocument();
expect(
await rendered.findByText(
@@ -0,0 +1,271 @@
/*
* Copyright 2022 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, { Dispatch, useEffect, useState } from 'react';
import {
Box,
Card,
IconButton,
LinearProgress,
Link,
Menu,
MenuItem,
Snackbar,
Tooltip,
} from '@material-ui/core';
import { default as MuiAlert } from '@material-ui/lab/Alert';
import { AzureSite } from '@backstage/plugin-azure-sites-common';
import { Table, TableColumn } from '@backstage/core-components';
import FlashOnIcon from '@material-ui/icons/FlashOn';
import PublicIcon from '@material-ui/icons/Public';
import MoreVertIcon from '@material-ui/icons/MoreVert';
import StartIcon from '@material-ui/icons/PlayArrow';
import StopIcon from '@material-ui/icons/Stop';
import OpenInNewIcon from '@material-ui/icons/OpenInNew';
import { DateTime } from 'luxon';
import { useApi } from '@backstage/core-plugin-api';
import { azureSiteApiRef } from '../../api';
type States = 'Waiting' | 'Running' | 'Paused' | 'Failed' | 'Stopped';
type Kinds = 'app' | 'functionapp';
const State = ({ value }: { value: States }) => {
const colorMap = {
Waiting: '#dcbc21',
Running: 'green',
Paused: 'black',
Failed: 'red',
Stopped: 'black',
};
return (
<Box display="flex" alignItems="center">
<span
style={{
display: 'block',
width: '8px',
height: '8px',
borderRadius: '50%',
backgroundColor: colorMap[value],
marginRight: '5px',
}}
/>
{value}
</Box>
);
};
const Kind = ({ value }: { value: Kinds }) => {
const iconMap = {
app: <PublicIcon />,
functionapp: <FlashOnIcon />,
};
return (
<Box display="flex" alignItems="center">
<Tooltip title={value}>{iconMap[value]}</Tooltip>
</Box>
);
};
type TableProps = {
data: AzureSite[];
loading: boolean;
};
const ActionButtons = ({
value,
onMenuItemClick,
}: {
value: AzureSite;
onMenuItemClick: Dispatch<React.SetStateAction<string | null>>;
}) => {
const azureApi = useApi(azureSiteApiRef);
const [anchorEl, setAnchorEl] = useState<null | HTMLElement>(null);
const open = Boolean(anchorEl);
const handleOpen = (event: React.MouseEvent<HTMLElement>) => {
setAnchorEl(event.currentTarget);
};
const handleClose = () => {
setAnchorEl(null);
};
const start = () => {
azureApi.start({
name: value.name,
resourceGroup: value.resourceGroup,
subscription: value.subscription,
});
onMenuItemClick('Starting, this may take some time...');
handleClose();
};
const stop = () => {
azureApi.stop({
name: value.name,
resourceGroup: value.resourceGroup,
subscription: value.subscription,
});
onMenuItemClick('Stopping, this may take some time...');
handleClose();
};
return (
<div>
<IconButton
aria-label="more"
id="long-button"
aria-controls={open ? 'long-menu' : undefined}
aria-expanded={open ? 'true' : undefined}
aria-haspopup="true"
onClick={handleOpen}
>
<MoreVertIcon />
</IconButton>
<Menu
id="long-menu"
MenuListProps={{
'aria-labelledby': 'long-button',
}}
anchorEl={anchorEl}
open={open}
onClose={handleClose}
PaperProps={{
style: {
maxHeight: 48 * 4.5,
width: '20ch',
},
}}
>
{value.state !== 'Running' && (
<MenuItem key="start" onClick={start}>
<StartIcon />
&nbsp;Start
</MenuItem>
)}
{value.state !== 'Stopped' && (
<MenuItem key="stop" onClick={stop}>
<StopIcon />
&nbsp;Stop
</MenuItem>
)}
<MenuItem
component="a"
href={value.logstreamHref}
target="_blank"
key="logStream"
onClick={handleClose}
>
<OpenInNewIcon />
&nbsp;Log Stream
</MenuItem>
</Menu>
</div>
);
};
/** @public */
export const AzureSitesOverviewTable = ({ data, loading }: TableProps) => {
const [snackbarMessage, setSnackbarMessage] = useState<null | string>(null);
const [isSnackbarOpen, setSnackbarOpen] = useState(false);
const onSnackbarClose = () => {
setSnackbarMessage(null);
};
useEffect(() => {
setSnackbarOpen(!!snackbarMessage);
}, [snackbarMessage]);
const columns: TableColumn<AzureSite>[] = [
{
width: '25px',
field: 'kind',
render: (func: AzureSite) => <Kind value={func.kind as Kinds} />,
},
{
title: 'name',
field: 'name',
highlight: true,
render: (func: AzureSite) => {
return (
<Link href={func.href} target="_blank">
{func.name}
</Link>
);
},
},
{
title: 'location',
field: 'location',
render: (func: AzureSite) => func.location ?? 'unknown',
},
{
title: 'status',
field: 'status',
render: (func: AzureSite) => <State value={func.state as States} />,
},
{
title: 'last modified',
field: 'lastModifiedDate',
render: (func: AzureSite) =>
DateTime.fromISO(func.lastModifiedDate).toLocaleString(
DateTime.DATETIME_MED,
),
},
{
title: 'actions',
align: 'right',
sorting: false,
field: 'actions',
render: (func: AzureSite) => (
<ActionButtons value={func} onMenuItemClick={setSnackbarMessage} />
),
},
];
const tableStyle = {
minWidth: '0',
width: '100%',
};
return (
<Card style={tableStyle}>
<Table
title={
<Box display="flex" alignItems="center">
<FlashOnIcon style={{ fontSize: 30 }} />
<Box mr={1} />
Azure Sites
</Box>
}
options={{ paging: true, search: false, pageSize: 10 }}
data={data}
emptyContent={<LinearProgress />}
isLoading={loading}
columns={columns}
/>
<Snackbar
open={isSnackbarOpen}
autoHideDuration={6_000}
anchorOrigin={{ vertical: 'top', horizontal: 'center' }}
onClose={onSnackbarClose}
>
<MuiAlert onClose={onSnackbarClose} severity="info">
{snackbarMessage}
</MuiAlert>
</Snackbar>
</Card>
);
};
@@ -14,12 +14,15 @@
* limitations under the License.
*/
import useInterval from 'react-use/lib/useInterval';
import useAsyncRetry from 'react-use/lib/useAsyncRetry';
import { useApi, errorApiRef } from '@backstage/core-plugin-api';
import { AzureSiteListResponse } from '@backstage/plugin-azure-functions-common';
import { AzureSiteListResponse } from '@backstage/plugin-azure-sites-common';
import { azureSiteApiRef } from '../api';
import { useCallback } from 'react';
const POLLING_INTERVAL = 15000;
export function useSites({ name }: { name: string }) {
const azureApi = useApi(azureSiteApiRef);
const errorApi = useApi(errorApiRef);
@@ -56,6 +59,8 @@ export function useSites({ name }: { name: string }) {
}
}, []);
useInterval(() => retry(), POLLING_INTERVAL);
return [
{
loading,
@@ -14,7 +14,7 @@
* limitations under the License.
*/
import { AzureSite } from '@backstage/plugin-azure-functions-common';
import { AzureSite } from '@backstage/plugin-azure-sites-common';
export const entityMock = {
metadata: {
@@ -40,6 +40,7 @@ export const siteMock: AzureSite = {
name: 'func-mock',
kind: 'functionapp',
resourceGroup: 'mock-resourcegroup',
subscription: '00000000-0000-0000-0000-000000000000',
tags: {
isMock: true,
},
@@ -17,5 +17,5 @@
import { createRouteRef } from '@backstage/core-plugin-api';
export const rootRouteRef = createRouteRef({
id: 'azure-functions',
id: 'azure-sites',
});
+70 -12
View File
@@ -339,6 +339,21 @@ __metadata:
languageName: node
linkType: hard
"@azure/arm-appservice@npm:^13.0.1":
version: 13.0.2
resolution: "@azure/arm-appservice@npm:13.0.2"
dependencies:
"@azure/abort-controller": ^1.0.0
"@azure/core-auth": ^1.3.0
"@azure/core-client": ^1.5.0
"@azure/core-lro": ^2.2.0
"@azure/core-paging": ^1.2.0
"@azure/core-rest-pipeline": ^1.8.0
tslib: ^2.2.0
checksum: 6d604c492a70a6cdd4d3ad3f634a74228dc081ed4f49128873e76bfa5e65ec8cce18b7b19319fd2b1b4edbd390dbd66c9ac48646f0ed80cae09cd2f1d05fb279
languageName: node
linkType: hard
"@azure/arm-resourcegraph@npm:^4.2.1":
version: 4.2.1
resolution: "@azure/arm-resourcegraph@npm:4.2.1"
@@ -358,7 +373,7 @@ __metadata:
languageName: node
linkType: hard
"@azure/core-auth@npm:^1.1.4":
"@azure/core-auth@npm:^1.1.4, @azure/core-auth@npm:^1.4.0":
version: 1.4.0
resolution: "@azure/core-auth@npm:1.4.0"
dependencies:
@@ -393,6 +408,21 @@ __metadata:
languageName: node
linkType: hard
"@azure/core-client@npm:^1.5.0":
version: 1.6.1
resolution: "@azure/core-client@npm:1.6.1"
dependencies:
"@azure/abort-controller": ^1.0.0
"@azure/core-auth": ^1.4.0
"@azure/core-rest-pipeline": ^1.9.1
"@azure/core-tracing": ^1.0.0
"@azure/core-util": ^1.0.0
"@azure/logger": ^1.0.0
tslib: ^2.2.0
checksum: 400890a9b5f0c8801ff92005c3cba7bb5124634e321735406731bef33688a79f23d28b49fccdfab90814dade41a13f3d3cb99f80151a2bff17628416e811afb6
languageName: node
linkType: hard
"@azure/core-http@npm:^2.0.0":
version: 2.2.4
resolution: "@azure/core-http@npm:2.2.4"
@@ -437,6 +467,15 @@ __metadata:
languageName: node
linkType: hard
"@azure/core-paging@npm:^1.2.0":
version: 1.3.0
resolution: "@azure/core-paging@npm:1.3.0"
dependencies:
tslib: ^2.2.0
checksum: 3fbf3d6474e2346f7c3ea8344a41bf41e053789efbbd29df78365e9c9ca66e143da3e5407d8c9dd5ddc82a65680185cd6f0ec851c48635776d18a6a605a98e78
languageName: node
linkType: hard
"@azure/core-rest-pipeline@npm:^1.1.0, @azure/core-rest-pipeline@npm:^1.5.0":
version: 1.5.0
resolution: "@azure/core-rest-pipeline@npm:1.5.0"
@@ -454,6 +493,24 @@ __metadata:
languageName: node
linkType: hard
"@azure/core-rest-pipeline@npm:^1.8.0, @azure/core-rest-pipeline@npm:^1.9.1":
version: 1.9.2
resolution: "@azure/core-rest-pipeline@npm:1.9.2"
dependencies:
"@azure/abort-controller": ^1.0.0
"@azure/core-auth": ^1.4.0
"@azure/core-tracing": ^1.0.1
"@azure/core-util": ^1.0.0
"@azure/logger": ^1.0.0
form-data: ^4.0.0
http-proxy-agent: ^5.0.0
https-proxy-agent: ^5.0.0
tslib: ^2.2.0
uuid: ^8.3.0
checksum: cdfdaf8bdb0778f40ecfeb8b5da0b4f8643d641b75bb5869485afd38f7c3127ab088ac2fe2980df03d28fb6715928e04560343ee6416246aebe75443c4dd2906
languageName: node
linkType: hard
"@azure/core-tracing@npm:1.0.0-preview.13":
version: 1.0.0-preview.13
resolution: "@azure/core-tracing@npm:1.0.0-preview.13"
@@ -464,7 +521,7 @@ __metadata:
languageName: node
linkType: hard
"@azure/core-tracing@npm:^1.0.0":
"@azure/core-tracing@npm:^1.0.0, @azure/core-tracing@npm:^1.0.1":
version: 1.0.1
resolution: "@azure/core-tracing@npm:1.0.1"
dependencies:
@@ -4339,16 +4396,17 @@ __metadata:
languageName: unknown
linkType: soft
"@backstage/plugin-azure-functions-backend@workspace:^, @backstage/plugin-azure-functions-backend@workspace:plugins/azure-functions-backend":
"@backstage/plugin-azure-sites-backend@workspace:^, @backstage/plugin-azure-sites-backend@workspace:plugins/azure-sites-backend":
version: 0.0.0-use.local
resolution: "@backstage/plugin-azure-functions-backend@workspace:plugins/azure-functions-backend"
resolution: "@backstage/plugin-azure-sites-backend@workspace:plugins/azure-sites-backend"
dependencies:
"@azure/arm-appservice": ^13.0.1
"@azure/arm-resourcegraph": ^4.2.1
"@azure/identity": ^2.1.0
"@backstage/backend-common": "workspace:^"
"@backstage/cli": "workspace:^"
"@backstage/config": "workspace:^"
"@backstage/plugin-azure-functions-common": "workspace:^"
"@backstage/plugin-azure-sites-common": "workspace:^"
"@types/express": ^4.17.6
"@types/supertest": ^2.0.8
express: ^4.17.1
@@ -4360,17 +4418,17 @@ __metadata:
languageName: unknown
linkType: soft
"@backstage/plugin-azure-functions-common@workspace:^, @backstage/plugin-azure-functions-common@workspace:plugins/azure-functions-common":
"@backstage/plugin-azure-sites-common@workspace:^, @backstage/plugin-azure-sites-common@workspace:plugins/azure-sites-common":
version: 0.0.0-use.local
resolution: "@backstage/plugin-azure-functions-common@workspace:plugins/azure-functions-common"
resolution: "@backstage/plugin-azure-sites-common@workspace:plugins/azure-sites-common"
dependencies:
"@backstage/cli": "workspace:^"
languageName: unknown
linkType: soft
"@backstage/plugin-azure-functions@workspace:^, @backstage/plugin-azure-functions@workspace:plugins/azure-functions":
"@backstage/plugin-azure-sites@workspace:^, @backstage/plugin-azure-sites@workspace:plugins/azure-sites":
version: 0.0.0-use.local
resolution: "@backstage/plugin-azure-functions@workspace:plugins/azure-functions"
resolution: "@backstage/plugin-azure-sites@workspace:plugins/azure-sites"
dependencies:
"@backstage/catalog-model": "workspace:^"
"@backstage/cli": "workspace:^"
@@ -4378,7 +4436,7 @@ __metadata:
"@backstage/core-components": "workspace:^"
"@backstage/core-plugin-api": "workspace:^"
"@backstage/dev-utils": "workspace:^"
"@backstage/plugin-azure-functions-common": "workspace:^"
"@backstage/plugin-azure-sites-common": "workspace:^"
"@backstage/plugin-catalog-react": "workspace:^"
"@backstage/test-utils": "workspace:^"
"@backstage/theme": "workspace:^"
@@ -22099,7 +22157,7 @@ __metadata:
"@backstage/plugin-apache-airflow": "workspace:^"
"@backstage/plugin-api-docs": "workspace:^"
"@backstage/plugin-azure-devops": "workspace:^"
"@backstage/plugin-azure-functions": "workspace:^"
"@backstage/plugin-azure-sites": "workspace:^"
"@backstage/plugin-badges": "workspace:^"
"@backstage/plugin-catalog-common": "workspace:^"
"@backstage/plugin-catalog-graph": "workspace:^"
@@ -22205,7 +22263,7 @@ __metadata:
"@backstage/plugin-auth-backend": "workspace:^"
"@backstage/plugin-auth-node": "workspace:^"
"@backstage/plugin-azure-devops-backend": "workspace:^"
"@backstage/plugin-azure-functions-backend": "workspace:^"
"@backstage/plugin-azure-sites-backend": "workspace:^"
"@backstage/plugin-badges-backend": "workspace:^"
"@backstage/plugin-catalog-backend": "workspace:^"
"@backstage/plugin-code-coverage-backend": "workspace:^"