AnalyticsBlueprint -> AnalyticsImplementationBlueprint
Signed-off-by: Eric Peterson <ericpeterson@spotify.com>
This commit is contained in:
@@ -2,12 +2,12 @@
|
||||
'@backstage/frontend-plugin-api': patch
|
||||
---
|
||||
|
||||
Plugins should now use the new `AnalyticsBlueprint` to define and provide concrete analytics implementations. For example:
|
||||
Plugins should now use the new `AnalyticsImplementationBlueprint` to define and provide concrete analytics implementations. For example:
|
||||
|
||||
```ts
|
||||
import { AnalyticsBlueprint } from '@backstage/frontend-plugin-api';
|
||||
import { AnalyticsImplementationBlueprint } from '@backstage/frontend-plugin-api';
|
||||
|
||||
const AcmeAnalytics = AnalyticsBlueprint.make({
|
||||
const AcmeAnalytics = AnalyticsImplementationBlueprint.make({
|
||||
name: 'acme-analytics',
|
||||
params: define =>
|
||||
define({
|
||||
|
||||
@@ -2,4 +2,4 @@
|
||||
'@backstage/plugin-app': patch
|
||||
---
|
||||
|
||||
The default implementation of the Analytics API now collects and instantiates analytics implementations exposed via `AnalyticsBlueprint` extensions. If no such extensions are discovered, the API continues to do nothing with analytics events fired within Backstage. If multiple such extensions are discovered, every discovered implementation automatically receives analytics events.
|
||||
The default implementation of the Analytics API now collects and instantiates analytics implementations exposed via `AnalyticsImplementationBlueprint` extensions. If no such extensions are discovered, the API continues to do nothing with analytics events fired within Backstage. If multiple such extensions are discovered, every discovered implementation automatically receives analytics events.
|
||||
|
||||
+26
-24
@@ -103,22 +103,23 @@ export const apis: AnyApiFactory[] = [
|
||||
];
|
||||
|
||||
// Or, when building for the new frontend system:
|
||||
import { AnalyticsBlueprint } from '@backstage/frontend-plugin-api';
|
||||
import { AnalyticsImplementationBlueprint } from '@backstage/frontend-plugin-api';
|
||||
|
||||
export const acmeAnalyticsImplementation = AnalyticsBlueprint.make({
|
||||
name: 'acme',
|
||||
params: define =>
|
||||
define({
|
||||
deps: {},
|
||||
factory() {
|
||||
return {
|
||||
captureEvent: event => {
|
||||
window._AcmeAnalyticsQ.push(event);
|
||||
},
|
||||
};
|
||||
},
|
||||
}),
|
||||
});
|
||||
export const acmeAnalyticsImplementation =
|
||||
AnalyticsImplementationBlueprint.make({
|
||||
name: 'acme',
|
||||
params: define =>
|
||||
define({
|
||||
deps: {},
|
||||
factory() {
|
||||
return {
|
||||
captureEvent: event => {
|
||||
window._AcmeAnalyticsQ.push(event);
|
||||
},
|
||||
};
|
||||
},
|
||||
}),
|
||||
});
|
||||
```
|
||||
|
||||
In reality, you would likely want to encapsulate instantiation logic and pull
|
||||
@@ -160,16 +161,17 @@ export const apis: AnyApiFactory[] = [
|
||||
];
|
||||
|
||||
// Or, when building for the new frontend system:
|
||||
import { AnalyticsBlueprint } from '@backstage/frontend-plugin-api';
|
||||
import { AnalyticsImplementationBlueprint } from '@backstage/frontend-plugin-api';
|
||||
|
||||
export const acmeAnalyticsImplementation = AnalyticsBlueprint.make({
|
||||
name: 'acme',
|
||||
params: define =>
|
||||
define({
|
||||
deps: { configApi: configApiRef },
|
||||
factory: ({ configApi }) => AcmeAnalytics.fromConfig(configApi),
|
||||
}),
|
||||
});
|
||||
export const acmeAnalyticsImplementation =
|
||||
AnalyticsImplementationBlueprint.make({
|
||||
name: 'acme',
|
||||
params: define =>
|
||||
define({
|
||||
deps: { configApi: configApiRef },
|
||||
factory: ({ configApi }) => AcmeAnalytics.fromConfig(configApi),
|
||||
}),
|
||||
});
|
||||
```
|
||||
|
||||
If you are integrating with an analytics service (as opposed to an internal
|
||||
|
||||
@@ -107,30 +107,6 @@ export type AnalyticsApi = {
|
||||
// @public
|
||||
export const analyticsApiRef: ApiRef<AnalyticsApi>;
|
||||
|
||||
// @public
|
||||
export const AnalyticsBlueprint: ExtensionBlueprint<{
|
||||
kind: 'analytics';
|
||||
name: undefined;
|
||||
params: <TDeps extends { [name in string]: unknown }>(
|
||||
params: AnalyticsImplementationFactory<TDeps>,
|
||||
) => ExtensionBlueprintParams<AnalyticsImplementationFactory<{}>>;
|
||||
output: ConfigurableExtensionDataRef<
|
||||
AnalyticsImplementationFactory<{}>,
|
||||
'core.analytics.factory',
|
||||
{}
|
||||
>;
|
||||
inputs: {};
|
||||
config: {};
|
||||
configInput: {};
|
||||
dataRefs: {
|
||||
factory: ConfigurableExtensionDataRef<
|
||||
AnalyticsImplementationFactory<{}>,
|
||||
'core.analytics.factory',
|
||||
{}
|
||||
>;
|
||||
};
|
||||
}>;
|
||||
|
||||
// @public
|
||||
export const AnalyticsContext: (options: {
|
||||
attributes: Partial<AnalyticsContextValue>;
|
||||
@@ -164,6 +140,30 @@ export type AnalyticsImplementation = {
|
||||
captureEvent(event: AnalyticsEvent): void;
|
||||
};
|
||||
|
||||
// @public
|
||||
export const AnalyticsImplementationBlueprint: ExtensionBlueprint<{
|
||||
kind: 'analytics';
|
||||
name: undefined;
|
||||
params: <TDeps extends { [name in string]: unknown }>(
|
||||
params: AnalyticsImplementationFactory<TDeps>,
|
||||
) => ExtensionBlueprintParams<AnalyticsImplementationFactory<{}>>;
|
||||
output: ConfigurableExtensionDataRef<
|
||||
AnalyticsImplementationFactory<{}>,
|
||||
'core.analytics.factory',
|
||||
{}
|
||||
>;
|
||||
inputs: {};
|
||||
config: {};
|
||||
configInput: {};
|
||||
dataRefs: {
|
||||
factory: ConfigurableExtensionDataRef<
|
||||
AnalyticsImplementationFactory<{}>,
|
||||
'core.analytics.factory',
|
||||
{}
|
||||
>;
|
||||
};
|
||||
}>;
|
||||
|
||||
// @public (undocumented)
|
||||
export type AnalyticsImplementationFactory<
|
||||
Deps extends {
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
import { ApiRef, createApiRef } from '@backstage/core-plugin-api';
|
||||
import { AnalyticsContextValue } from '../../analytics/types';
|
||||
import type { AnalyticsBlueprint } from '../../blueprints/';
|
||||
import type { AnalyticsImplementationBlueprint } from '../../blueprints/';
|
||||
|
||||
/**
|
||||
* Represents an event worth tracking in an analytics system that could inform
|
||||
@@ -149,8 +149,8 @@ export type AnalyticsApi = {
|
||||
*
|
||||
* @remarks
|
||||
*
|
||||
* To define a concrete Analytics Implementation, use {@link AnalyticsBlueprint}
|
||||
* instead.
|
||||
* To define a concrete Analytics Implementation, use
|
||||
* {@link AnalyticsImplementationBlueprint} instead.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
|
||||
+2
-2
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { AnalyticsBlueprint } from './AnalyticsBlueprint';
|
||||
import { AnalyticsImplementationBlueprint } from './AnalyticsImplementationBlueprint';
|
||||
|
||||
describe('AnalyticsBlueprint', () => {
|
||||
it('should create an extension with sensible defaults', () => {
|
||||
@@ -23,7 +23,7 @@ describe('AnalyticsBlueprint', () => {
|
||||
factory: () => ({ captureEvent: () => {} }),
|
||||
};
|
||||
|
||||
const extension = AnalyticsBlueprint.make({
|
||||
const extension = AnalyticsImplementationBlueprint.make({
|
||||
params: define => define(factory),
|
||||
name: 'test',
|
||||
});
|
||||
+1
-1
@@ -39,7 +39,7 @@ const factoryDataRef =
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export const AnalyticsBlueprint = createExtensionBlueprint({
|
||||
export const AnalyticsImplementationBlueprint = createExtensionBlueprint({
|
||||
kind: 'analytics',
|
||||
attachTo: [{ id: 'api:app/analytics', input: 'analyticsImplementations' }],
|
||||
output: [factoryDataRef],
|
||||
@@ -15,9 +15,9 @@
|
||||
*/
|
||||
|
||||
export {
|
||||
AnalyticsBlueprint,
|
||||
AnalyticsImplementationBlueprint,
|
||||
type AnalyticsImplementationFactory,
|
||||
} from './AnalyticsBlueprint';
|
||||
} from './AnalyticsImplementationBlueprint';
|
||||
export { ApiBlueprint } from './ApiBlueprint';
|
||||
export { AppRootElementBlueprint } from './AppRootElementBlueprint';
|
||||
export { AppRootWrapperBlueprint } from './AppRootWrapperBlueprint';
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
import { createExtensionTester } from '@backstage/frontend-test-utils';
|
||||
import { AnalyticsApi } from './AnalyticsApi';
|
||||
import {
|
||||
AnalyticsBlueprint,
|
||||
AnalyticsImplementationBlueprint,
|
||||
AnalyticsImplementation,
|
||||
ApiBlueprint,
|
||||
configApiRef,
|
||||
@@ -38,10 +38,10 @@ describe('AnalyticsApi', () => {
|
||||
const MockImplementation1 = createExtension({
|
||||
name: 'mock-implementation-1',
|
||||
attachTo: { id: 'api:analytics', input: 'analyticsImplementations' },
|
||||
output: [AnalyticsBlueprint.dataRefs.factory],
|
||||
output: [AnalyticsImplementationBlueprint.dataRefs.factory],
|
||||
factory() {
|
||||
return [
|
||||
AnalyticsBlueprint.dataRefs.factory({
|
||||
AnalyticsImplementationBlueprint.dataRefs.factory({
|
||||
deps: { configApi: configApiRef },
|
||||
factory: deps => ({
|
||||
captureEvent: event => captureEventSpy1(event, deps),
|
||||
@@ -54,10 +54,10 @@ describe('AnalyticsApi', () => {
|
||||
const MockImplementation2 = createExtension({
|
||||
name: 'mock-implementation-2',
|
||||
attachTo: { id: 'api:analytics', input: 'analyticsImplementations' },
|
||||
output: [AnalyticsBlueprint.dataRefs.factory],
|
||||
output: [AnalyticsImplementationBlueprint.dataRefs.factory],
|
||||
factory() {
|
||||
return [
|
||||
AnalyticsBlueprint.dataRefs.factory({
|
||||
AnalyticsImplementationBlueprint.dataRefs.factory({
|
||||
deps: { config: configApiRef, identityApi: identityApiRef },
|
||||
factory: deps => ({
|
||||
captureEvent: event => captureEventSpy2(event, deps),
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
import {
|
||||
analyticsApiRef,
|
||||
AnalyticsBlueprint,
|
||||
AnalyticsImplementationBlueprint,
|
||||
ApiBlueprint,
|
||||
ApiRef,
|
||||
createExtensionInput,
|
||||
@@ -26,7 +26,7 @@ export const AnalyticsApi = ApiBlueprint.makeWithOverrides({
|
||||
name: 'analytics',
|
||||
inputs: {
|
||||
analyticsImplementations: createExtensionInput([
|
||||
AnalyticsBlueprint.dataRefs.factory,
|
||||
AnalyticsImplementationBlueprint.dataRefs.factory,
|
||||
]),
|
||||
},
|
||||
factory(originalFactory, { inputs }) {
|
||||
@@ -35,7 +35,9 @@ export const AnalyticsApi = ApiBlueprint.makeWithOverrides({
|
||||
// if they were its own deps.
|
||||
const aggregatedDeps = inputs.analyticsImplementations
|
||||
.flatMap<ApiRef<unknown>>(impls =>
|
||||
Object.values(impls.get(AnalyticsBlueprint.dataRefs.factory).deps),
|
||||
Object.values(
|
||||
impls.get(AnalyticsImplementationBlueprint.dataRefs.factory).deps,
|
||||
),
|
||||
)
|
||||
.reduce<{ [x: string]: ApiRef<unknown> }>((accum, ref) => {
|
||||
accum[ref.id] = ref;
|
||||
@@ -48,7 +50,9 @@ export const AnalyticsApi = ApiBlueprint.makeWithOverrides({
|
||||
deps: aggregatedDeps,
|
||||
factory: analyticsApiDeps => {
|
||||
const actualApis = inputs.analyticsImplementations
|
||||
.map(impl => impl.get(AnalyticsBlueprint.dataRefs.factory))
|
||||
.map(impl =>
|
||||
impl.get(AnalyticsImplementationBlueprint.dataRefs.factory),
|
||||
)
|
||||
.map(({ factory, deps }) =>
|
||||
factory(
|
||||
// Reconstruct a deps argument to pass to this analytics
|
||||
|
||||
Reference in New Issue
Block a user