mattmilburn / strapi-plugin-preview-button Goto Github PK
View Code? Open in Web Editor NEWA plugin for Strapi CMS that adds a preview button and live view button to the content manager edit view.
License: MIT License
A plugin for Strapi CMS that adds a preview button and live view button to the content manager edit view.
License: MIT License
The button is not showing, I have an article type, and I have added the following to the plugins file
module.exports = ({ env }) => ({
...,
"preview-button": {
enabled: true,
config: {
contentTypes: [
{
uid: "api::article.article",
targetField: "slug",
draft: {
query: {
type: "article",
},
},
published: {
basePath: "articles",
},
},
],
},
},
...,
});
Is there anything else I'm missing?
Hello,
Thanks for this plugin currently working in Strapi 4.
I would like to know if is possible to show the preview button(with an eye icon for example) and how can we do that.
If it is not an available feature, I would like to suggest reviewing this plugin which supports this feature but is not migrated to version four.
Thank you
I'm working on a project with i18n, where it would be useful to provide a locale to the preview URL in addition to a slug.
I wonder if it might be helpful for others if the targetField
option could support more than one field which is included for the front-end query - in my case it would be slug
and locale
- so that a config such as this:
'preview-button': {
enabled: true,
config: {
contentTypes: [
{
uid: 'api::page.page',
targetField: ['slug', 'locale'],
},
],
},
},
would result in a URL:
http://example.com/api/preview?slug=your-page&locale=en&secret=YOURSECRET
Getting the following error on the latest version of strapi
npm ERR! code ERESOLVE npm ERR! ERESOLVE unable to resolve dependency tree npm ERR! npm ERR! While resolving: [email protected] npm ERR! Found: @strapi/[email protected] npm ERR! node_modules/@strapi/icons npm ERR! peer @strapi/icons@"^0.0.1-alpha.73" from @strapi/[email protected] npm ERR! node_modules/@strapi/design-system npm ERR! peer @strapi/design-system@"^1.1.0" from [email protected] npm ERR! node_modules/strapi-plugin-preview-button npm ERR! strapi-plugin-preview-button@"0.3.4" from the root project npm ERR! npm ERR! Could not resolve dependency: npm ERR! peer @strapi/icons@"^1.1.0" from [email protected] npm ERR! node_modules/strapi-plugin-preview-button npm ERR! strapi-plugin-preview-button@"0.3.4" from the root project npm ERR! npm ERR! Fix the upstream dependency conflict, or retry npm ERR! this command with --force, or --legacy-peer-deps npm ERR! to accept an incorrect (and potentially broken) dependency resolution.
module.exports = {
'preview-button': {
enabled: true,
config: {
contentTypes: [
{
uid: 'api::restaurant.restaurant',
draft: {
query: {
slug: 'restaurant',
},
},
published: {
basePath: 'restaurant',
},
},
],
},
},
};
STRAPI_PREVIEW_SECRET=12345678
STRAPI_PREVIEW_DRAFT_URL=http://localhost:1337/api/preview
STRAPI_PREVIEW_PUBLISHED_URL=http://localhost:8000
Error regarding preview-button config: Missing draft URL for api::restaurant.restaurant.
Hi there,
"@strapi/strapi": "4.10.6",
"strapi-plugin-preview-button": "1.1.3",
I followed your extending guide and created own plugin(both using only 3 files you have mentioned and then strapi-cli creator).
My bootstrap
function is being called but callback in hook does not fire. Nor console.log nor an changes to state object are working.
Final url is as it is in config
, no changes detected.
bootstrap(app) {
console.log("hello"); // works
app.registerHook( "plugin/preview-button/before-build-url", ( { state } ) => {
console.log("hello 2"); // does not work
const query = state?.query ?? {};
return {
state: {
...state,
query: {
...query,
example: "EXAMPLE",
},
},
};
});
},
Hi,
I would really appreciate showing both "preview" and "live" open buttons option when content is already published. When using Strapi with SSR content is published by making a deployment manually and then content user would be able to view draft state which is not yet published (even when editing already "published" content).
What do you think about that? Thanks
If we have the button on a piece of content, and then switch language, the page goes blank and the following error shows up in the console:
main.9296bcc6.js:10278 Error: Minified React error #310; visit https://reactjs.org/docs/error-decoder.html?invariant=310 for the full message or use the non-minified dev environment for full errors and additional helpful warnings.
at Ti (main.9296bcc6.js:10276:55391)
at Object.Ka [as useRef] (main.9296bcc6.js:10276:58831)
at p.useRef (main.9296bcc6.js:10307:5860)
at $.default (main.9296bcc6.js:9880:5574)
at h (main.9296bcc6.js:10224:16156)
at M (main.9296bcc6.js:10224:16852)
at Zu (main.9296bcc6.js:10276:54833)
at Ds (main.9296bcc6.js:10276:64692)
at Fc (main.9296bcc6.js:10280:10162)
at Rc (main.9296bcc6.js:10280:992)
If you follow the link, you'll discover that the issue is due to "Rendered more hooks than during the previous render."
Skimming the code, a candidate for this problem could be here: https://github.com/mattmilburn/strapi-plugin-preview-button/blob/main/admin/src/components/Injector/index.js
Namely:
if ( ! shouldRender ) {
return null;
}
const { data, isLoading } = usePreviewData( uid, id, [ initialData ] );
In this case, there's a risk that null
will be returned, which means that usePreviewData
is never called. React (for good reason) insists that hooks should never be conditionally run, hence the error.
One solution could be to have the hook return a load function instead of a result. Another is to introduce a skip
variable like e.g. Apollo does in their useQuery
, meaning that the hook is always called but could just do nothing if need be.
By the way, reloading the blank page makes it work again until you change language once again.
Looking forward to this plugin working with i18n content. :)
Hej Matt,
to which file do i have to add
module.exports = {
'preview-button': {
config: {
contentTypes: [
...
],
},
},
};
Thanks in advance!
Hello! I could not extend the plugin with the async code using the new "plugin/preview-button/before-build-url" hook.
Sync code works perfectly fine, but Strapi currently returns a minimal amount of fields for the relations. So to overcome that, we need to fetch particular fields of relations. If I add async code, the URL returned within the hook is correct but Live View button doesn't show on the admin FE. I have briefly checked the plugin admin code and the URL is returned as "undefined" assume because it's not ready to handle async code.
Here is the implementation:
// ...
bootstrap(app) {
app.registerHook("plugin/preview-button/before-build-url", async ({ state, data }) => {
const url = await parseUrlRelation(state, data);
return {
state: {
...state,
url,
},
};
});
},
// ...
And in "parseUrlRelation":
const parseUrlRelation = async (config, data) => {
// ...
for (const relation of relations) {
// ...
// get relations data and modify url
const entity = await request(`/get-my-relation-data`, {
fields: [field]
});
url = url.replace(relation, entity[field]);
}
return url;
};
Am I missing something or new hook just can't handle it? If so, any idea how to achieve that? Thanks!
Thank you very much for this great plugin!
I encountert one small inconvenience:
I pass a slug-field to the preview-URL. When I change the slug, the preview-URL is not updated immediately.
The user has to reload the page, that the preview-URL gets updated.
Is there a way to fix this?
I made my own plugin for nextjs revalidation and got some your ideas but with improvements. I added support to relations and if you like to see it I can extend your logic and create new pull request for this feature.
Should mention that it will work a bit different. I will use custom back-end endpoint which will redirect to correct url because i'm using strapi metadata to verify all things and define correct populates and requesting entity by one single request. Also this one works only with manyToOne
and oneToOne
.
As example this works like this:
{
uid: 'api::building.building',
query: {
city: '{neighbourhood.city.slug}',
neighborhood: '{neighbourhood.slug}',
building: '{slug}',
},
},
Also when path ends with relation and not common field you will just get id so {neighbourhood.city}
will add related city id to the query.
Reply to issue if you like it and i will make PR for this one.
Hey folks! I have the plugin installed here is my package.json :
"dependencies": {
"@strapi/plugin-i18n": "4.3.2",
"@strapi/plugin-users-permissions": "4.3.2",
"@strapi/strapi": "4.3.2",
"better-sqlite3": "7.4.6",
"dotenv": "^16.0.1",
"find-config": "^1.0.0",
"mysql": "^2.18.1",
"strapi-plugin-preview-button": "^0.3.5"
},
and I added the following configuration in ./config/plugins.js
module.exports = { 'preview-button': { config: { contentTypes: [ { uid: 'api::home-page.home-page' } ] } } }
But the button in never display. Do i miss something in the de docs ?
I just created a new strapi project on the latest version.
The default package.json->engines looks like that:
{
//...
"engines": {
"node": ">=14.19.1 <=18.x.x",
"npm": ">=6.0.0"
},
//...
}
Currently strapi-plugin-preview-button
has the following requirements in package.json:
{
//...
"engines": {
"node": ">=12.x.x <=16.x.x",
"npm": ">=6.0.0"
},
//...
}
Therefor, I had to install a node package manager, n
, in order to install node/16.x.x
because I only had node/19.2.0
on my machine. And I had to downgrade my own package.json->engine->node
requirements from 18.x.x
to 16.x.x
.
Hopefully, it is working fine, no issue.
Still, it would be nice if the upper node version requirements was following the strapi one.
So I must ask:
16.x.x
?18.x.x
?Hello!
This is my setup in plugins.ts:
'preview-button': {
config: {
contentTypes: [
{
uid: 'api::content.content',
draft: {
url: 'http://localhost:1337/api/preview',
query: {
type: 'content',
slug: '{slug}',
},
},
},
],
},
},
but trying to reach the unpublished article with slug: fasdfasdf at the link http://localhost:1337/api/preview?type=content&slug=fasdfasdf gives me 404. How to get the JSON response from Strapi for the drafts of type content?
My local server runs on http://localhost:1337
Env info
│ Time │ Thu Jun 29 2023 16:42:50 GMT+0200 (Central Euro… │
│ Launched in │ 682 ms │
│ Environment │ development │
│ Process PID │ 80393 │
│ Version │ 4.11.1 (node v18.15.0) │
│ Edition │ Community │
│ Database │ sqlite
Hi! How can I use it with different localization domains?
en -> site.com
fr -> fr.site.com
ru -> site.ru
Is it possible to add possibility to open 'preview' page always in new tab (not just replace the opened tab)?
I think we can remove (or make optional) the target
prop (PREVIEW_WINDOW_NAME
) in window.open( url, PREVIEW_WINDOW_NAME );
I need to localize my urls as some parts of my path are localized, e.g.
{
published: {
url: 'http://localhost:3000/{locale}/movie/{slug}',
url: 'http://localhost:3000/{locale}/film/{slug}',
},
}
How could I easily handle this case ?
Base install of...
Base install of...
"dependencies": {
"@strapi/strapi": "4.12.5",
"@strapi/plugin-users-permissions": "4.12.5",
"@strapi/plugin-i18n": "4.12.5",
"better-sqlite3": "8.5.0"
},
Running...
npm i strapi-plugin-preview-button@latest
Then...
npm ERR! Found: [email protected]
npm ERR! node_modules/react
npm ERR! peer react@"^17.0.0 || ^18.0.0" from @strapi/[email protected]
npm ERR! node_modules/@strapi/design-system
npm ERR! peer @strapi/design-system@"^1.6.0" from [email protected]
...
npm ERR! Could not resolve dependency:
npm ERR! peer react@"^17.0.2" from [email protected]
npm ERR! node_modules/strapi-plugin-preview-button
npm ERR! strapi-plugin-preview-button@"2.0.0" from the root project
npm ERR! Fix the upstream dependency conflict, or retry
npm ERR! this command with --force, or --legacy-peer-deps
npm ERR! to accept an incorrect (and potentially broken) dependency resolution.
I think bumping the React version should solve the error, but not sure if there are any side effects,
Hi,
I've been exploring strapi previews and if found your plugin, I find it quite good to use in Production but can I pass the API secret through the request header? (I don't want it to be visible through the URL so it can be leaked)
I can't get the button to show up at all.
Follow these steps to reproduce (as of 2022-07-22)
npx create-strapi-app@latest preview-strapi-test
cd preview-strapi-test
npm install strapi-plugin-preview-button
npm run develop
Set up a page content type through the content type builder with two attributes: title: string
and slug: uid
Make a basic plugins.js
module.exports = {
'preview-button': {
enabled: true,
config: {
contentTypes: [
{
uid: 'api::page.page',
targetField: 'slug',
},
],
},
},
};
Rerun npm run develop
and make a page, then the preview button does not show up.
I have tried removing the .cache
and node_modules
directories and reinstalling, but it still does not work.
Also changing targetField
to title
still does not work.
Am I missing any steps?
Hi,
I see that the format for preview links are:
https://example.com/api/preview?slug=my-page&secret=YOURSECRET
https://example.com/api/preview?slug=my-post&type=post&secret=YOURSECRET
Is it possible to do some customization in that format such as:
https://example.com/api/my-page?preview=YOURSECRET
https://example.com/api/my-post?preview=YOURSECRET
In my case I even need to use a single preview por all pages or ports so my-page and my-post will not be the current slug but a generic one:
https://example.com/api/pages?preview=YOURSECRET
https://example.com/api/posts?preview=YOURSECRET
Cheers,
Jacq
Currently when using this plugin with url-alias it is not possible to use url_alias
as the target field since it is not added when preview button tries to find the entity.
I have made a draft where one can provide a function and populate the entity themselves in Oak-Digital@2795726
However this might not be optimal, so could there be any other way to make this work?
In this use case, I'm using a "page" content type, and the site's Home page is the only page to have an empty slug. When previewing other pages with slugs set, everything works as expected, but when trying to preview the homepage, the created URL path is /en/{slug}
(or /en/%7Bslug%7D
after the browser's URL encoding).
Maybe the default for an empty variable such as the slug should be to interpolate the query URL with an empty string?
Here is my config:
'preview-button': {
enabled: true,
config: {
contentTypes: [
{
uid: 'api::page.page',
draft: {
url: env('STRAPI_PREVIEW_DRAFT_URL'),
query: {
type: 'page',
slug: '{slug}',
secret: env('STRAPI_PREVIEW_SECRET'),
locale: '{locale}',
},
},
published: {
url: `${env('STRAPI_PREVIEW_PUBLISHED_URL')}/{locale}/{slug}`,
},
},
],
},
}
Hi,
There would be nice to add functionality to create a link to preview environment and share it with somebody.
I've found this useful in a case where you are working on a page, and you need do show somebody an article or page (without publishing it) who hasn't got access to strapi.
I know that to make this the PREVIEW_SECRET
will no longer be a secret, but maybe there is other option?
Plugin lacks support for configurable buttons. There are cases, when Live Preview is not needed (or the opposite scenario, when Draft Preview is not needed).
Configuration could be extended to include some options such as disableDraftPreview
and disableLivePreview
Edit: This issue is similar to #20 I believe.
I have the following problem:
My value of the targetField is "/company/jobs"
If I click on "Open Live View", the plugin opens a new tab with the url "https://localhost:3000//company/jobs" because my targetField already contains a slash at the start of the string. Is there a way to remove the first slash the plugin is adding to the url?
When you first time entering admin page before logging in request to admin API to get config is sent but because it has 'admin::isAuthenticatedAdmin'
it crashes and so we are not getting any data (because on login page we're actually still not admin). That's why when you enter list page pluginConfig
is empty and additional column is not showing.
npm ERR! code ERESOLVE
npm ERR! ERESOLVE unable to resolve dependency tree
npm ERR!
npm ERR! While resolving: [email protected]
npm ERR! Found: @strapi/[email protected]
npm ERR! node_modules/@strapi/strapi
npm ERR! @strapi/strapi@"4.1.12" from the root project
npm ERR!
npm ERR! Could not resolve dependency:
npm ERR! peer @strapi/strapi@"4.0.7" from @exfabrica/[email protected]
npm ERR! node_modules/@exfabrica/strapi-plugin-awesome-seo
npm ERR! @exfabrica/strapi-plugin-awesome-seo@"*" from the root project
npm ERR!
npm ERR! Fix the upstream dependency conflict, or retry
npm ERR! this command with --force, or --legacy-peer-deps
npm ERR! to accept an incorrect (and potentially broken) dependency resolution.
npm ERR!
npm ERR! See C:\Users\Alex\AppData\Local\npm-cache\eresolve-report.txt for a full report.
npm ERR! A complete log of this run can be found in:
npm ERR! C:\Users\Alex\AppData\Local\npm-cache_logs\2022-06-07T03_02_09_192Z-debug.log
Is it possible to set dynamic URLs for Blog Posts vs. hard coding basePath = "blog"? For example, I have a blogSettings Single Type that sets the site-wide Blog root URL. Each blog post is based on this URL, for example - blog/post-1. However, the user has the ability to set the blog root URL to whatever they choose so I can't simply hard code this in plugins.js.
I was able to programmatically handle this in preview.js by writing logic based on the query.type being passed in. However, I am not sure if I can get around hard coding the basePath when using the published Object. In a perfect world, I would like to be able to set the basePath attribute to blogSettings.blogSlug (from the Single Type).
Currently urls for posts are pre-generated. By allowing the generation of the url (or parts of it) it would be possible to create more secure preview urls. The static key solution suggested in the docs is problematic for larger deployments, once the key leaked it have to be rotated, and rotation requires the Strapi instance to be restarted. This not only painful to manage, but it is impossible to track when the key is leaked so it have to be rotated on a timely basis. Generating tokens on demand would be a lot more secure, because you could use time based algorithms (JWT for example).
This would also open up other possibilities, for having custom logic determining the preview url.
I'm thinking for something similar:
// ...
'preview-button': {
config: {
contentTypes: [
{
uid: 'api::post.post',
draft: {
url: 'https://my-preview-solution.tld/{slug}',
query: {
token: function() {
return generateToken();
}
},
},
},
],
},
},
// ...
The button's onClick handler could check if the provided url is callable. If yes, it should call it and use the return value as the url. (Promises or something similar would be even better).
I'm not very familiar JavaScript so please forgive me for my inaccuracies.
Hello,
I have the following two collections Page and Category where
Page { slug: String, category: Category}
Category { slug: string }
and my Paths are generated in the following way /{category.slug}/{page.slug}
In the current state of the library, is it possible to achieve this use case? I looked for relation support, but I couldn't find it. Maybe I missed it.
If someone could point me up or could help would be really glad
Thanks
Hi,
I'm trying to modify some translations and especially label.draft
and label.published
but it doesn't seems to work when I add it to my src/admin/app.js
file. I've also tried overwriting the translations files by creating a src/extensions/preview-button/admin/src/translations/
folder with json files in it but with no success.
What would be the best way to do it without overwriting the node_module?
Thanks for your help!
Hello,
I have an issue with the following configuration. It seems when i check the api call that you made to get the configuration defined in the but it's always return an empty value. I also have setted the environment variable.
module.exports = {
'preview-button': {
enabled: true,
config: {
contentTypes: [
{
uid: "api::homepage.homepage",
},
{
uid: "api::product.product",
targetField: "id"
}
],
},
},
};
http://localhost/preview?type=article&slug=game&secret=JWT_TOKEN_HERE
When i config jwt in config/plugins.js isn't work
I mean jwt token will generate 1 time not every time
expected : i want jwt token generate every time when i open link.
Hello,
is there a way to display the button only if the content is published and not also in draft?
Thanks
Dan
here is my code
'preview-button': {
config: {
enabled: true,
// injectListViewColumn: false,
contentTypes: [
{
uid: 'api::home.home',
draft: {
url: 'http://localhost:6001/{locale}/posts/{slug}',
query: {
type: 'home',
locale: '{locale}',
slug: '{slug}',
},
},
published: {
url: 'http://localhost:3000',
},
},
{
uid: 'api::post.post',
draft: {
url: 'http://localhost:6001/{locale}/posts/{slug}',
query: {
type: 'post',
locale: '{locale}',
slug: '{slug}',
},
},
published: {
url: 'http://localhost:6001/{locale}/posts/{slug}',
copy: true,
},
},
],
},
},
but i'm not able to see any draft (preview. button) but it's only showing copylink and live button. Is there anything i'm missing now?
Hello,
How can multilingual be managed?
is there a way to add a different basePath based on the language of the content?
Thanks
I’m trying to customize one of the hooks file \src\extensions\preview-button\admin\src\hooks\use-preview-data.js but I’m not sure how to override the file with plugin extension. The documentation only show the method for plugin’s server interface but I’m not sure how to customize for admin interface. Anyone know how to solve this ?
I'm having trouble getting the preview button to show up. I've deleted my cache, node_modules folder, and package-lock file - re-installed everything - and run the build script but this doesn't help. I'm also confident I know the collection type as 'api::course.course'.
I'm running Strapi v4.2.0 and strapi-plugin-preview-button v0.3.4
The thing I am most confused about is where to place the code below. Does it go in Strapi's main config folder as a new file? Does it go in the plug-in's config.js file? Any help would be much appreciated. Thank you.
module.exports = {
'preview-button': {
enabled: true,
config: {
contentTypes: [
{
uid: 'api::course.course',
targetField: 'slug',
}
],
},
},
};
Nothing appears to show on the content manager view for Example Blog when I have the following added to plugins,ts. Am I missing an installation step?
"preview-button": {
config: {
contentTypes: [
{
uid: "api::example-blog.example-blog",
draft: {
url: "http://localhost:1337/api/preview",
query: {
type: "post",
id: "{slug}",
},
}
},
],
},
},
Hi, great plugin 👍, easygoing instructions, but maybe you should precise a couple of things, as some of us are just starting out with v4 (I struggled with these at first):
plugin.js
file under the config
folder.publicationState
API parameter to preview
when querying the content, otherwise, the draft will never be part of the response.I have installed the plugin, the button displays however when I click on it - I get a 404 error. Is there something other than the mentions in the documentations that is required to be able to preview.
I got the following client error using the preview button plugin (0.3.6) with strapi v.4.3.3 or v.4.3.4:
TypeError: Cannot read properties of null (reading 'model')
The error occurs when I open a detail view for an entity of a collection type.
plugin config is:
'preview-button': {
enabled: true,
config: {
contentTypes: [
{
uid: 'api::article.article',
targetField: 'slug',
draft: {
query: {
type: 'news',
},
},
},
],
},
},
Downgrading strapi to 4.3.2. fixes this error, but is not a satisfactory solution in the long run.
Since I've upgraded my Strapi (I tried in every release higher than 4.5.1), the preview plugin makes my Strapi admin page crash
Here after, you can find the error message I could find in my console
If I disable preview-button
in my config/plugin.js
file, everything is back to normal
Hope it could help you
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.