refactor table to own component. unit test the table
Signed-off-by: Wesley <wpattison08@gmail.com>
This commit is contained in:
@@ -38,8 +38,8 @@ export async function createRouter(
|
||||
logger.info('PONG!');
|
||||
response.send({ status: 'ok' });
|
||||
});
|
||||
router.get('/get', async (request, response) => {
|
||||
response.json(await azureWebManagementApi.list({ functionName: request.query.functionName!.toString() }))
|
||||
router.post('/list', async (request, response) => {
|
||||
response.json(await azureWebManagementApi.list({ functionName: request.body.functionName!.toString() }))
|
||||
});
|
||||
router.use(errorHandler());
|
||||
return router;
|
||||
|
||||
@@ -36,14 +36,15 @@ export class AzureFunctionsBackendClient implements AzureFunctionsApi {
|
||||
functionName: string;
|
||||
}): Promise<FunctionsData[]> {
|
||||
try {
|
||||
const url = `${await this.discoveryApi.getBaseUrl('azure-functions')}/get?functionName=${functionName}`;
|
||||
const url = `${await this.discoveryApi.getBaseUrl('azure-functions')}/list`;
|
||||
const { token: idToken } = await this.identityApi.getCredentials();
|
||||
const response = await fetch(url, {
|
||||
method: 'GET',
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
...(idToken && { Authorization: `Bearer ${idToken}` }),
|
||||
}
|
||||
},
|
||||
body: JSON.stringify({ functionName: functionName })
|
||||
});
|
||||
return await response.json();
|
||||
} catch (e: any) {
|
||||
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* 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 { Entity } from '@backstage/catalog-model';
|
||||
import { useFunctions } from '../../hooks/useFunctions';
|
||||
import {
|
||||
AZURE_FUNCTIONS_ANNOTATION,
|
||||
useServiceEntityAnnotations,
|
||||
} from '../../hooks/useServiceEntityAnnotations';
|
||||
import { MissingAnnotationEmptyState } from '@backstage/core-components';
|
||||
import ErrorBoundary from '../ErrorBoundary';
|
||||
import { useEntity } from '@backstage/plugin-catalog-react';
|
||||
import { OverviewTable } from '../OverviewTableComponent/OverviewTable';
|
||||
|
||||
export const isAzureFunctionsAvailable = (entity: Entity) =>
|
||||
entity?.metadata.annotations?.[AZURE_FUNCTIONS_ANNOTATION];
|
||||
|
||||
const AzureFunctionsOverview = ({ entity }: { entity: Entity }) => {
|
||||
const { functionsName } = useServiceEntityAnnotations(entity);
|
||||
|
||||
const [functionsData] = useFunctions({
|
||||
functionsName
|
||||
});
|
||||
|
||||
return (
|
||||
<><OverviewTable data={functionsData.data ?? []} loading={functionsData.loading} /></>
|
||||
);
|
||||
};
|
||||
|
||||
export const AzureFunctionsOverviewWidget = () => {
|
||||
const { entity } = useEntity();
|
||||
|
||||
if (!isAzureFunctionsAvailable(entity)) {
|
||||
return (<MissingAnnotationEmptyState annotation={AZURE_FUNCTIONS_ANNOTATION} />);
|
||||
}
|
||||
|
||||
return (
|
||||
<ErrorBoundary>
|
||||
<AzureFunctionsOverview entity={entity} />
|
||||
</ErrorBoundary>
|
||||
)
|
||||
};
|
||||
+12
-12
@@ -27,13 +27,12 @@ import {
|
||||
setupRequestMockHandlers,
|
||||
TestApiProvider,
|
||||
} from '@backstage/test-utils';
|
||||
import { EntityProvider } from '@backstage/plugin-catalog-react';
|
||||
import { setupServer } from 'msw/node';
|
||||
import {
|
||||
entityMock,
|
||||
functionResponseMock,
|
||||
} from '../../mocks/mocks';
|
||||
import { azureFunctionsApiRef, AzureFunctionsOverviewWidget } from '../..';
|
||||
import { azureFunctionsApiRef } from '../..';
|
||||
import { OverviewTable } from './OverviewTable';
|
||||
|
||||
const errorApiMock = { post: jest.fn(), error$: jest.fn() };
|
||||
const identityApiMock = (getCredentials: any) => ({
|
||||
@@ -61,9 +60,11 @@ describe('AzureFunctionsOverviewWidget', () => {
|
||||
|
||||
beforeEach(() => {
|
||||
worker.use(
|
||||
rest.get(
|
||||
'https://portal.azure.com/#@test/resource/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/mock_rg/providers/Microsoft.Web/sites/func-mock',
|
||||
(_, res, ctx) => res(ctx.json(functionResponseMock)),
|
||||
rest.post(
|
||||
'/list',
|
||||
(_, res, ctx) => {
|
||||
res(ctx.json(functionResponseMock));
|
||||
},
|
||||
),
|
||||
);
|
||||
});
|
||||
@@ -71,20 +72,19 @@ describe('AzureFunctionsOverviewWidget', () => {
|
||||
it('should display an overview table with the data from the requests', async () => {
|
||||
const rendered = render(
|
||||
<TestApiProvider apis={apis}>
|
||||
<EntityProvider entity={entityMock}>
|
||||
<AzureFunctionsOverviewWidget />
|
||||
</EntityProvider>
|
||||
<OverviewTable data={[functionResponseMock]} loading={false} />
|
||||
</TestApiProvider>,
|
||||
);
|
||||
|
||||
expect(
|
||||
await rendered.findByText(functionResponseMock.name),
|
||||
await rendered.findByText(functionResponseMock.functionName),
|
||||
).toBeInTheDocument();
|
||||
expect(
|
||||
await rendered.findByText(functionResponseMock.properties.state),
|
||||
await rendered.findByText(functionResponseMock.state),
|
||||
).toBeInTheDocument();
|
||||
expect(
|
||||
await rendered.findByText(
|
||||
new Date(functionResponseMock.properties.lastModifiedTimeUtc).toUTCString(),
|
||||
new Date(functionResponseMock.lastModifiedDate).toUTCString(),
|
||||
),
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
+2
-41
@@ -21,17 +21,9 @@ import {
|
||||
Link,
|
||||
LinearProgress
|
||||
} from '@material-ui/core';
|
||||
import { Entity } from '@backstage/catalog-model';
|
||||
import { useFunctions } from '../../hooks/useFunctions';
|
||||
import { FunctionsData } from '../../api/types';
|
||||
import {
|
||||
AZURE_FUNCTIONS_ANNOTATION,
|
||||
useServiceEntityAnnotations,
|
||||
} from '../../hooks/useServiceEntityAnnotations';
|
||||
import { MissingAnnotationEmptyState, Table, TableColumn } from '@backstage/core-components';
|
||||
import { Table, TableColumn } from '@backstage/core-components';
|
||||
import FlashOnIcon from '@material-ui/icons/FlashOn'
|
||||
import ErrorBoundary from '../ErrorBoundary';
|
||||
import { useEntity } from '@backstage/plugin-catalog-react';
|
||||
|
||||
type States = 'Waiting' | 'Running' | 'Paused' | 'Failed';
|
||||
|
||||
@@ -59,8 +51,6 @@ const State = ({ value }: { value: States }) => {
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
|
||||
type FunctionTableProps = {
|
||||
data: FunctionsData[];
|
||||
loading: boolean;
|
||||
@@ -95,7 +85,7 @@ const DEFAULT_COLUMNS: TableColumn<FunctionsData>[] = [
|
||||
},
|
||||
];
|
||||
|
||||
const OverviewComponent = ({ data, loading }: FunctionTableProps) => {
|
||||
export const OverviewTable = ({ data, loading }: FunctionTableProps) => {
|
||||
const columns: TableColumn<FunctionsData>[] = [...DEFAULT_COLUMNS];
|
||||
const tableStyle = {
|
||||
minWidth: '0',
|
||||
@@ -123,32 +113,3 @@ const OverviewComponent = ({ data, loading }: FunctionTableProps) => {
|
||||
</Card>
|
||||
);
|
||||
};
|
||||
|
||||
export const isAzureFunctionsAvailable = (entity: Entity) =>
|
||||
entity?.metadata.annotations?.[AZURE_FUNCTIONS_ANNOTATION];
|
||||
|
||||
const AzureFunctionsOverview = ({ entity }: { entity: Entity }) => {
|
||||
const { functionsName } = useServiceEntityAnnotations(entity);
|
||||
|
||||
const [functionsData] = useFunctions({
|
||||
functionsName
|
||||
});
|
||||
|
||||
return (
|
||||
<><OverviewComponent data={functionsData.data ?? []} loading={functionsData.loading} /></>
|
||||
);
|
||||
};
|
||||
|
||||
export const AzureFunctionsOverviewWidget = () => {
|
||||
const { entity } = useEntity();
|
||||
|
||||
if (!isAzureFunctionsAvailable(entity)) {
|
||||
return (<MissingAnnotationEmptyState annotation={AZURE_FUNCTIONS_ANNOTATION} />);
|
||||
}
|
||||
|
||||
return (
|
||||
<ErrorBoundary>
|
||||
<AzureFunctionsOverview entity={entity} />
|
||||
</ErrorBoundary>
|
||||
)
|
||||
};
|
||||
@@ -16,4 +16,4 @@
|
||||
|
||||
export * from './plugin';
|
||||
export * from './api';
|
||||
export * from './components/AzureFunctionsOverview/AzureFunctionsOverview';
|
||||
export * from './components/AzureFunctionsOverviewComponent/AzureFunctionsOverview';
|
||||
@@ -14,6 +14,8 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { FunctionsData } from "../api";
|
||||
|
||||
export const entityMock = {
|
||||
metadata: {
|
||||
namespace: 'default',
|
||||
@@ -35,225 +37,13 @@ export const entityMock = {
|
||||
};
|
||||
|
||||
// https://management.azure.com/subscriptions/{{subscriptionId}}/resourceGroups/{{resourceGroup}}/providers/Microsoft.Web/sites/{{functionsName}}?api-version=2022-03-01
|
||||
export const functionResponseMock = {
|
||||
id: "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg_mock/providers/Microsoft.Web/sites/func-mock",
|
||||
name: "func-mock",
|
||||
type: "Microsoft.Web/sites",
|
||||
kind: "functionapp",
|
||||
export const functionResponseMock: FunctionsData = {
|
||||
functionName: "func-mock",
|
||||
location: "West Europe",
|
||||
tags: {},
|
||||
properties: {
|
||||
name: "func-mock",
|
||||
state: "Running",
|
||||
hostNames: [
|
||||
"func-mock.azurewebsites.net"
|
||||
],
|
||||
webSpace: "rg_mock-WestEuropewebspace",
|
||||
selfLink: "https://mockurl.api.azurewebsites.windows.net:454/subscriptions/00000000-0000-0000-0000-000000000000/webspaces/rg_mock-WestEuropewebspace/sites/func-mock",
|
||||
repositorySiteName: "func-mock",
|
||||
owner: null,
|
||||
usageState: "Normal",
|
||||
enabled: true,
|
||||
adminEnabled: true,
|
||||
enabledHostNames: [
|
||||
"func-mock.azurewebsites.net",
|
||||
"func-mock.scm.azurewebsites.net"
|
||||
],
|
||||
siteProperties: {
|
||||
metadata: null,
|
||||
properties: [
|
||||
{
|
||||
name: "LinuxFxVersion",
|
||||
value: ""
|
||||
},
|
||||
{
|
||||
name: "WindowsFxVersion",
|
||||
value: null
|
||||
}
|
||||
],
|
||||
appSettings: null
|
||||
},
|
||||
availabilityState: "Normal",
|
||||
sslCertificates: null,
|
||||
csrs: [],
|
||||
cers: null,
|
||||
siteMode: null,
|
||||
hostNameSslStates: [
|
||||
{
|
||||
name: "func-mock.azurewebsites.net",
|
||||
sslState: "Disabled",
|
||||
ipBasedSslResult: null,
|
||||
virtualIP: null,
|
||||
thumbprint: null,
|
||||
toUpdate: null,
|
||||
toUpdateIpBasedSsl: null,
|
||||
ipBasedSslState: "NotConfigured",
|
||||
hostType: "Standard"
|
||||
},
|
||||
{
|
||||
name: "func-mock.scm.azurewebsites.net",
|
||||
sslState: "Disabled",
|
||||
ipBasedSslResult: null,
|
||||
virtualIP: null,
|
||||
thumbprint: null,
|
||||
toUpdate: null,
|
||||
toUpdateIpBasedSsl: null,
|
||||
ipBasedSslState: "NotConfigured",
|
||||
hostType: "Repository"
|
||||
}
|
||||
],
|
||||
computeMode: null,
|
||||
serverFarm: null,
|
||||
serverFarmId: "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg_mock/providers/Microsoft.Web/serverfarms/plan-mock",
|
||||
reserved: false,
|
||||
isXenon: false,
|
||||
hyperV: false,
|
||||
lastModifiedTimeUtc: "2022-09-02T11:09:58.9033333",
|
||||
storageRecoveryDefaultState: "Running",
|
||||
contentAvailabilityState: "Normal",
|
||||
runtimeAvailabilityState: "Normal",
|
||||
secretsCollection: [],
|
||||
vnetRouteAllEnabled: false,
|
||||
containerAllocationSubnet: null,
|
||||
useContainerLocalhostBindings: null,
|
||||
vnetImagePullEnabled: false,
|
||||
vnetContentShareEnabled: false,
|
||||
siteConfig: {
|
||||
numberOfWorkers: 1,
|
||||
defaultDocuments: null,
|
||||
netFrameworkVersion: null,
|
||||
phpVersion: null,
|
||||
pythonVersion: null,
|
||||
nodeVersion: null,
|
||||
powerShellVersion: null,
|
||||
linuxFxVersion: "",
|
||||
windowsFxVersion: null,
|
||||
requestTracingEnabled: null,
|
||||
remoteDebuggingEnabled: null,
|
||||
remoteDebuggingVersion: null,
|
||||
httpLoggingEnabled: null,
|
||||
azureMonitorLogCategories: null,
|
||||
acrUseManagedIdentityCreds: false,
|
||||
acrUserManagedIdentityID: null,
|
||||
logsDirectorySizeLimit: null,
|
||||
detailedErrorLoggingEnabled: null,
|
||||
publishingUsername: null,
|
||||
publishingPassword: null,
|
||||
appSettings: null,
|
||||
metadata: null,
|
||||
connectionStrings: null,
|
||||
machineKey: null,
|
||||
handlerMappings: null,
|
||||
documentRoot: null,
|
||||
scmType: null,
|
||||
use32BitWorkerProcess: null,
|
||||
webSocketsEnabled: null,
|
||||
alwaysOn: true,
|
||||
javaVersion: null,
|
||||
javaContainer: null,
|
||||
javaContainerVersion: null,
|
||||
appCommandLine: null,
|
||||
managedPipelineMode: null,
|
||||
virtualApplications: null,
|
||||
winAuthAdminState: null,
|
||||
winAuthTenantState: null,
|
||||
customAppPoolIdentityAdminState: null,
|
||||
customAppPoolIdentityTenantState: null,
|
||||
runtimeADUser: null,
|
||||
runtimeADUserPassword: null,
|
||||
loadBalancing: null,
|
||||
routingRules: null,
|
||||
experiments: null,
|
||||
limits: null,
|
||||
autoHealEnabled: null,
|
||||
autoHealRules: null,
|
||||
tracingOptions: null,
|
||||
vnetName: null,
|
||||
vnetRouteAllEnabled: null,
|
||||
vnetPrivatePortsCount: null,
|
||||
publicNetworkAccess: null,
|
||||
cors: null,
|
||||
push: null,
|
||||
apiDefinition: null,
|
||||
apiManagementConfig: null,
|
||||
autoSwapSlotName: null,
|
||||
localMySqlEnabled: null,
|
||||
managedServiceIdentityId: null,
|
||||
xManagedServiceIdentityId: null,
|
||||
keyVaultReferenceIdentity: null,
|
||||
ipSecurityRestrictions: null,
|
||||
ipSecurityRestrictionsDefaultAction: null,
|
||||
scmIpSecurityRestrictions: null,
|
||||
scmIpSecurityRestrictionsDefaultAction: null,
|
||||
scmIpSecurityRestrictionsUseMain: null,
|
||||
http20Enabled: false,
|
||||
minTlsVersion: null,
|
||||
minTlsCipherSuite: null,
|
||||
supportedTlsCipherSuites: null,
|
||||
scmMinTlsVersion: null,
|
||||
ftpsState: null,
|
||||
preWarmedInstanceCount: null,
|
||||
functionAppScaleLimit: 0,
|
||||
elasticWebAppScaleLimit: null,
|
||||
healthCheckPath: null,
|
||||
fileChangeAuditEnabled: null,
|
||||
functionsRuntimeScaleMonitoringEnabled: null,
|
||||
websiteTimeZone: null,
|
||||
minimumElasticInstanceCount: 1,
|
||||
azureStorageAccounts: null,
|
||||
http20ProxyFlag: null,
|
||||
sitePort: null,
|
||||
antivirusScanEnabled: null,
|
||||
storageType: null
|
||||
},
|
||||
deploymentId: "func-mock",
|
||||
slotName: null,
|
||||
trafficManagerHostNames: null,
|
||||
sku: "Standard",
|
||||
scmSiteAlsoStopped: false,
|
||||
targetSwapSlot: null,
|
||||
hostingEnvironment: null,
|
||||
hostingEnvironmentProfile: null,
|
||||
clientAffinityEnabled: false,
|
||||
clientCertEnabled: false,
|
||||
clientCertMode: "Required",
|
||||
clientCertExclusionPaths: null,
|
||||
hostNamesDisabled: false,
|
||||
domainVerificationIdentifiers: null,
|
||||
customDomainVerificationId: "",
|
||||
kind: "functionapp",
|
||||
inboundIpAddress: "",
|
||||
possibleInboundIpAddresses: "",
|
||||
ftpUsername: "func-mock\\$func-mock",
|
||||
ftpsHostName: "ftps://mockurl.ftp.azurewebsites.windows.net/site/wwwroot",
|
||||
outboundIpAddresses: "",
|
||||
possibleOutboundIpAddresses: "",
|
||||
containerSize: 1536,
|
||||
dailyMemoryTimeQuota: 0,
|
||||
suspendedTill: null,
|
||||
siteDisabledReason: 0,
|
||||
functionExecutionUnitsCache: null,
|
||||
maxNumberOfWorkers: null,
|
||||
homeStamp: "mockurl",
|
||||
cloningInfo: null,
|
||||
hostingEnvironmentId: null,
|
||||
tags: {},
|
||||
resourceGroup: "rg_mock",
|
||||
defaultHostName: "func-mock.azurewebsites.net",
|
||||
slotSwapStatus: null,
|
||||
httpsOnly: false,
|
||||
redundancyMode: "None",
|
||||
inProgressOperationId: null,
|
||||
geoDistributions: null,
|
||||
privateEndpointConnections: [],
|
||||
publicNetworkAccess: null,
|
||||
buildVersion: null,
|
||||
targetBuildVersion: null,
|
||||
migrationState: null,
|
||||
eligibleLogCategories: "FunctionAppLogs",
|
||||
storageAccountRequired: false,
|
||||
virtualNetworkSubnetId: null,
|
||||
keyVaultReferenceIdentity: "SystemAssigned",
|
||||
privateLinkIdentifiers: null
|
||||
}
|
||||
state: "Running",
|
||||
href: "https://mockurl.api.azurewebsites.windows.net:454/subscriptions/00000000-0000-0000-0000-000000000000/webspaces/rg_mock-WestEuropewebspace/sites/func-mock",
|
||||
logstreamHref: "https://mockurl.api.azurewebsites.windows.net:454/subscriptions/00000000-0000-0000-0000-000000000000/webspaces/rg_mock-WestEuropewebspace/sites/func-mock/logStream",
|
||||
usageState: "Normal",
|
||||
lastModifiedDate: new Date("2022-09-02T11:09:58.9033333"),
|
||||
containerSize: 100
|
||||
};
|
||||
|
||||
@@ -51,7 +51,7 @@ export const EntityAzureFunctionsOverviewCard = azureFunctionsPlugin.provide(
|
||||
name: 'EntityAzureFunctionsOverviewCard',
|
||||
component: {
|
||||
lazy: () =>
|
||||
import('./components/AzureFunctionsOverview/AzureFunctionsOverview').then(
|
||||
import('./components/AzureFunctionsOverviewComponent/AzureFunctionsOverview').then(
|
||||
m => m.AzureFunctionsOverviewWidget,
|
||||
),
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user