Skip to content

Commit

Permalink
Adding SDK-created extensions support (#1052)
Browse files Browse the repository at this point in the history
* Adding SDK-created extensions support
  • Loading branch information
ifielker authored Oct 2, 2024
1 parent be50533 commit 5bcf13d
Show file tree
Hide file tree
Showing 11 changed files with 210 additions and 38 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ describe('ParamList', () => {
const PARAM = 'pirojok-the-param';
const LABEL = 'pirojok-the-label';
const VALUE = 'pirojok-the-value';
const extension: Extension = {
const staticExtension: Extension = {
id,
params: [
{
Expand All @@ -39,6 +39,28 @@ describe('ParamList', () => {
],
} as Extension;

const dynId = 'dyn-pirojok';
const DYN_DESCRIPTION = 'dyn-pirojok-the-description';
const DYN_PARAM = 'dyn-pirojok-the-param';
const DYN_LABEL = 'dyn-pirojok-the-label';
const DYN_VALUE = 'dyn-pirojok-the-value';
const LABELS: Record<string, string> = {
createdBy: 'SDK',
codebase: 'default',
};
const dynamicExtension: Extension = {
id: dynId,
params: [
{
param: DYN_PARAM,
label: DYN_LABEL,
value: DYN_VALUE,
description: DYN_DESCRIPTION,
},
],
labels: LABELS,
} as Extension;

function setup(extension: Extension, id: string) {
return render(
<TestExtensionsProvider extensions={[extension]} instanceId={id}>
Expand All @@ -47,20 +69,36 @@ describe('ParamList', () => {
);
}

it('renders list of parameters', () => {
const { getByText } = setup(extension, id);
it('renders list of parameters for static extensions', () => {
const { getByText } = setup(staticExtension, id);

expect(getByText(new RegExp(LABEL))).not.toBeNull();
expect(getByText(new RegExp(VALUE))).not.toBeNull();
});

it('displays param description on expansion in markdown', () => {
const { getByText } = setup(extension, id);
it('renders list of parameters for dynamic extensions', () => {
const { getByText } = setup(dynamicExtension, dynId);

expect(getByText(new RegExp(DYN_LABEL))).not.toBeNull();
expect(getByText(new RegExp(DYN_VALUE))).not.toBeNull();
});

it('displays param description on expansion in markdown for static', () => {
const { getByText } = setup(staticExtension, id);

act(() => {
getByText(new RegExp(LABEL)).click();
});
expect(getByText(new RegExp(DESCRIPTION))).not.toBeNull();
expect(getByText(new RegExp(DESCRIPTION))).not.toBeNull();
});

it('displays param description on expansion in markdown for dynamic', () => {
const { getByText } = setup(dynamicExtension, dynId);

act(() => {
getByText(new RegExp(DYN_LABEL)).click();
});
expect(getByText(new RegExp(DYN_DESCRIPTION))).not.toBeNull();
});
});
55 changes: 35 additions & 20 deletions src/components/Extensions/Details/DetailCard/Tabs/ParamList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,36 +21,51 @@ import { Callout } from '../../../../common/Callout';
import { DOCS_BASE } from '../../../../common/links/DocsLink';
import { Markdown } from '../../../../common/Markdown';
import { useExtension } from '../../../api/useExtension';
import { isDynamicExtension } from '../../../api/useExtensions';
import { EventsConfig } from './EventsConfig';
import styles from './ParamList.module.scss';
import { ParamValue } from './ParamValue';

function ParamList() {
const extension = useExtension()!;
const isDynamic = isDynamicExtension(extension);
const docSuffix = isDynamic
? 'extensions/manage-installed-extensions?interface=sdk#reconfigure'
: 'extensions/manifest';

const dynamicFragment = (
<Typography use="body2">
Reconfigure is not available in the emulator. You can reconfigure
parameters by updating them in the code.
</Typography>
);

const staticFragment = (
<>
<Typography use="body2">
Reconfigure is not available in the emulator. You can reconfigure
parameters by updating your .env files with:
</Typography>
<br />
<code>firebase ext:configure {extension.id} --local</code>)
</>
);

return (
<div>
<div className={styles.paramHeader}>
<Callout aside type="note">
<Accordion
title={
<Typography use="body2">
Reconfigure is not available in the emulator. You can
reconfigure parameters by <b>updating your .env files</b> with:
</Typography>
}
>
<code>firebase ext:configure {extension.id} --local</code>
<div className={styles.learnButton}>
<a
href={DOCS_BASE + 'extensions/manifest'}
target="_blank"
rel="noopener noreferrer"
tabIndex={-1}
>
<Button>Learn more</Button>
</a>
</div>
</Accordion>
{isDynamic ? dynamicFragment : staticFragment}
<div className={styles.learnButton}>
<a
href={DOCS_BASE + docSuffix}
target="_blank"
rel="noopener noreferrer"
tabIndex={-1}
>
<Button>Learn more</Button>
</a>
</div>
</Callout>
</div>
{(extension.params || []).map((param) => {
Expand Down
4 changes: 2 additions & 2 deletions src/components/Extensions/List/ExtensionsCallout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,12 @@ export const ExtensionCallout: React.FC<
actions={
<div className={styles.link}>
<DocsLink
href="extensions/manifest"
href="extensions/manage-installed-extensions"
target="_blank"
rel="noopener noreferrer"
>
<Typography theme="primary" use="body2" className={styles.link}>
Learn how to manage your extensions manifest
Learn how to manage your extensions
</Typography>
</DocsLink>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,11 @@ export const ExtensionsTableRow: React.FC<
{extension.ref}
</Typography>
</div>
<div>
<Typography use="body2" theme="textSecondaryOnBackground">
{extension.id}
</Typography>
</div>
</DataTableCell>
<DataTableCell className={`${styles.actionCell} actionCell`}>
<Button
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@ describe('useExtensionBackends', () => {
await waitFor(() => result.current !== null);
await waitFor(() => delay(100));

expect(result.current).toEqual([BACKEND_LIST[0], BACKEND_LIST[1]]);
expect(result.current).toEqual([
BACKEND_LIST[0],
BACKEND_LIST[1],
BACKEND_LIST[2],
]);
});
});
64 changes: 62 additions & 2 deletions src/components/Extensions/api/internal/useExtensionsData.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ describe('useExtensionsData', () => {

expect(result.current).toEqual([
{
id: 'pirojok-the-published-extension',
authorName: 'Awesome Inc',
authorUrl: 'https://google.com/awesome',
params: [],
Expand Down Expand Up @@ -93,14 +94,15 @@ describe('useExtensionsData', () => {
sourceUrl: '',
extensionDetailsUrl:
'https://firebase.google.com/products/extensions/good-tool',
id: 'pirojok-the-published-extension',

ref: 'awesome-inc/[email protected]',
iconUri:
'https://www.gstatic.com/mobilesdk/211001_mobilesdk/google-pay-logo.svg',
publisherIconUri:
'https://www.gstatic.com/mobilesdk/160503_mobilesdk/logo/2x/firebase_128dp.png',
},
{
id: 'pirojok-the-local-extension',
authorName: 'Awesome Inc',
authorUrl: 'https://google.com/awesome',
params: [],
Expand Down Expand Up @@ -150,7 +152,65 @@ describe('useExtensionsData', () => {
sourceUrl: '',
extensionDetailsUrl:
'https://firebase.google.com/products/extensions/good-tool',
id: 'pirojok-the-local-extension',
},
{
id: 'pirojok-the-dynamic-extension',
authorName: 'Awesome Inc',
authorUrl: 'https://google.com/awesome',
params: [],
name: 'good-tool',
displayName: 'Pirojok-the-tool',
specVersion: 'v1beta',
env: {
ALLOWED_EVENT_TYPES: 'google.firebase.v1.custom-event-occurred',
EVENTARC_CHANNEL:
'projects/test-project/locations/us-west1/channels/firebase',
},
allowedEventTypes: ['google.firebase.v1.custom-event-occurred'],
eventarcChannel:
'projects/test-project/locations/us-west1/channels/firebase',
events: [
{
type: 'google.firebase.v1.custom-event-occurred',
description: 'A custom event occurred',
},
],
apis: [
{
apiName: 'storage-component.googleapis.com',
reason: 'Needed to use Cloud Storage',
},
],
resources: [
{
type: 'firebaseextensions.v1beta.function',
description:
'Listens for new images uploaded to your specified Cloud Storage bucket, resizes the images, then stores the resized images in the same bucket. Optionally keeps or deletes the original images.',
name: 'generateResizedImage',
propertiesYaml:
// eslint-disable-next-line no-template-curly-in-string
'availableMemoryMb: 1024\neventTrigger:\n eventType: google.storage.object.finalize\n resource: projects/_/buckets/${param:IMG_BUCKET}\nlocation: ${param:LOCATION}\nruntime: nodejs14\n',
},
],
roles: [
{
role: 'storage.admin',
reason:
'Allows the extension to store resized images in Cloud Storage',
},
],
readmeContent: '',
postinstallContent: '### See it in action',
sourceUrl: '',
extensionDetailsUrl:
'https://firebase.google.com/products/extensions/good-tool',

ref: 'awesome-inc/[email protected]',
iconUri:
'https://www.gstatic.com/mobilesdk/211001_mobilesdk/google-pay-logo.svg',
publisherIconUri:
'https://www.gstatic.com/mobilesdk/160503_mobilesdk/logo/2x/firebase_128dp.png',
labels: { createdBy: 'SDK', codebase: 'default' },
},
]);
});
Expand Down
15 changes: 11 additions & 4 deletions src/components/Extensions/api/internal/useExtensionsData.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,11 @@
* limitations under the License.
*/
import { Extension, ExtensionResource, Resource } from '../../models';
import { ExtensionBackend, isLocalExtension } from '../useExtensions';
import {
ExtensionBackend,
isDynamicExtension,
isLocalExtension,
} from '../useExtensions';
import { useExtensionBackends } from './useExtensionBackends';

const EXTENSION_DETAILS_URL_BASE =
Expand Down Expand Up @@ -46,7 +50,8 @@ export function convertBackendToExtension(
: r;
};

const shared = {
const shared: Omit<Extension, 'authorName'> = {
id: backend.extensionInstanceId,
authorUrl: spec.author?.url ?? '',
params: spec.params.map((p) => {
return {
Expand All @@ -70,17 +75,19 @@ export function convertBackendToExtension(
extensionDetailsUrl: EXTENSION_DETAILS_URL_BASE + spec.name,
};

if (isDynamicExtension(backend)) {
shared.labels = backend.labels;
}

if (isLocalExtension(backend)) {
return {
...shared,
authorName: spec.author?.authorName ?? '',
id: backend.extensionInstanceId,
};
}

return {
...shared,
id: backend.extensionInstanceId,
ref: backend.extensionVersion.ref,
authorName:
spec.author?.authorName ??
Expand Down
18 changes: 16 additions & 2 deletions src/components/Extensions/api/useExtensions.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,11 @@

import { renderHook } from '@testing-library/react';

import { EXTENSION } from '../testing/utils';
import { DYNAMIC_EXTENSION, EXTENSION } from '../testing/utils';
import { ExtensionsProvider, useExtensions } from './useExtensions';

describe('useExtensions', () => {
it('returns the list of extension backends', () => {
it('returns the list of static extension backends', () => {
const wrapper: React.FC<React.PropsWithChildren<unknown>> = ({
children,
}) => (
Expand All @@ -33,4 +33,18 @@ describe('useExtensions', () => {

expect(result.current).toEqual([EXTENSION]);
});

it('returns the list of dynamic extension backends', () => {
const wrapper: React.FC<React.PropsWithChildren<unknown>> = ({
children,
}) => (
<ExtensionsProvider extensions={[DYNAMIC_EXTENSION]}>
{children}
</ExtensionsProvider>
);

const { result } = renderHook(() => useExtensions(), { wrapper });

expect(result.current).toEqual([DYNAMIC_EXTENSION]);
});
});
7 changes: 7 additions & 0 deletions src/components/Extensions/api/useExtensions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ interface CommonExtensionBackend {
env: Record<string, string>;
extensionInstanceId: string;
functionTriggers: FunctionTrigger[];
labels?: Record<string, string>;
}

interface PublishedExtensionBackend extends CommonExtensionBackend {
Expand Down Expand Up @@ -72,3 +73,9 @@ export function isLocalExtension(
): backend is LocalExtensionBackend {
return backend.hasOwnProperty('extensionSpec');
}

export function isDynamicExtension(
extension: Extension | ExtensionBackend
): boolean {
return extension.labels?.createdBy === 'SDK';
}
3 changes: 3 additions & 0 deletions src/components/Extensions/models.ts
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,9 @@ export interface Extension {
sourceUrl: string;
postinstallContent: string;
extensionDetailsUrl: string;
name?: string;
env?: Record<string, string>;
labels?: Record<string, string>;
}

export interface ExternalService {
Expand Down
Loading

0 comments on commit 5bcf13d

Please sign in to comment.