Skip to content

Commit

Permalink
feat: make preview-button configurable from strapi dashboard
Browse files Browse the repository at this point in the history
in the strapi-dashboard `/config/plugins.ts`

```js
  'preview-button': {
    enabled: true,
    config: {
      domain: env('STRAPI_FRONTEND_URL'),
      token: env('PREVIEW_SECRET_TOKEN'),
      slug: 'products',
    },
  },
  • Loading branch information
AliKdhim87 committed Mar 22, 2023
1 parent 6ce976e commit 924faa7
Show file tree
Hide file tree
Showing 21 changed files with 218 additions and 31 deletions.
36 changes: 35 additions & 1 deletion packages/preview-button/README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,37 @@
# Strapi plugin preview-button

A quick description of preview-button.
## Usage

Create plugins file or update the existing file `./config/plugins.ts` or `.js`

**Typescript**:

```ts
export default ({ env }) => ({
'preview-button': {
enabled: true,
config: {
domain: env('STRAPI_FRONTEND_URL'),
token: env('PREVIEW_SECRET_TOKEN'),
slug: 'products',
},
},
});
```

**Javascript**:

```js
module.exports = ({ env }) => ({
'preview-button': {
enabled: true,
config: {
domain: env('STRAPI_FRONTEND_URL'),
token: env('PREVIEW_SECRET_TOKEN'),
slug: 'products',
},
},
});
```

After the plugin integration, you have to build the Strapi dashboard by using `strapi build && strapi develop` or you can use the `strapi develop --watch-admin`
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,21 @@ import React from 'react';
import { useCMEditViewDataManager } from '@strapi/helper-plugin';
import Eye from '@strapi/icons/Eye';
import { LinkButton } from '@strapi/design-system/LinkButton';
import usePluginConfig from '../../hooks/use-plugin-config';

const PreviewLink = () => {
const { initialData } = useCMEditViewDataManager();
if (!initialData.slug) {
return null;
}
const { config } = usePluginConfig();

return (
<LinkButton
size="S"
startIcon={<Eye />}
style={{ width: '100%' }}
href={`${STRAPI_FRONTEND_URL}/api/preview?secret=${STRAPI_FRONTEND_PREVIEW_SECRET}&type=${STRAPI_FRONTEND_TYPE}&slug=${initialData.slug}&locale=${initialData.locale}`}
href={`${config?.domain}/api/preview?secret=${config?.token}&type=${config?.slug}&slug=${initialData.slug}&locale=${initialData.locale}`}
variant="secondary"
target="_blank"
rel="noopener noreferrer"
Expand Down
3 changes: 3 additions & 0 deletions packages/preview-button/admin/src/constants.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { pluginId } from './utils';

export const RESOLVE_CONFIG = `${pluginId}/resolve-config`;
50 changes: 50 additions & 0 deletions packages/preview-button/admin/src/hooks/use-plugin-config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { useEffect } from 'react';

import { useSelector, useDispatch } from 'react-redux';
import { request, useNotification } from '@strapi/helper-plugin';

import { RESOLVE_CONFIG } from '../constants';
import { pluginId } from '../utils';

const usePluginConfig = () => {
const dispatch = useDispatch();
const toggleNotification = useNotification();
const ctx = useSelector((state) => state[`${pluginId}_config`]);

useEffect(() => {
// Do nothing if we have already loaded the config data.
if (!ctx?.isLoading && !!ctx?.config) {
return;
}

const abortController = new AbortController();

const fetchData = async () => {
try {
const endpoint = `/${pluginId}/config`;
const data = await request(endpoint, {
method: 'GET',
signal: abortController.signal,
});
return data ?? {};
} catch (err) {
console.error(err);
if (!abortController.signal.aborted) {
toggleNotification({
type: 'warning',
message: { id: 'notification.error' },
});

return err;
}
}
};
fetchData().then((data) => dispatch({ type: RESOLVE_CONFIG, data }));

return () => abortController.abort();
}, [dispatch, toggleNotification]);

return { config: ctx?.config, isLoading: ctx?.isLoading };
};

export default usePluginConfig;
2 changes: 2 additions & 0 deletions packages/preview-button/admin/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@ import pluginId from './pluginId';
import Initializer from './components/Initializer';
import PreviewLink from './components/PreviewLink';
import PluginIcon from './components/PluginIcon';
import reducers from './reducers';

const name = pluginPkg.strapi.name;
export default {
register(app) {
app.addReducers(reducers);
// app.addMenuLink({
// to: `/plugins/${pluginId}`,
// icon: PluginIcon,
Expand Down
25 changes: 25 additions & 0 deletions packages/preview-button/admin/src/reducers/config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import produce from 'immer';

import { RESOLVE_CONFIG } from '../constants';

const initialState = {
isLoading: true,
config: {},
};

const configReducer = produce((state = initialState, action) => {
switch (action.type) {
case RESOLVE_CONFIG: {
state.isLoading = false;
state.config = action.data;
break;
}

default:
return state;
}

return state;
});

export default configReducer;
8 changes: 8 additions & 0 deletions packages/preview-button/admin/src/reducers/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { pluginId } from '../utils';
import config from './config';

const reducers = {
[`${pluginId}_config`]: config,
};

export default reducers;
1 change: 1 addition & 0 deletions packages/preview-button/admin/src/utils/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default as pluginId } from './plugin-id';
3 changes: 3 additions & 0 deletions packages/preview-button/admin/src/utils/plugin-id.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import pluginPkg from '../../../package.json';

export default pluginPkg.strapi.name;
17 changes: 16 additions & 1 deletion packages/preview-button/server/config/index.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,21 @@
'use strict';

const { ValidationError } = require('@strapi/utils').errors;

module.exports = {
default: {},
validator() {},
validator: (config) => {
if (!config) {
return;
}
if (!config?.domain) {
throw new ValidationError('Missing domain prop.');
}
if (!config?.token) {
throw new ValidationError('Missing token prop.');
}
if (!config?.slug) {
throw new ValidationError('Missing slug prop.');
}
},
};
4 changes: 2 additions & 2 deletions packages/preview-button/server/controllers/index.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
'use strict';

const myController = require('./my-controller');
const previewButton = require('./preview-button');

module.exports = {
myController,
'preview-button': previewButton,
};
7 changes: 0 additions & 7 deletions packages/preview-button/server/controllers/my-controller.js

This file was deleted.

14 changes: 14 additions & 0 deletions packages/preview-button/server/controllers/preview-button.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
'use strict';

const { getService } = require('../util');

module.exports = {
async config(ctx) {
try {
const config = await getService('plugin').getConfig();
ctx.body = config;
} catch (error) {
ctx.badRequest('Something went wrong with the Preview button config');
}
},
};
15 changes: 15 additions & 0 deletions packages/preview-button/server/routes/admin-api.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
'use strict';

module.exports = {
type: 'admin',
routes: [
{
method: 'GET',
path: '/config',
handler: 'preview-button.config',
config: {
policies: ['admin::isAuthenticatedAdmin'],
},
},
],
};
17 changes: 7 additions & 10 deletions packages/preview-button/server/routes/index.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
module.exports = [
{
method: 'GET',
path: '/',
handler: 'myController.index',
config: {
policies: [],
},
},
];
'use strict';

const admin = require('./admin-api');

module.exports = {
'admin-api': admin,
};
4 changes: 2 additions & 2 deletions packages/preview-button/server/services/index.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
'use strict';

const myService = require('./my-service');
const plugin = require('./plugin');

module.exports = {
myService,
plugin,
};
7 changes: 0 additions & 7 deletions packages/preview-button/server/services/my-service.js

This file was deleted.

11 changes: 11 additions & 0 deletions packages/preview-button/server/services/plugin.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
'use strict';

const config = require('../config');
const { pluginId } = require('../util');

module.exports = ({ strapi }) => ({
async getConfig() {
const data = await strapi.config.get(`plugin.${pluginId}`, config.default);
return data;
},
});
7 changes: 7 additions & 0 deletions packages/preview-button/server/util/get-service.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
'use strict';

const pluginId = require('./plugin-id');

const getService = (name) => strapi.plugin(pluginId).service(name);

module.exports = getService;
9 changes: 9 additions & 0 deletions packages/preview-button/server/util/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
'use strict';

const getService = require('./get-service');
const pluginId = require('./plugin-id');

module.exports = {
getService,
pluginId,
};
5 changes: 5 additions & 0 deletions packages/preview-button/server/util/plugin-id.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
'use strict';

const pluginPkg = require('../../package.json');

module.exports = pluginPkg.strapi.name;

0 comments on commit 924faa7

Please sign in to comment.