-
Notifications
You must be signed in to change notification settings - Fork 0
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
Headless docs/start #3
Conversation
… the setup chapter
…t the graphQL playground.
…he react components before the static movie list is done.
…only making it dynamic remains.
…hen clicking the list
Ser ut som en bra start Espen. Har du tenkt å gjøre det mulig å gjøre react helt headless alså en webapp? |
… maybe a bit more downboiling.
Ja, skriver på kapittel 9 nå - webapp. Available now at a CR near you! |
* commit 'cea53c88d8afe1889a46cadc525b1851cb484ecd': Emphasize that react4xp components don't need to be inserted into react-rendered XP regions, and vice versa. Important NPM install note during the setup.
…e second, XP-helper variation, then PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The more i read on this guide i think we should create 2 different ones.
I see that this is only sued for the poor developers thrown into a headless cms and need to learn how our system works. Might ask Thomas about it.
One guide for pure headless.
And one for XP rendering and healess fetching?
Review not completed. about 50% done.
docs/guillotine.adoc
Outdated
.site/content-types/movie/movie.xml: | ||
[source,xml,options="nowrap"] | ||
---- | ||
<content-type xmlns="urn:enonic:xp:model:1.0"> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I do want the decleration of namespace, but i wonder if it might confuse people.
Since it can be tricky to setup in anything that is not intelliJ
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Or just getting into the xml model etc. Keep it if you think people will mostly just ignore it and not ask questions.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point, fixing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
✅
<occurrences minimum="1" maximum="1"/> | ||
</input> | ||
|
||
<input name="description" type="HtmlArea"> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Exclude all
Inlucde text
TextArea?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What did you mean, it should be a text area (or that it practically is)?
I just thought it'd be neat to both allow bold/italic/underline, which requires a html area (and demonstrates that transferring unescaped data and rendering with dangerouslyInsertHtml works).
It's not really a big deal, of course I can fix it if you think it makes things clearer.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This practically is a text area. I just don't understand why you excluded 90% of the html features. Just allow all no need to restrict on a demo.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Excluding those features enables me to skip the processHtml step in XP...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about you @sigdestad , do you have an opinion? Between:
- using a textarea and keeping it real simple,
- like it is now: a simplifiled htmlarea with only bold/italic/underline, so that it processHtml isn't needed and we keep the server side of things simpler... but still have one content point that delivers html tags so that it demonstrates an instance of unescaped rendering (
dangerouslyInsertHtml
=data-th-utext
) still working in a headless context, OR - allowing full html features, so that the entire flow of that is demonstrated in a headless/hybrid context? On the downside: increases the complexity of the lesson a bit, and will require more writing/polish on these docs
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
-> #7
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
docs/guillotine.adoc
Outdated
|
||
This is a pure entry wrapper that just imports the next react component from _react4xp/shared_. | ||
|
||
Why import code from _shared_ instead of keeping it all in the entry? Two reasons: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove two reasons. And add a numbered list below. If you think it looks fine now, ignore comment 😄
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, how about this:
Why import code from _shared_ instead of keeping it all in the entry? Firstly, it's a good rule of thumb to keep entries slim, for better optimization. And secondly, in addition to a Content Studio preview for single movies, we're going to use the *imported components* in the actual movie list too, for each single movie in the list.
It's more of a side note actually, bullets and numbered list both made it seem too central. 👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
✅
|
||
<Info heading="Description"> | ||
<div className="description" | ||
dangerouslySetInnerHTML={{ __html: description }}> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this actually a react method dangerouslySetInnerHTML? 👍
If we change it to a textArea we might not scare people that much.
But they will not learn how to insert unformated text with react components.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, it's the standard way - equivalent to thymeleaf's data-th-utext
. Strictly speaking it's not a necessary part of this lesson, I just thought it would be interesting to show that this context handles that too. Hmm, scary, I guess it's supposed to be... :D Maybe worth a comment at least?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No need for more comments everything is so defailed allready. We probably want people to learn how to use html area.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@sigdestad , same issue here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Two important points when using a controller mapping like this: | ||
|
||
[NOTE] | ||
==== |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Excellent node 👍 Easy to confuse the two.
==== | ||
First, the controller reference in a mapping in _site.xml_ must always refer to *the runtime name of the controller*. In our case, the source file of our controller is _/controllers/previewMovie_ *_.es6_*, but at compile time, this is compiled into *_.js_* which is used at XP runtime. | ||
|
||
Second, controller mappings use qualified content type names that have *the name of the app* in it: `com.enonic.app.react4xp`. If/when you use a different name for your app, make sure to update content type references like this, e.g. `<match>type:'my.awesome.app:movie'</match>` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This could maybe even be part of the main text? I assume everyone will not use the default name in production?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, isn't notes supposed to be for emphasis, "above" the main text, like you-should-really-take-special-note-of-this? Or are they more like side notes, feel-free-to-skip-this stuff? Hope I don't have to rewrite too many of them...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Differs from context. Its fine if we keep it like this. The most important is mentioning it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay, I'll just keep it then.
docs/guillotine.adoc
Outdated
|
||
In order to make requests for a list of movies below a container item in the content hierarchy, we'll need a specific guillotine query string, as well as functionality to adapt the resulting data into the proper props structure for the react components. | ||
|
||
And by using the same code on the frontend and backend, for this too, we gain a bit of isomorphism (the predictability of a singe source of truth, in short). So we'll make *a module with custom helper functionality* for our use case, and import from it in both places. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
singe -> single
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What did you mean?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(the predictability of a singe source of truth, in short)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, a typo! Hah, thanks!
Singed source of truth... 🔥
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
✅
|
||
|
||
// Not using util-lib, to ensure usability on frontend | ||
const forceArray = maybeArray => Array.isArray(maybeArray) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Double ternary 😕
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you write your own forceArray just use that everywhere. No need to include lib-util then.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good points.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll need to restructure a little bit of code then, and subsequently the docs. Suggestion: we release the docs without this improvement, and create a polish-task for it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
docs/guillotine.adoc
Outdated
+ | ||
NOTE: Again, remember that this query hardcodes qualified names to a content type, that contain the name of the app: `com.enonic.app.react4xp:movie` and `com_enonic_app_react4xp_Movie`. Change these if your app name is not `com.enonic.app.react4xp`. | ||
+ | ||
For more about the query language, see the link:https://developer.enonic.com/docs/headless-cms/2.x/api[guillotine API documentation]. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When i read query language i think abotu our implementation of elastic search. NoQl reference.
Maybe just say "For more about the guillotine query see ..."
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Aha! Yep.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
✅
|
||
const query = buildQueryListMovies(); <!--3--> | ||
|
||
const variables = { <!--4--> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is the most meta variable i have seen.
A variable named variables containing varius variables used as variables. 😹
Jokes aside please rename this, maybe params?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Haha, true dat. But the argument for keeping it like this: variables
is what guillotine calls it, it expects the params query
and variables
. So, 1-to-1 (and also, it's sent through POST params, so then you'd get a params
param. 😄 )
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm adding a parenthesis about this name, then
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"<4> Build the variables
object with the query's parameters (what's up with a variable called variables
, you ask? This is for consistencty - the guillotine lib and its docs refer to the encapsulated object of values for the various variables in the query, as an argument called variables
. Now we have that clarified),"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
✅
[source,sass,options="nowrap"] | ||
---- | ||
.movieList { | ||
margin: 0 auto; width: 1024px; max-width: 100%; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you set each value on a new line?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Uhh, I don't really wanna? :D
In a regular code context I'd agree heavily. But here, the styling just takes heaps of space and creates a sidetrack for the reader's attention span in an already crowded doc...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
✅
</site> | ||
---- | ||
|
||
After rebuilding, the API is now up and running at `<site-url>/api/headless` (e.g. `http://localhost:8080/admin/site/preview/default/draft/moviesite/api/headless`). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Question: Why did you choose to expose this as a controller mapping instead of a service?
I'm okay with both.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No great reasons.
- I think it was @sigdestad 's suggestion.
- I've never used one so I wanted to try. :D
- Seemed at the time like it didn't matter much one way or the other. Now I guess I'm a bit locked-in.
docs/guillotine.adoc
Outdated
handleResponseErrorFunc, <!--4--> | ||
extractDataFunc, <!--5--> | ||
handleDataFunc, <!--6--> | ||
catchErrorsFunc // <!--7--> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is 7 commented out? Poor 7.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
✅
docs/guillotine.adoc
Outdated
|
||
<1> `url` (string, mandatory): URL to the API endpoint, i.e. to the controller mapping of `headless/guillotineApi.es6`: `<site-url>/api/headless`. | ||
<2> `query` (string, mandatory): valid link:https://developer.enonic.com/docs/headless-cms/2.x/api[guillotine query] string. | ||
<3> `variables` (object, optional): object with key-value pairs where the keys correspond to parameters in the `query` string, e.g. the value of `variables.first` will be inserted into the query string as `$first`. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Variables is to generic.
queryVariables will be more confusing, params could work. Values can we pass the query values?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See above: guillotine itself calls it "variables", so this way it corresponds with everything else.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"<3> variables
(object, optional): corresponds to the guillotine variables
object: key-value pairs where the keys correspond to parameters in the query
string. E.g. the value of variables.first
will be inserted into the query string as $first
."
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
✅
Headless docs/webapp
Chapter 8 (guillotine requests) first draft: basically just https://github.com/enonic/doc-react4xp/blob/headlessDocs/start/docs/guillotine.adoc