Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update subhub link checker deps #226

Merged
merged 11 commits into from
Feb 23, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 15 additions & 1 deletion subhub-link-checker/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,21 @@ Written with React/TypeScript/Contentful App Framework.
Part of the Hub Expansion project. This is required due to SubHub routing logic in the frontend.

There are three instances of the Contentful App - one for dev, test and prod. [Read more...](https://www.contentful.com/developers/docs/extensibility/app-framework/)

## Seeing and deploying your changes
This assumes the Contentful environments are set up with the required app definitions. See the First time deployment section if you need to redo those steps.

ResearchHub has three Contentful environments - `dev`, `test`, and `prod`, and `prod` is the one content authors see. Use `dev` for previewing your changes and manual testing - Contentful Apps can't be run locally. Deployment to `test` and `prod` should only be done as part of [the official release process](https://wiki.auckland.ac.nz/display/APPLCTN/Release+to+prod) and content authors need to be notified before deploying updates.

1. If you are deploying to `test` and `prod`, first check-in your changes to Git and merge them into `master`.
1. Run `npm run build` to build a new bundle.
2. Run `npm run upload`.
1. For the bundle comment, put in the hash of Git commit you built the bundle from if applicable.
2. Follow on-screen instructions to paste in your access token.
3. Choose your organisation (should be University of Auckland.)
4. Choose the app definition you want to upload to - the name should match the environment you're deploying to.
3. Go to Contentful to see your changes.

## First time deployment

1. Create three Apps on Contentful. In the `subhub-link-checker` folder, run the command:
Expand Down Expand Up @@ -44,7 +59,6 @@ There are three instances of the Contentful App - one for dev, test and prod. [R

Open a SubHub to verify the Internal Pages field is still editable. If it is, then the App setup is complete!

Run `npm run upload` if you'd like to do an ad-hoc manual update - first deploying to the dev App instance, then to the others.
## Development
This project was bootstrapped with [Create Contentful App](https://github.com/contentful/create-contentful-app).

Expand Down
46,552 changes: 32,637 additions & 13,915 deletions subhub-link-checker/package-lock.json

Large diffs are not rendered by default.

25 changes: 12 additions & 13 deletions subhub-link-checker/package.json
Original file line number Diff line number Diff line change
@@ -1,28 +1,27 @@
{
"name": "hub-subhub-link-checker",
"version": "0.1.0",
"version": "0.2.0",
"private": true,
"dependencies": {
"@contentful/app-sdk": "^3.38.0",
"@contentful/field-editor-single-line": "^0.14.6",
"@contentful/field-editor-test-utils": "^0.16.0",
"@contentful/forma-36-fcss": "^0.3.2",
"@contentful/forma-36-react-components": "^3.90.7",
"@contentful/forma-36-tokens": "^0.10.2",
"@contentful/field-editor-reference": "^2.18.0",
"@contentful/app-sdk": "^4.2.0",
"@contentful/f36-components": "^4.0.17",
"@contentful/f36-tokens": "^4.0.0",
"@contentful/field-editor-reference": "^4.1.0",
"@contentful/field-editor-single-line": "^1.1.0",
"@contentful/field-editor-test-utils": "^1.1.0",
"@testing-library/jest-dom": "^5.14.1",
"@testing-library/react": "^12.0.0",
"@testing-library/user-event": "^13.1.9",
"@types/jest": "^26.0.24",
"@types/node": "^16.0.2",
"@types/react": "^17.0.14",
"@types/react-dom": "^17.0.9",
"@types/react-dom": "^17.0.11",
"cross-env": "^7.0.3",
"gh-pages": "^3.1.0",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-scripts": "4.0.3",
"typescript": "^4.3.5",
"gh-pages": "^3.1.0"
"react-scripts": "5.0.0",
"typescript": "^4.3.5"
},
"scripts": {
"start": "cross-env BROWSER=none react-scripts start",
Expand All @@ -48,7 +47,7 @@
]
},
"devDependencies": {
"@contentful/app-scripts": "^0.8.49"
"@contentful/app-scripts": "^0.14.130"
},
"homepage": "."
}
11 changes: 0 additions & 11 deletions subhub-link-checker/src/components/Dialog.spec.tsx

This file was deleted.

13 changes: 0 additions & 13 deletions subhub-link-checker/src/components/Dialog.tsx

This file was deleted.

5 changes: 3 additions & 2 deletions subhub-link-checker/src/components/Field.spec.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import React from 'react';
import Field from './Field';
import { render } from '@testing-library/react';
import { mockSdk } from '../../test/mocks';

describe('Field component', () => {
it('Component text exists', () => {
const { getByText } = render(<Field />);
const { getByText } = render(<Field sdk={mockSdk} />);

expect(getByText('Hello Entry Field Component')).toBeInTheDocument();
// Add more tests here.
});
});
96 changes: 50 additions & 46 deletions subhub-link-checker/src/components/Field.tsx
Original file line number Diff line number Diff line change
@@ -1,33 +1,33 @@
import React, { useEffect } from 'react';
import { CollectionResponse, EntrySys, FieldExtensionSDK } from '@contentful/app-sdk';
import { ContentEntitySys, FieldExtensionSDK } from '@contentful/app-sdk';
import { CombinedLinkActions, MultipleEntryReferenceEditor } from '@contentful/field-editor-reference';
import { Entry } from '@contentful/field-editor-reference/dist/types';
import { LinkActionsProps } from '@contentful/field-editor-reference/dist/components';
import "./Field.css";
import { createClient, Environment } from 'contentful-management';

interface FieldProps {
sdk: FieldExtensionSDK;
}

function checkPageReferences(sdk: FieldExtensionSDK, subhubSys: EntrySys, pageSys: EntrySys): Promise<Boolean> {
async function checkPageReferences(environment: Environment, subhubSys: ContentEntitySys, pageSys: ContentEntitySys): Promise<Boolean> {
console.log(`Checking page reference for subhub ${subhubSys.id} and page ${pageSys.id}`);
// First, check if the content author is trying to link a subhub to itself.
if (subhubSys.type === pageSys.type && subhubSys.id === pageSys.id) {
console.log("Subhub and page are the same, rejecting.");
return Promise.resolve(false);
return false;
}
// Fetch other subhubs that have links to this page.
return sdk.space.getEntries({
const entries = await environment.getEntries({
"content_type": "subHub",
"fields.internalPages.sys.id": pageSys.id,
"sys.id[ne]": subhubSys.id
}).then((entries: CollectionResponse<Object>) => {
console.log(`Found ${entries.items.length} other Subhub(s) that contain this page.`);
if (entries.items.length > 0) {
console.log("Other SubHub(s) containing this page",entries.items);
}
return entries.items.length === 0;
});
console.log(`Found ${entries.items.length} other Subhub(s) that contain this page.`);
if (entries.items.length > 0) {
console.log("Other SubHub(s) containing this page",entries.items);
}
return entries.items.length === 0;
}

const doFailedAlertDialog = (sdk: FieldExtensionSDK, hasMultiplePages: boolean, failedPageNames : string[]) => {
Expand Down Expand Up @@ -64,50 +64,54 @@ interface CustomLinkActionsProps {

const CustomLinkActions = ({inheritedProps:props, sdk}: CustomLinkActionsProps) => {
const locale = sdk.locales.default;
// Get the current contentful Space.
const cma = createClient(
{ apiAdapter: sdk.cmaAdapter }
);
return <CombinedLinkActions
{...props}
onLinkExisting={index => {
onLinkExisting={async (index) => {
// This callback is called when the user wants to "link" existing pages to the subhub's internalPages collection.
const contentTypes = getContentTypesAcceptedByField(sdk);
sdk.dialogs
.selectMultipleEntries({
const space = await cma.getSpace(sdk.ids.space);
const environment = await space.getEnvironment(sdk.ids.environment);
const entries = await sdk.dialogs.selectMultipleEntries({
locale: sdk.field.locale,
contentTypes
})
.then((entries) => {
if (!entries || entries.length === 0) {
return;
}
// Check all entries are ok.
const subhubSys = sdk.entry.getSys();
return Promise.all(
entries.map(entry => checkPageReferences(sdk, subhubSys, (entry as Entry).sys))
).then(results => {
const failedEntries = entries.filter((entry, i) => !results[i]);
if (failedEntries.length === 0) {
// All OK! Will add all entries to entry list.
props.onLinkedExisting(entries as Entry[], index);
return;
} else {
// There were some pages that didn't pass the check. Do not allow them to be entered.
const hasMultiplePages = entries.length !== 1;
const failedPageNames = failedEntries.map(entry => {
const title = (entry as Entry).fields.title;
return title ? title[locale] : "(Untitled content)";
});
doFailedAlertDialog(sdk, hasMultiplePages, failedPageNames);
return;
}
});
}).catch(reason => {
sdk.dialogs.openAlert({
title: "Error occurred in the SubHub link checking application",
message: "Sorry, an error occurred while adding your page(s) to the SubHub Internal Pages field. " +
"Please try again. If problems persist, please message the ResearchHub team for assistance. " +
"You can also add your page(s) to the External Pages field as a workaround."
});
if (!entries || entries.length === 0) {
return;
}
// Check all entries are ok.
const subhubSys = sdk.entry.getSys();
try {
const results = await Promise.all(
entries.map(entry => checkPageReferences(environment, subhubSys, (entry as Entry).sys))
);
const failedEntries = entries.filter((entry, i) => !results[i]);
if (failedEntries.length === 0) {
// All OK! Will add all entries to entry list.
props.onLinkedExisting(entries as Entry[], index);
return;
} else {
// There were some pages that didn't pass the check. Do not allow them to be entered.
const hasMultiplePages = entries.length !== 1;
const failedPageNames = failedEntries.map(entry => {
const title = (entry as Entry).fields.title;
return title ? title[locale] : "(Untitled content)";
});
console.log("Error occurred in SubHub link checking application", reason);
doFailedAlertDialog(sdk, hasMultiplePages, failedPageNames);
return;
}
} catch (reason) {
sdk.dialogs.openAlert({
title: "Error occurred in the SubHub link checking application",
message: "Sorry, an error occurred while adding your page(s) to the SubHub Internal Pages field. " +
"Please try again. If problems persist, please message the ResearchHub team for assistance. " +
"You can also add your page(s) to the External Pages field as a workaround."
});
console.log("Error occurred in SubHub link checking application", reason);
}
}}
/>
};
Expand Down
13 changes: 8 additions & 5 deletions subhub-link-checker/src/components/LocalhostWarning.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import React from 'react';
import { Paragraph, TextLink, Note } from '@contentful/forma-36-react-components';

import { Note, TextLink, Paragraph } from "@contentful/f36-components";

const LocalhostWarning = () => {
return (
Expand All @@ -10,19 +11,21 @@ const LocalhostWarning = () => {
marginTop: '40px'
}}>
<Note title="App running outside of Contentful" style={{ maxWidth: '800px' }}>
<Paragraph>
<Paragraph marginBottom="none">
Contentful Apps need to run inside the Contentful web app to function properly. Install
the app into a space and render your app into one of the{' '}
<TextLink href="https://www.contentful.com/developers/docs/extensibility/ui-extensions/sdk-reference/#locations">
<TextLink
href="https://www.contentful.com/developers/docs/extensibility/ui-extensions/sdk-reference/#locations">
available locations
</TextLink>
.
</Paragraph>
<br />

<Paragraph>
<Paragraph marginBottom="none">
Follow{' '}
<TextLink href="https://www.contentful.com/developers/docs/extensibility/app-framework/tutorial/">
<TextLink
href="https://www.contentful.com/developers/docs/extensibility/app-framework/tutorial/">
our guide
</TextLink>{' '}
to get started or{' '}
Expand Down
11 changes: 0 additions & 11 deletions subhub-link-checker/src/components/Page.spec.tsx

This file was deleted.

13 changes: 0 additions & 13 deletions subhub-link-checker/src/components/Page.tsx

This file was deleted.

10 changes: 0 additions & 10 deletions subhub-link-checker/src/index.css
Original file line number Diff line number Diff line change
@@ -1,10 +0,0 @@
html,
body,
div {
margin: 0;
padding: 0;
border: 0;
font-size: 100%;
font: inherit;
vertical-align: baseline;
}
17 changes: 1 addition & 16 deletions subhub-link-checker/src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,12 @@ import { render } from 'react-dom';

import {
FieldExtensionSDK,
DialogExtensionSDK,
PageExtensionSDK,
init,
locations,
} from '@contentful/app-sdk';
import '@contentful/forma-36-react-components/dist/styles.css';
import '@contentful/forma-36-fcss/dist/styles.css';
import '@contentful/forma-36-tokens/dist/css/index.css';
import './index.css';

import Page from './components/Page';
import Field from './components/Field';
import Dialog from './components/Dialog';

import LocalhostWarning from './components/LocalhostWarning';

Expand All @@ -34,15 +27,7 @@ if (process.env.NODE_ENV === 'development' && window.self === window.top) {
{
location: locations.LOCATION_ENTRY_FIELD,
component: <Field sdk={sdk as FieldExtensionSDK} />,
},
{
location: locations.LOCATION_DIALOG,
component: <Dialog sdk={sdk as DialogExtensionSDK} />,
},
{
location: locations.LOCATION_PAGE,
component: <Page sdk={sdk as PageExtensionSDK} />,
},
}
];

// Select a component depending on a location in which the app is rendered.
Expand Down
2 changes: 2 additions & 0 deletions subhub-link-checker/test/mocks/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export { mockCma } from './mockCma.ts';
export { mockSdk } from './mockSdk.ts';
3 changes: 3 additions & 0 deletions subhub-link-checker/test/mocks/mockCma.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
const mockCma: any = {};

export { mockCma };
10 changes: 10 additions & 0 deletions subhub-link-checker/test/mocks/mockSdk.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
const mockSdk: any = {
app: {
onConfigure: jest.fn(),
getParameters: jest.fn().mockReturnValueOnce({}),
setReady: jest.fn(),
getCurrentState: jest.fn(),
},
};

export { mockSdk };