implement createApiExtension
Co-authored-by: Patrik Oldsberg <poldsberg@gmail.com> Co-authored-by: Johan Haals <johan.haals@gmail.com> Signed-off-by: Fredrik Adelöw <freben@gmail.com>
This commit is contained in:
@@ -5,6 +5,8 @@
|
||||
```ts
|
||||
/// <reference types="react" />
|
||||
|
||||
import { AnyApiFactory } from '@backstage/core-plugin-api';
|
||||
import { AnyApiRef } from '@backstage/core-plugin-api';
|
||||
import { ComponentType } from 'react';
|
||||
import { JsonObject } from '@backstage/types';
|
||||
import { z } from 'zod';
|
||||
@@ -28,8 +30,40 @@ export interface BackstagePlugin {
|
||||
export const coreExtensionData: {
|
||||
reactComponent: ExtensionDataRef<ComponentType<{}>>;
|
||||
routePath: ExtensionDataRef<string>;
|
||||
apiFactory: ExtensionDataRef<AnyApiFactory>;
|
||||
};
|
||||
|
||||
// @public (undocumented)
|
||||
export function createApiExtension<
|
||||
TConfig extends {},
|
||||
TInputs extends Record<
|
||||
string,
|
||||
{
|
||||
extensionData: AnyExtensionDataMap;
|
||||
}
|
||||
>,
|
||||
>(
|
||||
options: (
|
||||
| {
|
||||
api: AnyApiRef;
|
||||
factory: (options: {
|
||||
config: TConfig;
|
||||
inputs: {
|
||||
[pointName in keyof TInputs]: ExtensionDataValue<
|
||||
TInputs[pointName]['extensionData']
|
||||
>[];
|
||||
};
|
||||
}) => AnyApiFactory;
|
||||
}
|
||||
| {
|
||||
factory: AnyApiFactory;
|
||||
}
|
||||
) & {
|
||||
configSchema?: PortableSchema<TConfig>;
|
||||
inputs?: TInputs;
|
||||
},
|
||||
): Extension<TConfig>;
|
||||
|
||||
// @public (undocumented)
|
||||
export function createExtension<
|
||||
TData extends AnyExtensionDataMap,
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
"react": "^16.13.1 || ^17.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@backstage/core-plugin-api": "workspace:^",
|
||||
"@backstage/types": "workspace:^",
|
||||
"lodash": "^4.17.21",
|
||||
"zod": "^3.21.4",
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* 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 { createApiExtension } from './createApiExtension';
|
||||
import { createApiFactory, createApiRef } from '@backstage/core-plugin-api';
|
||||
|
||||
describe('createApiExtension', () => {
|
||||
it('fills in the expected values for an existing factory', () => {
|
||||
const api = createApiRef<{ foo: string }>({ id: 'test' });
|
||||
const factory = createApiFactory({
|
||||
api,
|
||||
deps: {},
|
||||
factory: () => ({ foo: 'bar' }),
|
||||
});
|
||||
|
||||
const extension = createApiExtension({
|
||||
factory,
|
||||
});
|
||||
|
||||
expect(extension).toEqual({
|
||||
$$type: 'extension',
|
||||
id: 'apis.test',
|
||||
at: 'core/apis',
|
||||
disabled: false,
|
||||
configSchema: undefined,
|
||||
inputs: {},
|
||||
output: {
|
||||
api: {
|
||||
$$type: 'extension-data',
|
||||
id: 'core.api.factory',
|
||||
},
|
||||
},
|
||||
factory: expect.any(Function),
|
||||
});
|
||||
});
|
||||
|
||||
it('fills in the expected values for a ref and custom factory', () => {
|
||||
const api = createApiRef<{ foo: string }>({ id: 'test' });
|
||||
const factory = jest.fn(() => ({ foo: 'bar' }));
|
||||
|
||||
const extension = createApiExtension({
|
||||
api,
|
||||
inputs: {},
|
||||
factory({ config: _config, inputs: _inputs }) {
|
||||
return createApiFactory({
|
||||
api,
|
||||
deps: {},
|
||||
factory,
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
expect(extension).toEqual({
|
||||
$$type: 'extension',
|
||||
id: 'apis.test',
|
||||
at: 'core/apis',
|
||||
disabled: false,
|
||||
configSchema: undefined,
|
||||
inputs: {},
|
||||
output: {
|
||||
api: {
|
||||
$$type: 'extension-data',
|
||||
id: 'core.api.factory',
|
||||
},
|
||||
},
|
||||
factory: expect.any(Function),
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* 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 { AnyApiFactory, AnyApiRef } from '@backstage/core-plugin-api';
|
||||
import { PortableSchema } from '../createSchemaFromZod';
|
||||
import {
|
||||
AnyExtensionDataMap,
|
||||
coreExtensionData,
|
||||
createExtension,
|
||||
ExtensionDataValue,
|
||||
} from '../types';
|
||||
|
||||
/** @public */
|
||||
export function createApiExtension<
|
||||
TConfig extends {},
|
||||
TInputs extends Record<string, { extensionData: AnyExtensionDataMap }>,
|
||||
>(
|
||||
options: (
|
||||
| {
|
||||
api: AnyApiRef;
|
||||
factory: (options: {
|
||||
config: TConfig;
|
||||
inputs: {
|
||||
[pointName in keyof TInputs]: ExtensionDataValue<
|
||||
TInputs[pointName]['extensionData']
|
||||
>[];
|
||||
};
|
||||
}) => AnyApiFactory;
|
||||
}
|
||||
| {
|
||||
factory: AnyApiFactory;
|
||||
}
|
||||
) & {
|
||||
configSchema?: PortableSchema<TConfig>;
|
||||
inputs?: TInputs;
|
||||
},
|
||||
) {
|
||||
const { factory, configSchema, inputs: extensionInputs } = options;
|
||||
|
||||
const apiRef =
|
||||
'api' in options ? options.api : (factory as { api: AnyApiRef }).api;
|
||||
|
||||
return createExtension({
|
||||
id: `apis.${apiRef.id}`,
|
||||
at: 'core/apis',
|
||||
inputs: extensionInputs,
|
||||
configSchema,
|
||||
output: {
|
||||
api: coreExtensionData.apiFactory,
|
||||
},
|
||||
factory({ bind, config, inputs }) {
|
||||
if (typeof factory === 'function') {
|
||||
bind.api(factory({ config, inputs }));
|
||||
} else {
|
||||
bind.api(factory);
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -14,4 +14,5 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
export { createApiExtension } from './createApiExtension';
|
||||
export { createPageExtension } from './createPageExtension';
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { AnyApiFactory } from '@backstage/core-plugin-api';
|
||||
import { ComponentType } from 'react';
|
||||
import { PortableSchema } from './createSchemaFromZod';
|
||||
|
||||
@@ -34,6 +35,7 @@ export function createExtensionDataRef<T>(id: string): ExtensionDataRef<T> {
|
||||
export const coreExtensionData = {
|
||||
reactComponent: createExtensionDataRef<ComponentType>('core.reactComponent'),
|
||||
routePath: createExtensionDataRef<string>('core.routing.path'),
|
||||
apiFactory: createExtensionDataRef<AnyApiFactory>('core.api.factory'),
|
||||
};
|
||||
|
||||
/** @public */
|
||||
|
||||
@@ -4298,6 +4298,7 @@ __metadata:
|
||||
resolution: "@backstage/frontend-plugin-api@workspace:packages/frontend-plugin-api"
|
||||
dependencies:
|
||||
"@backstage/cli": "workspace:^"
|
||||
"@backstage/core-plugin-api": "workspace:^"
|
||||
"@backstage/frontend-app-api": "workspace:^"
|
||||
"@backstage/types": "workspace:^"
|
||||
"@testing-library/jest-dom": ^5.10.1
|
||||
|
||||
Reference in New Issue
Block a user