Skip to content

Commit fa0885e

Browse files
authored
Hubspot improvements [] (#10040)
* Refactor on config screen validation * Use sdk.cma instead of createClient * Remove unnecessary try catch * Add deploy script
1 parent dc84283 commit fa0885e

File tree

11 files changed

+35
-115
lines changed

11 files changed

+35
-115
lines changed

apps/hubspot/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,8 @@
2727
"test": "vitest",
2828
"create-app-definition": "contentful-app-scripts create-app-definition",
2929
"add-locations": "contentful-app-scripts add-locations",
30-
"deploy:staging": "contentful-app-scripts upload --ci --bundle-dir ./dist --organization-id ${TEST_ORG_ID} --definition-id 1p60PoDynErXJmD8UYlvM8 --token ${TEST_CMA_TOKEN}",
30+
"deploy": "contentful-app-scripts upload --ci --bundle-dir ./build --organization-id ${DEFINITIONS_ORG_ID} --definition-id 4u975fs1eUfiPsdaxpbQFO --token ${CONTENTFUL_CMA_TOKEN}",
31+
"deploy:staging": "contentful-app-scripts upload --ci --bundle-dir ./build --organization-id ${TEST_ORG_ID} --definition-id 1p60PoDynErXJmD8UYlvM8 --token ${TEST_CMA_TOKEN}",
3132
"upload": "contentful-app-scripts upload --bundle-dir ./build",
3233
"upload-ci": "contentful-app-scripts upload --ci --bundle-dir ./build --organization-id $CONTENTFUL_ORG_ID --definition-id $CONTENTFUL_APP_DEF_ID --token $CONTENTFUL_ACCESS_TOKEN",
3334
"upsert-actions": "contentful-app-scripts upsert-actions --ci --organization-id $CONTENTFUL_ORG_ID --definition-id $CONTENTFUL_APP_DEF_ID --token $CONTENTFUL_ACCESS_TOKEN",

apps/hubspot/src/components/ContentTypeMultiSelect.tsx

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,21 +2,19 @@ import React, { useEffect, useState } from 'react';
22
import { Box, Stack, Pill } from '@contentful/f36-components';
33
import { Multiselect } from '@contentful/f36-multiselect';
44
import { CONFIG_CONTENT_TYPE_ID, ContentType } from '../utils/utils';
5-
import { ContentTypeProps, PlainClientAPI } from 'contentful-management';
5+
import { ContentTypeProps } from 'contentful-management';
66
import { ConfigAppSDK } from '@contentful/app-sdk';
77

88
interface ContentTypeMultiSelectProps {
99
selectedContentTypes: ContentType[];
1010
setSelectedContentTypes: (contentTypes: ContentType[]) => void;
1111
sdk: ConfigAppSDK;
12-
cma: PlainClientAPI;
1312
}
1413

1514
const ContentTypeMultiSelect: React.FC<ContentTypeMultiSelectProps> = ({
1615
selectedContentTypes,
1716
setSelectedContentTypes,
1817
sdk,
19-
cma,
2018
}) => {
2119
const [availableContentTypes, setAvailableContentTypes] = useState<ContentType[]>([]);
2220
const getPlaceholderText = () => {
@@ -41,7 +39,7 @@ const ContentTypeMultiSelect: React.FC<ContentTypeMultiSelectProps> = ({
4139
let areMoreContentTypes = true;
4240

4341
while (areMoreContentTypes) {
44-
const response = await cma.contentType.getMany({
42+
const response = await sdk.cma.contentType.getMany({
4543
spaceId: sdk.ids.space,
4644
environmentId: sdk.ids.environment,
4745
query: { skip, limit },

apps/hubspot/src/locations/ConfigScreen.tsx

Lines changed: 8 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@ import {
2828
ContentType,
2929
HUBSPOT_PRIVATE_APPS_URL,
3030
} from '../utils/utils';
31-
import { createClient } from 'contentful-management';
3231
import ContentTypeMultiSelect from '../components/ContentTypeMultiSelect';
3332
import ConfigEntryService from '../utils/ConfigEntryService';
3433
import sidebarExample from '../assets/sidebar-example.png';
@@ -46,39 +45,21 @@ const ConfigScreen = () => {
4645
});
4746
const [selectedContentTypes, setSelectedContentTypes] = useState<ContentType[]>([]);
4847

49-
const cma = createClient(
50-
{ apiAdapter: sdk.cmaAdapter },
51-
{
52-
type: 'plain',
53-
defaults: {
54-
environmentId: sdk.ids.environmentAlias ?? sdk.ids.environment,
55-
spaceId: sdk.ids.space,
56-
},
57-
}
58-
);
59-
60-
function checkIfHasValue(
61-
value: string,
62-
setError: (error: string | null) => void,
63-
errorMessage: string
64-
) {
65-
const hasValue = !!value?.trim();
66-
setError(hasValue ? null : errorMessage);
67-
return hasValue;
48+
function checkIfHasValue(value: string) {
49+
return !!value?.trim();
6850
}
6951

7052
const validateAccessToken = async () => {
7153
setHubspotTokenError(null);
7254

73-
const hubspotTokenHasValue = checkIfHasValue(
74-
parameters.hubspotAccessToken,
75-
setHubspotTokenError,
76-
EMPTY_MESSAGE
77-
);
55+
const hubspotTokenHasValue = checkIfHasValue(parameters.hubspotAccessToken);
7856

7957
if (!hubspotTokenHasValue) {
58+
setHubspotTokenError(EMPTY_MESSAGE);
8059
sdk.notifier.error(EMPTY_MESSAGE);
8160
return false;
61+
} else {
62+
setHubspotTokenError(null);
8263
}
8364
return true;
8465
};
@@ -90,7 +71,7 @@ const ConfigScreen = () => {
9071
}
9172

9273
try {
93-
const configService = new ConfigEntryService(cma, sdk.locales.default);
74+
const configService = new ConfigEntryService(sdk.cma, sdk.locales.default);
9475
await configService.createConfig();
9576
} catch (e) {
9677
sdk.notifier.error('The app configuration was not saved. Please try again.');
@@ -110,7 +91,7 @@ const ConfigScreen = () => {
11091
parameters,
11192
targetState: { EditorInterface: { ...editorInterface } },
11293
};
113-
}, [parameters, sdk, cma, selectedContentTypes]);
94+
}, [parameters, sdk, selectedContentTypes]);
11495

11596
useEffect(() => {
11697
sdk.app.onConfigure(() => onConfigure());
@@ -217,7 +198,6 @@ const ConfigScreen = () => {
217198
selectedContentTypes={selectedContentTypes}
218199
setSelectedContentTypes={setSelectedContentTypes}
219200
sdk={sdk}
220-
cma={cma}
221201
/>
222202
<Subheading marginTop="spacing2Xl" marginBottom="spacingS">
223203
Getting started

apps/hubspot/src/locations/Dialog.tsx

Lines changed: 2 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import { useAutoResizer, useSDK } from '@contentful/react-apps-toolkit';
44
import { useMemo, useState, useEffect } from 'react';
55
import FieldSelection from '../components/FieldSelection';
66
import FieldModuleNameMapping from '../components/FieldModuleNameMapping';
7-
import { createClient } from 'contentful-management';
87
import { SdkField, SelectedSdkField } from '../utils/fieldsProcessing';
98
import { styles } from './Dialog.styles';
109
import ConfigEntryService from '../utils/ConfigEntryService';
@@ -22,16 +21,6 @@ enum Step {
2221

2322
const Dialog = () => {
2423
const sdk = useSDK<DialogAppSDK>();
25-
const cma = createClient(
26-
{ apiAdapter: sdk.cmaAdapter },
27-
{
28-
type: 'plain',
29-
defaults: {
30-
environmentId: sdk.ids.environment,
31-
spaceId: sdk.ids.space,
32-
},
33-
}
34-
);
3524
useAutoResizer();
3625
const invocationParams = sdk.parameters.invocation as unknown as InvocationParams;
3726
const fields = invocationParams.fields;
@@ -45,7 +34,7 @@ const Dialog = () => {
4534

4635
useEffect(() => {
4736
const fetchConnectedFields = async () => {
48-
const configService = new ConfigEntryService(cma, sdk.locales.default);
37+
const configService = new ConfigEntryService(sdk.cma, sdk.locales.default);
4938
const entryConnectedFields = await configService.getEntryConnectedFields(
5039
invocationParams.entryId
5140
);
@@ -92,7 +81,7 @@ const Dialog = () => {
9281
});
9382

9483
try {
95-
const response = await cma.appActionCall.createWithResponse(
84+
const response = await sdk.cma.appActionCall.createWithResponse(
9685
{
9786
spaceId: sdk.ids.space,
9887
environmentId: sdk.ids.environmentAlias ?? sdk.ids.environment,

apps/hubspot/src/locations/Page.tsx

Lines changed: 8 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import React, { useEffect, useState } from 'react';
22
import { Box, Flex, Heading, Spinner, Text, Note, TextLink } from '@contentful/f36-components';
33
import { useSDK } from '@contentful/react-apps-toolkit';
4-
import { createClient } from 'contentful-management';
54
import ConfigEntryService from '../utils/ConfigEntryService';
65
import { styles } from './Page.styles';
76
import { ConnectedFields, EntryWithContentType, getUniqueFieldId } from '../utils/utils';
@@ -19,23 +18,12 @@ const Page: React.FC = () => {
1918
const [modalEntry, setModalEntry] = useState<EntryWithContentType | null>(null);
2019
const [modalOpen, setModalOpen] = useState<boolean>(false);
2120

22-
const cma = createClient(
23-
{ apiAdapter: sdk.cmaAdapter },
24-
{
25-
type: 'plain',
26-
defaults: {
27-
environmentId: sdk.ids.environment,
28-
spaceId: sdk.ids.space,
29-
},
30-
}
31-
);
32-
3321
useEffect(() => {
3422
const fetchConnectedEntries = async () => {
3523
setLoading(true);
3624
setError(null);
3725
try {
38-
const configService = new ConfigEntryService(cma, defaultLocale);
26+
const configService = new ConfigEntryService(sdk.cma, defaultLocale);
3927
const connectedFields = await configService.getConnectedFields();
4028
setConnectedFields(connectedFields);
4129
const entryIds = Object.keys(connectedFields);
@@ -45,24 +33,17 @@ const Page: React.FC = () => {
4533
return;
4634
}
4735

48-
const entriesResponse = await cma.entry.getMany({ query: { 'sys.id[in]': entryIds } });
36+
const entriesResponse = await sdk.cma.entry.getMany({ query: { 'sys.id[in]': entryIds } });
4937
const fetchEntriesWithContentType = await Promise.all(
5038
entriesResponse.items.map(async (entry) => {
51-
try {
52-
const contentType = await cma.contentType.get({
53-
contentTypeId: entry.sys.contentType.sys.id,
54-
});
55-
return { entry, contentType };
56-
} catch (err) {
57-
return null;
58-
}
39+
const contentType = await sdk.cma.contentType.get({
40+
contentTypeId: entry.sys.contentType.sys.id,
41+
});
42+
return { entry, contentType };
5943
})
6044
);
6145

62-
const filteredEntries: EntryWithContentType[] = fetchEntriesWithContentType.filter(
63-
(e): e is EntryWithContentType => e !== null
64-
);
65-
setEntriesWithContentType(filteredEntries);
46+
setEntriesWithContentType(fetchEntriesWithContentType);
6647
} catch (e) {
6748
setEntriesWithContentType([]);
6849
setError(
@@ -94,7 +75,7 @@ const Page: React.FC = () => {
9475
async function handleDisconnectFields(selectedFieldIds: string[]) {
9576
if (!modalEntry) return;
9677
const entryId = modalEntry.entry.sys.id;
97-
const configService = new ConfigEntryService(cma, defaultLocale);
78+
const configService = new ConfigEntryService(sdk.cma, defaultLocale);
9879

9980
try {
10081
const currentFields = await configService.getEntryConnectedFields(entryId);

apps/hubspot/src/locations/Sidebar.tsx

Lines changed: 2 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,24 +2,13 @@ import { Button, Flex, Text, RelativeDateTime, Note, TextLink } from '@contentfu
22
import { SidebarAppSDK } from '@contentful/app-sdk';
33
import { useAutoResizer, useSDK } from '@contentful/react-apps-toolkit';
44
import { processFields } from '../utils/fieldsProcessing';
5-
import { createClient } from 'contentful-management';
65
import { useEffect, useState } from 'react';
76
import ConfigEntryService from '../utils/ConfigEntryService';
87
import { EntryConnectedFields } from '../utils/utils';
98
import { ErrorCircleOutlineIcon } from '@contentful/f36-icons';
109

1110
const Sidebar = () => {
1211
const sdk = useSDK<SidebarAppSDK>();
13-
const cma = createClient(
14-
{ apiAdapter: sdk.cmaAdapter },
15-
{
16-
type: 'plain',
17-
defaults: {
18-
environmentId: sdk.ids.environment,
19-
spaceId: sdk.ids.space,
20-
},
21-
}
22-
);
2312
useAutoResizer();
2413

2514
const [connectedFields, setConnectedFields] = useState<EntryConnectedFields | undefined>(
@@ -46,7 +35,7 @@ const Sidebar = () => {
4635
entryId: sdk.ids.entry,
4736
fields: JSON.parse(
4837
JSON.stringify(
49-
await processFields(Object.values(sdk.entry.fields), cma, sdk.locales.default)
38+
await processFields(Object.values(sdk.entry.fields), sdk.cma, sdk.locales.default)
5039
)
5140
),
5241
},
@@ -63,7 +52,7 @@ const Sidebar = () => {
6352
const getConfig = async () => {
6453
try {
6554
const entryConnectedFields = await new ConfigEntryService(
66-
cma,
55+
sdk.cma,
6756
sdk.locales.default
6857
).getEntryConnectedFields(sdk.ids.entry);
6958
setConnectedFields(entryConnectedFields);

apps/hubspot/src/utils/ConfigEntryService.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,14 @@ import {
66
ConnectedFields,
77
EntryConnectedFields,
88
} from './utils';
9+
import { CMAClient } from '@contentful/app-sdk';
910

1011
class ConfigEntryService {
11-
private cma: PlainClientAPI;
12+
private cma: CMAClient;
1213
private configEntry?: EntryProps<KeyValueMap>;
1314
private defaultLocale: string | undefined;
1415

15-
constructor(cma: PlainClientAPI, defaultLocale?: string) {
16+
constructor(cma: CMAClient | PlainClientAPI, defaultLocale?: string) {
1617
this.cma = cma;
1718
this.defaultLocale = defaultLocale;
1819
}

apps/hubspot/src/utils/fieldsProcessing.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { CMAClient, EntryFieldAPI, FieldLinkType, FieldType, Items } from '@contentful/app-sdk';
2+
import { PlainClientAPI } from 'contentful-management';
23

34
export type SdkField = {
45
type: FieldType;
@@ -30,7 +31,7 @@ const SUPPORTED_FIELD_TYPES = [
3031

3132
export const processFields = async (
3233
fields: EntryFieldAPI[],
33-
cma: CMAClient,
34+
cma: CMAClient | PlainClientAPI,
3435
defaultLocale: string
3536
) => {
3637
const processedFields: SdkField[] = [];

apps/hubspot/test/locations/Page.spec.tsx

Lines changed: 2 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,13 @@
11
import { render, waitFor, screen, cleanup, fireEvent } from '@testing-library/react';
22
import { vi, describe, beforeEach, it, expect, afterEach } from 'vitest';
33
import Page from '../../src/locations/Page';
4-
5-
const mockNavigator = { openEntry: vi.fn() };
6-
const mockSdk = {
7-
cmaAdapter: {},
8-
ids: { environment: 'env', space: 'space' },
9-
locales: { default: 'en-US' },
10-
navigator: mockNavigator,
11-
notifier: {
12-
success: vi.fn(),
13-
error: vi.fn(),
14-
},
15-
};
16-
17-
const mockCma = {
18-
entry: {
19-
get: vi.fn(),
20-
getMany: vi.fn(),
21-
},
22-
contentType: {
23-
get: vi.fn(),
24-
},
25-
};
4+
import { mockSdk } from '../mocks/mockSdk';
5+
import { mockCma } from '../mocks/mockCma';
266

277
vi.mock('@contentful/react-apps-toolkit', () => ({
288
useSDK: () => mockSdk,
299
}));
3010

31-
vi.mock('contentful-management', () => ({
32-
createClient: () => mockCma,
33-
}));
34-
3511
const mockGetConnectedFields = vi.fn();
3612
const mockGetEntryConnectedFields = vi.fn();
3713
const mockUpdateEntryConnectedFields = vi.fn();

apps/hubspot/test/mocks/mockCma.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ const mockCma = {
1111
},
1212
entry: {
1313
get: vi.fn(),
14+
getMany: vi.fn(),
1415
createWithId: vi.fn(),
1516
},
1617
editorInterface: {

0 commit comments

Comments
 (0)