Skip to content

Commit

Permalink
initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
pauloamgomes committed May 8, 2023
0 parents commit 7666a57
Show file tree
Hide file tree
Showing 39 changed files with 4,608 additions and 0 deletions.
4 changes: 4 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@

CONTENTFUL_ACCESS_TOKEN=
CONTENTFUL_ORG_ID=
CONTENTFUL_APP_DEF_ID=
14 changes: 14 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# dependencies
/node_modules

# testing
/coverage

# misc
.DS_Store

npm-debug.log*
yarn-debug.log*
yarn-error.log*

.env
21 changes: 21 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2023 Paulo Gomes

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
88 changes: 88 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
# Contentful Broken References App

The Contentful Broken References App is a simple [Contentful App](https://www.contentful.com/developers/docs/extensibility/app-framework/) providing an interface to bulk identify broken references in the contents.

A broken reference occurs when the linked entry is deleted or unpublished, making it inaccessible to the reference field.
Typically and depending on how your application is built a broken reference can results in an error, causing issues, such as missing content or broken relationships. To ensure data integrity and avoid these issues, this App will help to identify and resolve broken references in your Contentful entries.

[![](./docs/app-video-play.gif)](https://www.loom.com/share/1ca2aa82244a417e8dd317dfdc4fc780)

## 🛠 Setup

Install the App using by doing the below steps:

1. Create a new Contentful custom App and define the Application Name (e.g. Broken References)

2. Download this repo and drag the dist folder into the Bundles upload zone:

![App Bundles Upload](./docs//app-bundles-upload.png)

Give a name to the bundle

![App Bundles Uploade](./docs//app-bundles-uploaded.png)

You can find more details about hosting an [Contentful app her](https://www.contentful.com/developers/docs/extensibility/app-framework/hosting-an-app/)

3. Set the App configuration screen and Page location

![App Locations](./docs//app-locations.png)

4. Save, and Install the App in your space, on the space configuration screen fill the Contentful Delivery Access token.

![App Configuration Screen](./docs//app-config-screen.png)

5. The App should be available in the Apps menu:

![Apps Menu](./docs//app-apps-page.png)

6. Open the App and it will automatically analyze and display if any, a list of broken references:

![Apps Menu](./docs//app-page.png)

Clicking in the broken reference items will open the affected entry and you'll be able to fix it.

## 🥷 Development

In the project directory, you can run:

#### `yarn start`

Creates or updates your app definition in Contentful, and runs the app in development mode.
Open your app to view it in the browser.

The page will reload if you make edits.
You will also see any lint errors in the console.

#### `yarn build`

Builds the app for production to the `dist` folder.
It correctly bundles React in production mode and optimizes the build for the best performance.

The build is minified and the filenames include the hashes.
Your app is ready to be deployed!

#### `yarn upload`

Uploads the `dist` folder to Contentful and creates a bundle that is automatically activated.
The command guides you through the deployment process and asks for all required arguments.
Read [here](https://www.contentful.com/developers/docs/extensibility/app-framework/create-contentful-app/#deploy-with-contentful) for more information about the deployment process.

#### `yarn upload-ci`

Similar to `yarn upload` it will upload your app to contentful and activate it. The only difference is
that with this command all required arguments are read from the environment variables, for example when you add
the upload command to your CI pipeline.

For this command to work, the following environment variables must be set:

- `CONTENTFUL_ORG_ID` - The ID of your organization
- `CONTENTFUL_APP_DEF_ID` - The ID of the app to which to add the bundle
- `CONTENTFUL_ACCESS_TOKEN` - A personal [access token](https://www.contentful.com/developers/docs/references/content-management-api/#/reference/personal-access-tokens)

## 💡Learn more

This project was bootstrapped with [Create Contentful App](https://github.com/contentful/create-contentful-app).

## Copyright and license

Copyright 2023 pauloamgomes under the MIT license.
376 changes: 376 additions & 0 deletions dist/assets/index.a5547887.js

Large diffs are not rendered by default.

22 changes: 22 additions & 0 deletions dist/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<script type="module" crossorigin src="./assets/index.a5547887.js"></script>
</head>

<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>

<!--
This HTML file is a template.
If you open it directly in the browser, you will see an empty page.
You can add webfonts, meta tags, or analytics to this file.
The build step will place the bundled scripts into the <body> tag.
To begin the development, run `npm start`.
To create a production bundle, use `npm run build`.
-->
</body>
</html>
Binary file added docs/app-apps-page.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/app-bundles-upload.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/app-bundles-uploaded.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/app-config-screen.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/app-locations.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/app-page.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/app-video-play.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
21 changes: 21 additions & 0 deletions index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
</head>

<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
<script type="module" src="/src/index.tsx"></script>
<!--
This HTML file is a template.
If you open it directly in the browser, you will see an empty page.
You can add webfonts, meta tags, or analytics to this file.
The build step will place the bundled scripts into the <body> tag.
To begin the development, run `npm start`.
To create a production bundle, use `npm run build`.
-->
</body>
</html>
37 changes: 37 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
{
"name": "contentful-broken-references-app",
"version": "0.1.0",
"private": true,
"dependencies": {
"@contentful/app-sdk": "^4.17.1",
"@contentful/f36-components": "4.10.5",
"@contentful/f36-tokens": "4.0.1",
"@contentful/f36-workbench": "^4.21.0",
"@contentful/react-apps-toolkit": "1.2.2",
"contentful": "^10.1.6",
"contentful-management": "10.7.0",
"emotion": "10.0.27",
"react": "17.0.2",
"react-dom": "17.0.2"
},
"scripts": {
"start": "vite",
"build": "tsc && vite build",
"test": "vitest",
"create-app-definition": "contentful-app-scripts create-app-definition",
"upload": "contentful-app-scripts upload --bundle-dir ./dist",
"upload-ci": "contentful-app-scripts upload --ci --bundle-dir ./dist --organization-id $CONTENTFUL_ORG_ID --definition-id $CONTENTFUL_APP_DEF_ID --token $CONTENTFUL_ACCESS_TOKEN"
},
"devDependencies": {
"@contentful/app-scripts": "1.1.11",
"@testing-library/react": "12.1.5",
"@types/node": "18.0.3",
"@types/react": "17.0.47",
"@types/react-dom": "17.0.17",
"@vitejs/plugin-react": "1.3.2",
"happy-dom": "6.0.2",
"typescript": "4.7.4",
"vite": "3.0.0",
"vitest": "0.18.0"
}
}
36 changes: 36 additions & 0 deletions src/App.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { locations } from '@contentful/app-sdk';
import { useSDK } from '@contentful/react-apps-toolkit';
import { useMemo } from 'react';
import ConfigScreen from './locations/ConfigScreen';
import Dialog from './locations/Dialog';
import EntryEditor from './locations/EntryEditor';
import Field from './locations/Field';
import Page from './locations/Page';
import Sidebar from './locations/Sidebar';
import Home from './locations/Home';

const ComponentLocationSettings = {
[locations.LOCATION_APP_CONFIG]: ConfigScreen,
[locations.LOCATION_ENTRY_FIELD]: Field,
[locations.LOCATION_ENTRY_EDITOR]: EntryEditor,
[locations.LOCATION_DIALOG]: Dialog,
[locations.LOCATION_ENTRY_SIDEBAR]: Sidebar,
[locations.LOCATION_PAGE]: Page,
[locations.LOCATION_HOME]: Home,
};

const App = () => {
const sdk = useSDK();

const Component = useMemo(() => {
for (const [location, component] of Object.entries(ComponentLocationSettings)) {
if (sdk.location.is(location)) {
return component;
}
}
}, [sdk.location]);

return Component ? <Component /> : null;
};

export default App;
31 changes: 31 additions & 0 deletions src/components/LocalhostWarning.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { Flex, Note, Paragraph, TextLink } from '@contentful/f36-components';

const LocalhostWarning = () => {
return (
<Flex marginTop="spacingXl" justifyContent="center">
<Note title="App running outside of Contentful" style={{ maxWidth: '800px' }}>
<Paragraph>
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">
available locations
</TextLink>
.
</Paragraph>
<br />

<Paragraph>
Follow{' '}
<TextLink href="https://www.contentful.com/developers/docs/extensibility/app-framework/tutorial/#embed-your-app-in-the-contentful-web-app">
our guide
</TextLink>{' '}
to get started or{' '}
<TextLink href="https://app.contentful.com/deeplink?link=apps">open Contentful</TextLink>{' '}
to manage your app.
</Paragraph>
</Note>
</Flex>
);
};

export default LocalhostWarning;
22 changes: 22 additions & 0 deletions src/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { render } from 'react-dom';

import { GlobalStyles } from '@contentful/f36-components';
import { SDKProvider } from '@contentful/react-apps-toolkit';

import App from './App';
import LocalhostWarning from './components/LocalhostWarning';

const root = document.getElementById('root');

if (import.meta.env.DEV && window.self === window.top) {
// You can remove this if block before deploying your app
render(<LocalhostWarning />, root);
} else {
render(
<SDKProvider>
<GlobalStyles />
<App />
</SDKProvider>,
root
);
}
20 changes: 20 additions & 0 deletions src/locations/ConfigScreen.spec.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { render } from '@testing-library/react';
import { describe, expect, it, vi } from 'vitest';
import { mockCma, mockSdk } from '../../test/mocks';
import ConfigScreen from './ConfigScreen';

vi.mock('@contentful/react-apps-toolkit', () => ({
useSDK: () => mockSdk,
useCMA: () => mockCma,
}));

describe('Config Screen component', () => {
it('Component text exists', async () => {
const { getByText } = render(<ConfigScreen />);

// simulate the user clicking the install button
await mockSdk.app.onConfigure.mock.calls[0][0]();

expect(getByText('Welcome to your contentful app. This is your config page.')).toBeTruthy();
});
});
Loading

0 comments on commit 7666a57

Please sign in to comment.