Unable to add an UI extension on Contentful. When i run nopm run start, I get a 404 error on ui_config - contentful

I am new to contentful. I am trying to develop an UI extension on Contentful using Contentful SDK.
I followed all the steps mentioned in this article.
This is the code I have in index.js.
import React from 'react';
import PropTypes from 'prop-types';
import ReactDOM from 'react-dom';
import { TextInput , Button } from '#contentful/forma-36-react-components';
import { init } from 'contentful-ui-extensions-sdk';
import '#contentful/forma-36-react-components/dist/styles.css';
import './index.css';
export class App extends React.Component {
static propTypes = {
sdk: PropTypes.object.isRequired
};
detachExternalChangeHandler = null;
constructor(props) {
super(props);
this.state = {
value: props.sdk.field.getValue() || ''
};
}
componentDidMount() {
this.props.sdk.window.startAutoResizer();
// Handler for external field value changes (e.g. when multiple authors are working on the same entry).
this.detachExternalChangeHandler = this.props.sdk.field.onValueChanged(this.onExternalChange);
}
componentWillUnmount() {
if (this.detachExternalChangeHandler) {
this.detachExternalChangeHandler();
}
}
onExternalChange = value => {
this.setState({ value });
};
onChange = e => {
const value = e.currentTarget.value;
this.setState({ value });
if (value) {
this.props.sdk.field.setValue(value);
} else {
this.props.sdk.field.removeValue();
}
};
onButtonClick = async () => {
console.log('hurray');
};
render() {
return (
<Button buttonType="primary" isFullWidth={false}
onClick={this.onButtonClick}>
Add Content from AEM DAM
</Button>
);
}
}
Ideally i am trying to create an UI extension to be used in contentful space. I downloaded the contentful SDK and i have put in a button. But I receive this error on the console and it doesn't work
Screenshot:

https://github.com/contentful/create-contentful-extension
Go to the content of this Content Type and enable mixed content at
your browser so that development version that is served from your
local machine could be rendered within https://app.contentful.com.
Better yet:
I'm not the biggest fan of disabling the mixed content setting in browsers. Can I use HTTPS in development mode?
Yes, you can serve your extension using HTTPS. Add --https to start command.
"start": "contentful-extension-scripts start --https",
It uses Parcel HTTPS under the hood , which generates a self-signed certificate, you might have to configure your browser to allow self-signed certificates for localhost.
I think that will fix the 404 error and get things working.
Please follow the readme carefully and post a separate question if you still have problems.

Related

How to map dynamic routes to components outside pages folder in a NextJs multi tenant application

I am following this template here to create a Multi-tenant application using NextJS.
However, I am stucked at how to properly resolve the routing of the pages.
My pages folder is structured in this manner
pages/
_sites/[site]
[path.jsx]
index.jsx
I have the routing logic inside[path.jsx] file above
I have moved all my components from the pages folder to another folder called components.
Now, when a user visits for example james.mydomain.com/blog I wish to load the blog component from the components folder.
How can that be neatly done without too much hardcoding?
Here is what I have attempted but the page only freezes without loading the component:
import { useRouter } from "next/router";
import { useEffect, useState } from "react";
import Loading from "react-loading";
export default function SiteComponent(props) {
const router = useRouter();
const [component, setComponent] = useState(null);
const { path } = router.query;
const loadComponent = async (path) => {
const importedComponent = await import(`../../../src/components/${path}`);
setComponent(importedComponent.default);
}
useEffect(() => {
if (path) {
loadComponent(path);
}
}, []);
return (
component ? <component /> : <Loading color="teal" type="bubble" />
);
}
Is there a way to do this neatly without the above dynamic component loading?
I feel the above code may not even work properly on the occasion I wish to load a nested route eg. james.mydomain.com/blog/categories.
Please kindly suggest a cleaner approach.

Angular Universal app not honoring 'useAbsoluteUrl' or HTTP Interceptor on server-side

Our Angular 14 app is configured to use Angular Universal for SSR, and is integrated with our .NET 6 back end. The Universal guide incorrectly states (per this bug) that relative URLs will "automatically" be converted to absolute if you're using Express, but we still get relative URL errors from SSR even after updating our app.server.module.ts to include the necessary setting .useAbsoluteUrl = true (and providing the base URL), which fixes the issue for some per the bug thread:
export class AppServerModule {
constructor(
#Inject(INITIAL_CONFIG) private config: PlatformConfig,
private baseUrlService: BaseUrlService
) {
this.config.baseUrl = this.baseUrlService.getBaseUrl();
this.config.useAbsoluteUrl = true;
}
}
We've also tried implementing a custom HTTP Interceptor to handle the conversion, which doesn't seem to work either when declared as a provider in app.server.module.ts. This must be a misconfiguration issue, right? Our main.server.ts file imports the aspnet-prerendering package and has a default createServerRenderer() method, which calls renderModule(AppServerModule, options), but is something else missing with this approach? The main.server.ts is:
....
export default createServerRenderer(params => {
const { AppServerModule } = (module as any).exports;
const options = {
document: params.data.originalHtml,
url: params.url,
extraProviders: [
{ provide: APP_BASE_HREF, useValue: params.baseUrl },
{ provide: 'BASE_URL', useValue: params.origin }
]
};
// Bypass ssr api call cert warnings in development
process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';
const renderPromise = renderModule(AppServerModule, options);
return renderPromise.then(html => ({ html }));
});
export { renderModule } from '#angular/platform-server';
export { AppServerModule } from './app/app.server.module';
Microsoft's now-deprecated NodeServices implementation(?) apparently requires the use of commonjs for Node (in tsconfig.server.json), if that's relevant.

Open a URL in system default browser

I have an electron app using angular. I want to open a URL in the system default browser. I tried the code below
import { ElectronService } from 'ngx-electron';
export class AutoBackupsComponent implements OnInit {
constructor(private electronService: ElectronService) { }
private onAction() {
this.electronService.shell.openExternal('https:www.//google.com');
}
}
On the other threads, everyone suggested this way but it is not working for me. I am not sure how can I make it running in either renderer or main process.

Import contentful in to react-native

I am extremely excited about using contentful for my project, but I can't get the JS library to work in a react-native project.
I get the following error:
I have tried the following approaches:
import contentful from 'contentful';
// or
var contentful = require('contentful');
You can reproduce the bug by going to this repo and following the steps I have provided.
Help would be greatly appreciated.
I am maintaining the Contentful sdk. I've put together a simple example
that shows how to use the SDK in React Native, you can check it here
It is basically getting a list of items from one of our example spaces and display the names in a ListView.Check indes.ios.js.
It looks like there is something wrong with the caching in your machine or so.
Anyway I hope this helps.If you have more problems please feel free to create issues in our github page
[UPDATE]
you can now configure the axios instance used in the SDK to use a different adapter. You can pass that when calling createClient
adapter: config => {
config.adapter = null // this is important if it is passing to another axios instance
// an http client combatible with React Native
return fetch(config)
}
Best,
Khaled
I've tried every option and it will never work using the Contentful SDK.
However, you can get it with REST and transform the response using the types from the contentful lib.
import axios from 'axios';
import {EntryCollection} from 'contentful';
import Env from '../Env';
const contentfulApi = 'https://cdn.contentful.com';
/**
* Default locale used in contentful calls
*
* #see {#link getContentfulEntries}
* #constant
*/
export const ContentfulLocale = 'sv';
/**
* #typedef ContentfulProps
* #param locale optional locale to use. Default is {#link ContentfulLocale}
* #param entryType content type in contentful model
*/
type ContentfulProps = {
entryType: string;
locale?: string;
};
/**
* Get entries from Contentful content API
* #param props See {#link ContentfulProps}
*/
export const getContentfulEntries = async <T>(
props: ContentfulProps,
): Promise<EntryCollection<T>> => {
const client = axios.create({
baseURL: `${contentfulApi}/spaces/${Env.CONTENTFUL_SPACEID}/environments/master/entries?`,
timeout: 1000,
headers: {Authorization: `Bearer ${Env.CONTENTFUL_TOKEN}`},
});
const result = await client.get<EntryCollection<T>>(
'&content_type=' + props.entryType,
);
return result.data;
};
export default getContentfulEntries;
I think the best way to use Contentful APIs with React Native is to use Apollo client and graphQL packages.
I worked around the same and get it done.
Install Apollo client and GraphQL npm package
npm install #apollo/client graphql
Install react-native async storage to store cache
npm install #react-native-async-storage/async-storage
Install apollo cache persist to persist the cache
npm install apollo3-cache-persist
you can read apollographql official documents for implementation
Create ApolloClient in the app.tsx/.js file
import { ApolloClient, ApolloProvider, InMemoryCache } from '#apollo/client';
const cache = new InMemoryCache();
const client = new ApolloClient({
uri: 'https://graphql.contentful.com/content/v1/spaces/{SPACE_ID}',
cache,
credentials: 'same-origin',
headers: {
Authorization: `Bearer {CDA-Access-Token}`,
},
});
Wrap all components in ApolloProvider
const App = () => {
const [loadingCache, setLoadingCache] = useState(true);
useEffect(() => {
persistCache({
cache,
storage: AsyncStorage,
}).then(() => setLoadingCache(false));
}, []);
if (loadingCache) {
return <Loader />;
}
return (
<ApolloProvider client={client}>
<SafeAreaView style={{flex: 1}}>
<Posts />
</SafeAreaView>
</ApolloProvider>
);
};
export default App;
Import gql and useQuery to fetch data
import { gql, useQuery } from '#apollo/client';
Now, write GraphQL query
const QUERY_COLLECTION = gql`
{
postsCollection {
items {
title
author
publishDate
inshorts
featuredImage {
url
}
}
}
}
`;
Fetch data using useQuery function
const { data, loading } = useQuery(QUERY_COLLECTION);
That's all to fetch data from Contentful in React Native App.
To read this in detailed, have a look to this post

Can I do the server rendering with data in React?

I'm working on react recently. I am using the server rendering with react-router, but it can only render the HTML from react components, and I need to get the initial data via ajax in componentDidMount().
The problem is for some pages/components, they need the initial data to render. So if users visit such a page directly(by typing url or refresh), the page broken, because the server cannot render it without initial data.
I'm thinking can I get the data from database and insert it to template when rendering in server? Just like what classic front-end template or PHP does.
If no way, what's the best practice for rendering first-page data?
Now my server code is like:
router.get('*', function(req, res) {
console.log('GET ADMIN');
match({
routes: appRoutes,
location: req.originalUrl
}, (error, redirectLocation, renderProps) => {
if (error) {
res.status(500)
.send(error.message);
} else if (redirectLocation) {
res.status(302)
.redirect(redirectLocation.pathname + redirectLocation.search);
} else if (renderProps) {
var content = renderToString(<RoutingContext {...renderProps}/>);
var html = swig.renderFile('src/client/admin.html', {
content: content
});
res.status(200)
.send(html);
} else {
res.status(404)
.send('Not found');
}
});
});
Finally I found the answer in GitHub: https://github.com/rackt/react-router/issues/1969#issuecomment-140988110
This method insert all data you need into the HTML template when rendering in server and get the data in front-end as context. All component can get the data via context.
I use a <DataWrapper> component to wrap the original root app component. On the server side when rendering:
data = JSON.stringify(data); // data is an object
ReactDOMServer.renderToString(<DataWrapper data={data}><RoutingContext {...renderProps}/></DataWrapper>)
and the <DataWrapper> is something like:
import React from 'react';
class DataWrapper extends React.Component {
getChildContext () {
return {
data: this.props.data
};
}
render () {
return this.props.children;
}
}
DataWrapper.childContextTypes = {
data: React.PropTypes.object.isRequired
};
export default DataWrapper;
on the client side:
var data = JSON.parse(document.getElementById('data').innerHTML),
history = createBrowserHistory();
ReactDOM.render(<DataWrapper data={ data }><Router history={ history }>{ routes }</Router></DataWrapper>, document.getElementById('app'));
get the data via context in components:
class someComponent extends React.Component {
constructor (props, context) {
super(props, context);
this.state = context.data.someData;
}
}
someComponent.contextTypes = {
data: React.PropTypes.object.isRequired
};
export default someComponent;
it works well
The problem with using an AJAX call for the initialisation is that it forces you to render first without the data and then to re-render once the data arrives.
A better way is to include the data in the page so it's there for your initial render. e.g.
<script>
var __INITIAL_DATA__ = { /* etc */ }
</script>
Yeah globals are ugly. But necessary in this instance. And you only use it once to initialise your React component. (Or your store if you're using Flux.)
And yes indeed, in isomorphic/universal apps you use the same data in your server side code. Just like in PHP and other server side languages. Only your server side code won't be pulling from a global variable. The data should be passed directly into the React component that you're mounting.

Resources