How do I get Watch Mode with Sanity.io and Gatsby to refresh content when referenced documents are edited in the CMS / Studio? - sanity

I'm using Sanity.io, GatsbyJS 3.x
Watch mode works great when you update content in the CMS, except for when the content you edit is part of a referenced schema of type 'document'.
Put another way, changes made to a document referenced by another document will not re-render the page despite having watch mode on and configured properly.
For example, here is a snippet from my Page schema.
...
{
name: "content",
type: "array",
title: "Page Sections",
description: "Add, edit, and reorder sections",
of: [
{
type: 'reference',
to: [
{ type: 'nav' },
{ type: 'section' },
{ type: 'footer' }
]
}
],
},
...
The above schema references a
nav schema
section schema
footer schema
Each of these are type 'document'.
See the example below.
export default {
type: 'document',
name: 'section',
title: 'Page Sections',
fields: [
{
name: 'meta',
title: 'Section Meta Data',
type: 'meta'
},
...
I want to reference a document, rather than an object, because I need to use the content created based on these schemas to be re-used in throughout the application.
Finally, I've configured the source plugin correctly for watch mode.
Gatsby Config is set properly
{
resolve: `gatsby-source-sanity`,
options: {
projectId: `asdfasdf`,
dataset: `template`,
watchMode: true,
overlayDrafts: true,
token: process.env.MY_SANITY_TOKEN,
},
},
In the CMS / Studio, when you edit one of the fields, you can see Gatsby re-compile in dev mode from the terminal. However, the page does not auto reload and display the changes made to the referenced document.
I've tried reloading the page with the reload button and via hard refresh, the changes do not render.
The only way to render the changes is to go back to the CMS and edit a field on the main “Page” document. Then it refreshes immediately.
Am I doing something wrong? Is this expected behavior? Is there a way to get this to work?

For those that run across this issue, I was able to answer my own question. I hope this saves you the day's it took me to find a solution.
Solution TLDR
You need to explicitly query the referenced document in order for watch mode to work properly.
Details with Examples
Summary
The gatsby-source-sanity plugin provides convenience queries that start with _raw for array types. When you use the _raw query in your GraphQL query, it will not trigger watch mode to reload the data. You need to explicitly query the referenced document in order for watch mode to work properly. This may have to do with how the plugin sets up listeners and I don't know if this is a bug or a feature.
Example
My Page Document has the following schema
{
name: "content",
type: "array",
title: "Page Sections",
description: "Add, edit, and reorder sections",
of: [
{
type: "reference",
to: [
{ type: "nav" },
{ type: 'section' },
],
},
],
},
The section is a reference to a section document.
{ type: 'section' }
The reason I'm not using an object is because I want the page sections to be re-usable on multiple pages.
Assuming you have watch mode enabled properly in your gatsby-config.js file, watch mode, like so...
// gatsby-config.js
{
resolve: `gatsby-source-sanity`,
options: {
projectId: `asdf123sg`,
dataset: `datasetname`,
watchMode: true,
overlayDrafts: true,
token: process.env.SANITY_TOKEN,
},
},
Then you should see the following behavior:
listen for document/content updates
re-run queries, update the data, hot-reload the page
You'll see the following scroll in your terminal window.
success Re-building development bundle - 1.371s
success building schema - 0.420s
success createPages - 0.020s
info Total nodes: 64, SitePage nodes: 9 (use --verbose for breakdown)
success Checking for changed pages - 0.001s
success update schema - 0.081s
success onPreExtractQueries - 0.006s
success extract queries from components - 0.223s
success write out requires - 0.002s
success run page queries - 0.010s - 1/1 99.82/s
This works great if you are querying the main document or any referenced objects. However, if you are querying any references to another document then there is one gotcha you need to be aware of.
The Gotcha
When you use the _raw query in your GraphQL query, it will not trigger watch mode to reload the data. You need to explicitly query the referenced document in order for watch mode to work properly.
Example: This Query will NOT work
export const PageQuery = graphql`
fragment PageInfo on SanityPage {
_id
_key
_updatedAt
_rawContent(resolveReferences: {maxDepth: 10})
}
`
Example: This query WILL Work
export const PageQuery = graphql`
fragment PageInfo on SanityPage {
_id
_key
_updatedAt
_rawContent(resolveReferences: {maxDepth: 10})
content {
... on SanitySection {
id
}
}
}
`
This additional query is the key
Here is where I am explicitly querying the document that is being referenced in the 'content' array.
content {
... on SanitySection {
id
}
}
You don't actually need to use the data that results from that query, you simply need to include this in your query.
My guess is that this informs the gatsby-source-sanity plugin to set up a listener, whereas the _rawContent fragment does not.
Not sure if this is a feature, bug, or just expected behavior. At the time of writing the versions were as follows.
"gatsby": "3.5.1",
"gatsby-source-sanity": "^7.0.0",

Related

Issue with aws cognito UI form fields in vue js

I'm using AWS cognito and amplify in my vue js application. Everything is working fine with pre-defined fields.
I've added the custom fields in AWS user pool attributes section. Those newly added fields are not reflecting in UI.
Here is my code for amplify config and custom fields.
HTML Code:
<amplify-authenticator>
<amplify-sign-up
slot="sign-up"
header-text="My Project Sign-Up"
submit-button-text="Register"
:formFields="formFields"
></amplify-sign-up>
</amplify-authenticator>
Custom Fields JSON
formFields: [
{ type: 'username' },
{ type: 'password' },
{ type: 'email', inputProps: { required: true, autocomplete: 'username' } },
{ type: 'phone_number' },
{ type: 'custom:name' },
]
Result form
Custom fields are not coming in the form. Can some one please help me to solve this issue?
The issue appears to be related to Stencil. See this discussion.
The solution suggested is to change formFields to formFields.prop.
E.g.
<amplify-authenticator>
<amplify-sign-up
slot="sign-up"
header-text="My Project Sign-Up"
submit-button-text="Register"
:formFields.prop="formFields"
></amplify-sign-up>
</amplify-authenticator>
This worked for me using Vue 2.

Keystonejs 4.0 File system storage adapter image preview

How do I get an image preview for a Types.File field in the admin UI.
It says "The FS adapter supports all the default Keystone file schema fields. It also additionally supports and enables the filename path (required)." However when I try (doc):
format: function(item, file){
return '<img src="/files/'+file.filename+'" style="max-width: 300px">'
}
Nothing appears in the UI
The format function hasn't been working for a while as far as I can tell from the Keystone GitHub. I don't know if the function exists in Keystone 4.0. Reference here.
You could fork the current beta and patch the function yourself if you need this immediately.
You can find it at https://github.com/keystonejs/keystone/blob/v4.0.0-beta.5/fields/types/file/FileType.js#L81
Doesn't seem right to me, though. I hope they will fix it before releasing 4.0, along with the missing File Array type.
Image previews are now possible in the latest master branch of keystone (see https://github.com/keystonejs/keystone/pull/4509). At the moment you need to depend on the git version of keystone, so put this in your package.json and run npm install:
"keystone": "https://github.com/keystonejs/keystone.git"
In your model, specify thumb: true on the image field in question. You also need the url property in the schema. For example:
const storage = new keystone.Storage({
adapter: keystone.Storage.Adapters.FS,
fs: {
path: keystone.expandPath('./uploads/images'),
publicPath: '/images/'
},
schema: {
url: true,
}
})
ImageUpload.add({
name: { type: Types.Key, index: true },
image: {
type: Types.File,
storage: myStorage,
thumb: true
},
createdTimeStamp: { type: String }
});
The admin UI should now show a small preview of the image and a link to it.

Alfresco custom action permission

I have done a custom action. I can see the action in documentary library but i canot see it on faceted search result page.
<action id="custom-action" type="javascript" label="actions.custom.action">
<param name="function">onCustomActionlick</param>
</action>
So I went in the aikau-1.0.8.1.jar\META-INF\js\aikau\1.0.8.1\alfresco\renderers\_ActionsMixin.js file.
I see that we do a test to determine if action is allowed in this file :
if (this.filterActions === false || AlfArray.arrayContains(this.allowedActions, action.id))
On firebug i see that my costum action is not in the allowedActions object. My question is why ?
I think that actions wich have not permission are always allowed to all users. Am I right ?
What can i do to allow this action et make it visible on faceted search result page?
Thank you in advance.
You need to write an extension module which is described here: https://forums.alfresco.com/comment/159331#comment-159331.
In the JavaScript code you need to get the widget id of MERGED_ACTIONS and add your customAction to the array of allowdActions and define it in CustomActions.
This is the Aikau code from the link, probably it has been updated in the newer Alfresco version. So you need to extend this within your extension module.
You can probably just use org\alfresco\share\pages\faceted-search as your <sourcePackageRoot> in the module.
widgets: [{
id: "MERGED_ACTIONS",
name: "alfresco/renderers/Actions",
config: {
filterActions: true,
mergeActions: true,
allowedActions: ["folder-manage-rules", "folder-download", "folder-view-details", "CUSTOM3"],
customActions: [{
id: "CUSTOM3",
label: "Custom Action 3",
icon: "document-delete",
index: "10",
publishTopic: "DELETE_ACTION_TOPIC",
type: "javascript"
}],
widgetsForActions: [{
name: "alfresco/renderers/actions/ManageAspects"
}]
}
}]
The Document Library (at least up until Alfresco Share 5.1) is built with YUI, whereas the search page is built using Aikau. At the time of writing there is not yet parity of action handling between the search page and the Document Library, and the process of adding actions is very different.
In order to get your custom action to display in the faceted search page you'll need to do a couple of things:
Extend the search page to update the configuration for the "alfresco/search/AlfSearchResult" (it has the id "FCTSRCH_SEARCH_RESULT") to add your custom actions to the "additionalDocumentAndFolderActions" array (see http://dev.alfresco.com/resource/docs/aikau-jsdoc/AlfSearchResult.html)
Your custom action will publish a topic, so you need to create a new service to subscribe to that topic to perform the action. You will need to further extend the faceted search page so that your service is included on the page.
I'm paraphrasing from our latest blog the method we've used for this.
Our use case was we had existing actions in the document library view we didn't want to have to recreate, with standard configuration xml.
The first step is to create a Share Extension Module to add a Javascript controller in web-extensions/site-data/extensions/example.xml:
<extension>
<modules>
<module>
<id>Example Service</id>
<version>1.0</version>
<auto-deploy>true</auto-deploy>
<customizations>
<customization>
<targetPackageRoot>org.alfresco.share.pages.faceted-search</targetPackageRoot>
<sourcePackageRoot>com.parashift.example</sourcePackageRoot>
</customization>
</customizations>
</module>
</modules>
</extension>
This will load some extra javascript, allowing you to adjust the widget config.
Create a file in web-extension/site-webscripts/com/parashift/example/faceted-search.get.js (or whatever package name you've used in sourcePackageRoot), add in a file called faceted-search.get.js with the following contents:
var searchResultPage = widgetUtils.findObject(model.jsonModel.widgets, "id", "FCTSRCH_SEARCH_RESULT");
if(searchResultPage != null) {
searchResultPage.config = {
enableContextMenu : false,
mergeActions : true,
additionalDocumentAndFolderActions : ["example-action"]
}
}
model.jsonModel.widgets.push({
id: "EXAMPLE_LISTENER",
name: "parashift/action/example"
});
This will:
Add example-action to the list of actions in the search results. This should already be a configured action in some share-config.xml file.
Add a new listener widget for you to listen to when the action button is clicked.
Add a file for your listener widget: META-INF/parashift/action/example.js
define(["dojo/_base/declare",
"dijit/_WidgetBase",
"alfresco/core/Core"
],
function(declare, _Widget, Core) {
return declare([_Widget, Core], {
postCreate: function () {
this.alfSubscribe("ALF_SINGLE_DOCUMENT_ACTION_REQUEST", lang.hitch(this, this._onPayloadReceive));
},
_onPayloadReceive: function (payload) {
if(payload.action.id == "example-action") {
this.alfLog("log", "Received action, handling accordingly");
.......
}
}
});
});
This code will listen for ALF_SINGLE_DOCUMENT_ACTION_REQUEST and execute the _onPayloadReceive function. In this function we filter to the example-action and execute any custom code.
The payload variable will include document and action objects. Using Debug Logging you can see what their shape is.
This is roughly equivalent to the old YUI method:
YAHOO.Bubbling.fire("registerAction", {
actionName: "onExampleAction",
fn: function(file) {
console.log("Received action, handling accordingly");
....
}
});

Store contains only data inside "raw" property

I'm having strange problem with my store inside ExtJS. My ASP.NET MVC3 controller returns JSON:
My store:
Ext.define('MyApp.store.Users', {
extend: 'Ext.data.Store',
config: {
// I know the model works
model: 'MyApp.model.User',
storeId: 'Users',
autoLoad: true,
proxy: {
type: 'ajax',
url: 'users/read',
reader: {
type: 'json',
root: 'users'
// also tried this
rootProperty: 'users'
}
}
}
});
Now, when I connect this store to the grid inside ExtJS 4.2.1, the grid shows TWO rows but without data. When I console.log(store) I see the data only inside raw property, not inside data property.
Does anyone know what's the problem? Why isn't there any mapping? The grid's dataIndex is also the same as Models fields (I've done this a thousand times with PHP, I don't know where is the problem here.)
One more thing I've tried. I've tried renderer: function(value) { console.log(value); } inside grid's columns and I was just getting undefined.
Edit: this is how the JSON actually looks like:
Try using root: 'users' not rootProperty. If not specified root defaults to ''.
Sencha Docs
SENCHA what the hell?! Sencha Touch 2 always says put everything in config?
Now when I do that in ExtJS, everything breaks?
I removed everything from config: {} and now it works great.

ExtJS4 / Sencha Touch 2: Reuse data (loaded into store) in different views with different sorting

I have data in an external database which can be accessed via JSON. Now I want to provide different views on these data sets (eg. different sorting, ..). Is it possible to use one single store for this or do I need two stores accessing the same URL except with a different sorter?
My example code looks like this:
Ext.define('MyApp.store.MyStore', {
extend: 'Ext.data.Store',
requires: [
'MyApp.model.MyModel'
],
config: {
autoLoad: true,
model: 'MyApp.model.MyModel',
storeId: 'MyJsonStore',
proxy: {
type: 'ajax',
url: 'http://localhost/index.php?data=MyData&format=json',
reader: {
type: 'json'
}
},
sorters: [
{
direction: 'DESC',
property: 'MyRating'
},
{
direction: 'ASC',
property: 'MyLabel'
}
] } });
And one view should now render a list sorted by the rating and a second one should display a list sorted by the label.
Is there a way to prevent querying the DB twice?
Thanks - I just started out with Sencha Touch and ExtJS --- therefore please excuse my simple question ;)
Somehow I couldn't find any smart solution by asking Google for this basic task..
You don't have to worry about anything unless your two views are presented at the same time. Just re-sort the same store locally.
If they are presented at the same time you will have to create a copy of a store. Otherwise they will show exact same information.