feat: add iframe-block plugin (#1281)
* feat: iframe-block plugin done * refactor: iframe html filed type changed * refactor: remove built-in actions in the ACL * refactor: use built-in resource action * fix: add iframe-block in built-in plugins * refactor: remove id collection schema * fix: fix iframe-block permission * fix: fix iframe-block permission * fix: improve code * fix: src * fix: bug Co-authored-by: chenos <chenlinxh@gmail.com>
This commit is contained in:
parent
98bad0c8ea
commit
6d1a4425f2
1
packages/app/client/src/plugins/iframe-block.ts
Normal file
1
packages/app/client/src/plugins/iframe-block.ts
Normal file
@ -0,0 +1 @@
|
|||||||
|
export { default } from '@nocobase/plugin-iframe-block/client';
|
@ -1,66 +0,0 @@
|
|||||||
import { ISchema, useField, useFieldSchema } from '@formily/react';
|
|
||||||
import React from 'react';
|
|
||||||
import { useTranslation } from 'react-i18next';
|
|
||||||
import { GeneralSchemaDesigner, SchemaSettings } from '../../../schema-settings';
|
|
||||||
import { useDesignable } from '../../hooks';
|
|
||||||
|
|
||||||
export const IframeDesigner = () => {
|
|
||||||
const field = useField();
|
|
||||||
const fieldSchema = useFieldSchema();
|
|
||||||
const { t } = useTranslation();
|
|
||||||
const { dn } = useDesignable();
|
|
||||||
|
|
||||||
return (
|
|
||||||
<GeneralSchemaDesigner>
|
|
||||||
<SchemaSettings.ModalItem
|
|
||||||
title={t('Edit iframe')}
|
|
||||||
schema={
|
|
||||||
{
|
|
||||||
type: 'object',
|
|
||||||
title: t('Edit chart'),
|
|
||||||
properties: {
|
|
||||||
url: {
|
|
||||||
title: t('URL'),
|
|
||||||
type: 'string',
|
|
||||||
default: fieldSchema?.['x-component-props']?.['url'],
|
|
||||||
'x-decorator': 'FormItem',
|
|
||||||
'x-component': 'Input',
|
|
||||||
required: true,
|
|
||||||
},
|
|
||||||
height: {
|
|
||||||
title: t('Height'),
|
|
||||||
type: 'string',
|
|
||||||
default: fieldSchema?.['x-component-props']?.height || '60vh',
|
|
||||||
'x-decorator': 'FormItem',
|
|
||||||
'x-component': 'Input',
|
|
||||||
required: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
} as ISchema
|
|
||||||
}
|
|
||||||
// {{ fetchData(api, { url: 'chartData:get' }) }}
|
|
||||||
onSubmit={async ({ url, height }) => {
|
|
||||||
field.componentProps.url = url;
|
|
||||||
field.componentProps.height = height;
|
|
||||||
const componentProps = fieldSchema['x-component-props'] || {};
|
|
||||||
componentProps['url'] = url;
|
|
||||||
componentProps['height'] = height;
|
|
||||||
fieldSchema['x-component-props'] = componentProps;
|
|
||||||
dn.emit('patch', {
|
|
||||||
schema: {
|
|
||||||
'x-uid': fieldSchema['x-uid'],
|
|
||||||
'x-component-props': componentProps,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<SchemaSettings.Divider />
|
|
||||||
<SchemaSettings.Remove
|
|
||||||
removeParentsIfNoChildren
|
|
||||||
breakRemoveOn={{
|
|
||||||
'x-component': 'Grid',
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</GeneralSchemaDesigner>
|
|
||||||
);
|
|
||||||
};
|
|
@ -1,4 +1,2 @@
|
|||||||
export * from './dnd-context';
|
export * from './dnd-context';
|
||||||
export * from './iframe';
|
|
||||||
export * from './sortable-item';
|
export * from './sortable-item';
|
||||||
|
|
||||||
|
@ -164,12 +164,6 @@ export const BlockInitializers = {
|
|||||||
title: '{{t("Markdown")}}',
|
title: '{{t("Markdown")}}',
|
||||||
component: 'MarkdownBlockInitializer',
|
component: 'MarkdownBlockInitializer',
|
||||||
},
|
},
|
||||||
{
|
|
||||||
key: 'iframe',
|
|
||||||
type: 'item',
|
|
||||||
title: '{{t("Iframe")}}',
|
|
||||||
component: 'IframeBlockInitializer',
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
key: 'auditLogs',
|
key: 'auditLogs',
|
||||||
type: 'item',
|
type: 'item',
|
||||||
|
@ -17,7 +17,6 @@ export * from './DetailsBlockInitializer';
|
|||||||
export * from './FilterActionInitializer';
|
export * from './FilterActionInitializer';
|
||||||
export * from './FormBlockInitializer';
|
export * from './FormBlockInitializer';
|
||||||
export * from './G2PlotInitializer';
|
export * from './G2PlotInitializer';
|
||||||
export * from './IframeBlockInitializer';
|
|
||||||
export * from './InitializerWithSwitch';
|
export * from './InitializerWithSwitch';
|
||||||
export * from './KanbanBlockInitializer';
|
export * from './KanbanBlockInitializer';
|
||||||
export * from './MarkdownBlockInitializer';
|
export * from './MarkdownBlockInitializer';
|
||||||
@ -38,4 +37,3 @@ export * from './TableSelectorInitializer';
|
|||||||
export * from './UpdateActionInitializer';
|
export * from './UpdateActionInitializer';
|
||||||
export * from './UpdateSubmitActionInitializer';
|
export * from './UpdateSubmitActionInitializer';
|
||||||
export * from './ViewActionInitializer';
|
export * from './ViewActionInitializer';
|
||||||
|
|
||||||
|
@ -22,7 +22,7 @@ import {
|
|||||||
useAPIClient,
|
useAPIClient,
|
||||||
useCollection,
|
useCollection,
|
||||||
useCompile,
|
useCompile,
|
||||||
useDesignable,
|
useDesignable
|
||||||
} from '..';
|
} from '..';
|
||||||
import { useSchemaTemplateManager } from '../schema-templates';
|
import { useSchemaTemplateManager } from '../schema-templates';
|
||||||
import { useBlockTemplateContext } from '../schema-templates/BlockTemplate';
|
import { useBlockTemplateContext } from '../schema-templates/BlockTemplate';
|
||||||
@ -574,7 +574,18 @@ SchemaSettings.ActionModalItem = React.memo((props: any) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
SchemaSettings.ModalItem = (props) => {
|
SchemaSettings.ModalItem = (props) => {
|
||||||
const { hidden, title, components, scope, effects, schema, onSubmit, initialValues, ...others } = props;
|
const {
|
||||||
|
hidden,
|
||||||
|
title,
|
||||||
|
components,
|
||||||
|
scope,
|
||||||
|
effects,
|
||||||
|
schema,
|
||||||
|
onSubmit,
|
||||||
|
asyncGetInitialValues,
|
||||||
|
initialValues,
|
||||||
|
...others
|
||||||
|
} = props;
|
||||||
const options = useContext(SchemaOptionsContext);
|
const options = useContext(SchemaOptionsContext);
|
||||||
const cm = useContext(CollectionManagerContext);
|
const cm = useContext(CollectionManagerContext);
|
||||||
if (hidden) {
|
if (hidden) {
|
||||||
@ -583,7 +594,8 @@ SchemaSettings.ModalItem = (props) => {
|
|||||||
return (
|
return (
|
||||||
<SchemaSettings.Item
|
<SchemaSettings.Item
|
||||||
{...others}
|
{...others}
|
||||||
onClick={() => {
|
onClick={async () => {
|
||||||
|
const values = asyncGetInitialValues ? await asyncGetInitialValues() : initialValues;
|
||||||
FormDialog(schema.title || title, () => {
|
FormDialog(schema.title || title, () => {
|
||||||
return (
|
return (
|
||||||
<CollectionManagerContext.Provider value={cm}>
|
<CollectionManagerContext.Provider value={cm}>
|
||||||
@ -596,7 +608,7 @@ SchemaSettings.ModalItem = (props) => {
|
|||||||
);
|
);
|
||||||
})
|
})
|
||||||
.open({
|
.open({
|
||||||
initialValues,
|
initialValues: values,
|
||||||
effects,
|
effects,
|
||||||
})
|
})
|
||||||
.then((values) => {
|
.then((values) => {
|
||||||
|
@ -56,7 +56,8 @@ export function registerMiddlewares(app: Application, options: ApplicationOption
|
|||||||
|
|
||||||
app.use(async (ctx, next) => {
|
app.use(async (ctx, next) => {
|
||||||
ctx.getBearerToken = () => {
|
ctx.getBearerToken = () => {
|
||||||
return ctx.get('Authorization').replace(/^Bearer\s+/gi, '');
|
const token = ctx.get('Authorization').replace(/^Bearer\s+/gi, '');
|
||||||
|
return token || ctx.query.token;
|
||||||
};
|
};
|
||||||
await next();
|
await next();
|
||||||
});
|
});
|
||||||
|
4
packages/plugins/iframe-block/client.d.ts
vendored
Normal file
4
packages/plugins/iframe-block/client.d.ts
vendored
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
// @ts-nocheck
|
||||||
|
export * from './lib/client';
|
||||||
|
export { default } from './lib/client';
|
||||||
|
|
30
packages/plugins/iframe-block/client.js
Normal file
30
packages/plugins/iframe-block/client.js
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
"use strict";
|
||||||
|
|
||||||
|
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
|
||||||
|
|
||||||
|
function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
|
||||||
|
|
||||||
|
var _index = _interopRequireWildcard(require("./lib/client"));
|
||||||
|
|
||||||
|
Object.defineProperty(exports, "__esModule", {
|
||||||
|
value: true
|
||||||
|
});
|
||||||
|
var _exportNames = {};
|
||||||
|
Object.defineProperty(exports, "default", {
|
||||||
|
enumerable: true,
|
||||||
|
get: function get() {
|
||||||
|
return _index.default;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Object.keys(_index).forEach(function (key) {
|
||||||
|
if (key === "default" || key === "__esModule") return;
|
||||||
|
if (Object.prototype.hasOwnProperty.call(_exportNames, key)) return;
|
||||||
|
if (key in exports && exports[key] === _index[key]) return;
|
||||||
|
Object.defineProperty(exports, key, {
|
||||||
|
enumerable: true,
|
||||||
|
get: function get() {
|
||||||
|
return _index[key];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
9
packages/plugins/iframe-block/package.json
Normal file
9
packages/plugins/iframe-block/package.json
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"name": "@nocobase/plugin-iframe-block",
|
||||||
|
"version": "0.8.0-alpha.13",
|
||||||
|
"main": "lib/server/index.js",
|
||||||
|
"devDependencies": {
|
||||||
|
"@nocobase/server": "0.8.0-alpha.13",
|
||||||
|
"@nocobase/test": "0.8.0-alpha.13"
|
||||||
|
}
|
||||||
|
}
|
4
packages/plugins/iframe-block/server.d.ts
vendored
Normal file
4
packages/plugins/iframe-block/server.d.ts
vendored
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
// @ts-nocheck
|
||||||
|
export * from './lib/server';
|
||||||
|
export { default } from './lib/server';
|
||||||
|
|
30
packages/plugins/iframe-block/server.js
Normal file
30
packages/plugins/iframe-block/server.js
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
"use strict";
|
||||||
|
|
||||||
|
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
|
||||||
|
|
||||||
|
function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
|
||||||
|
|
||||||
|
var _index = _interopRequireWildcard(require("./lib/server"));
|
||||||
|
|
||||||
|
Object.defineProperty(exports, "__esModule", {
|
||||||
|
value: true
|
||||||
|
});
|
||||||
|
var _exportNames = {};
|
||||||
|
Object.defineProperty(exports, "default", {
|
||||||
|
enumerable: true,
|
||||||
|
get: function get() {
|
||||||
|
return _index.default;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Object.keys(_index).forEach(function (key) {
|
||||||
|
if (key === "default" || key === "__esModule") return;
|
||||||
|
if (Object.prototype.hasOwnProperty.call(_exportNames, key)) return;
|
||||||
|
if (key in exports && exports[key] === _index[key]) return;
|
||||||
|
Object.defineProperty(exports, key, {
|
||||||
|
enumerable: true,
|
||||||
|
get: function get() {
|
||||||
|
return _index[key];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
131
packages/plugins/iframe-block/src/client/Iframe.Designer.tsx
Normal file
131
packages/plugins/iframe-block/src/client/Iframe.Designer.tsx
Normal file
@ -0,0 +1,131 @@
|
|||||||
|
import { ISchema, useField, useFieldSchema } from '@formily/react';
|
||||||
|
import { uid } from '@formily/shared';
|
||||||
|
import { GeneralSchemaDesigner, SchemaSettings, useAPIClient, useDesignable } from '@nocobase/client';
|
||||||
|
import React from 'react';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
|
export const IframeDesigner = () => {
|
||||||
|
const field = useField();
|
||||||
|
const fieldSchema = useFieldSchema();
|
||||||
|
const { t } = useTranslation();
|
||||||
|
const { dn } = useDesignable();
|
||||||
|
const api = useAPIClient();
|
||||||
|
const { mode, url, htmlId, height = '60vh' } = fieldSchema['x-component-props'] || {};
|
||||||
|
|
||||||
|
const saveHtml = async (html: string) => {
|
||||||
|
const options = {
|
||||||
|
values: { html },
|
||||||
|
};
|
||||||
|
if (htmlId) {
|
||||||
|
const { data } = await api.resource('iframeHtml').update?.({ ...options, filterByTk: htmlId });
|
||||||
|
return data?.data?.[0] || { id: htmlId };
|
||||||
|
} else {
|
||||||
|
const { data } = await api.resource('iframeHtml').create?.(options);
|
||||||
|
return data?.data;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const submitHandler = async ({ mode, url, html, height }) => {
|
||||||
|
const componentProps = fieldSchema['x-component-props'] || {};
|
||||||
|
componentProps['mode'] = mode;
|
||||||
|
componentProps['height'] = height;
|
||||||
|
componentProps['url'] = url;
|
||||||
|
if (mode === 'html') {
|
||||||
|
const data = await saveHtml(html);
|
||||||
|
componentProps['htmlId'] = data.id;
|
||||||
|
}
|
||||||
|
fieldSchema['x-component-props'] = componentProps;
|
||||||
|
field.componentProps = { ...componentProps };
|
||||||
|
field.data = { v: uid() };
|
||||||
|
dn.emit('patch', {
|
||||||
|
schema: {
|
||||||
|
'x-uid': fieldSchema['x-uid'],
|
||||||
|
'x-component-props': componentProps,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<GeneralSchemaDesigner>
|
||||||
|
<SchemaSettings.ModalItem
|
||||||
|
title={t('Edit iframe')}
|
||||||
|
asyncGetInitialValues={async () => {
|
||||||
|
const values = {
|
||||||
|
mode,
|
||||||
|
url,
|
||||||
|
height,
|
||||||
|
};
|
||||||
|
if (htmlId) {
|
||||||
|
const { data } = await api.resource('iframeHtml').get?.({ filterByTk: htmlId });
|
||||||
|
values['html'] = data?.data?.html || '';
|
||||||
|
}
|
||||||
|
return values;
|
||||||
|
}}
|
||||||
|
schema={
|
||||||
|
{
|
||||||
|
type: 'object',
|
||||||
|
title: t('Edit iframe'),
|
||||||
|
properties: {
|
||||||
|
mode: {
|
||||||
|
title: '{{t("Mode")}}',
|
||||||
|
'x-component': 'Radio.Group',
|
||||||
|
'x-decorator': 'FormItem',
|
||||||
|
required: true,
|
||||||
|
default: 'url',
|
||||||
|
enum: [
|
||||||
|
{ value: 'url', label: t('URL') },
|
||||||
|
{ value: 'html', label: t('html') },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
url: {
|
||||||
|
title: t('URL'),
|
||||||
|
type: 'string',
|
||||||
|
'x-decorator': 'FormItem',
|
||||||
|
'x-component': 'Input',
|
||||||
|
required: true,
|
||||||
|
'x-reactions': {
|
||||||
|
dependencies: ['mode'],
|
||||||
|
fulfill: {
|
||||||
|
state: {
|
||||||
|
hidden: '{{$deps[0] === "html"}}',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
html: {
|
||||||
|
title: t('html'),
|
||||||
|
type: 'string',
|
||||||
|
'x-decorator': 'FormItem',
|
||||||
|
'x-component': 'Input.TextArea',
|
||||||
|
required: true,
|
||||||
|
'x-reactions': {
|
||||||
|
dependencies: ['mode'],
|
||||||
|
fulfill: {
|
||||||
|
state: {
|
||||||
|
hidden: '{{$deps[0] === "url"}}',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
height: {
|
||||||
|
title: t('Height'),
|
||||||
|
type: 'string',
|
||||||
|
'x-decorator': 'FormItem',
|
||||||
|
'x-component': 'Input',
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
} as ISchema
|
||||||
|
}
|
||||||
|
onSubmit={submitHandler}
|
||||||
|
/>
|
||||||
|
<SchemaSettings.Divider />
|
||||||
|
<SchemaSettings.Remove
|
||||||
|
removeParentsIfNoChildren
|
||||||
|
breakRemoveOn={{
|
||||||
|
'x-component': 'Grid',
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</GeneralSchemaDesigner>
|
||||||
|
);
|
||||||
|
};
|
@ -1,4 +1,5 @@
|
|||||||
import { observer } from '@formily/react';
|
import { observer, useField } from '@formily/react';
|
||||||
|
import { useAPIClient } from '@nocobase/client';
|
||||||
import { Card } from 'antd';
|
import { Card } from 'antd';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
@ -6,7 +7,7 @@ import RIframe from 'react-iframe';
|
|||||||
import type { IIframe } from 'react-iframe/types';
|
import type { IIframe } from 'react-iframe/types';
|
||||||
import { IframeDesigner } from './Iframe.Designer';
|
import { IframeDesigner } from './Iframe.Designer';
|
||||||
|
|
||||||
function isNumeric(str: string) {
|
function isNumeric(str: string | undefined) {
|
||||||
if (typeof str !== 'string') return false; // we only process strings!
|
if (typeof str !== 'string') return false; // we only process strings!
|
||||||
return (
|
return (
|
||||||
!isNaN(str as any) && // use type coercion to parse the _entirety_ of the string (`parseFloat` alone does not do this)...
|
!isNaN(str as any) && // use type coercion to parse the _entirety_ of the string (`parseFloat` alone does not do this)...
|
||||||
@ -14,15 +15,27 @@ function isNumeric(str: string) {
|
|||||||
); // ...and ensure strings of whitespace fail
|
); // ...and ensure strings of whitespace fail
|
||||||
}
|
}
|
||||||
|
|
||||||
export const Iframe: any = observer((props: IIframe) => {
|
export const Iframe: any = observer((props: IIframe & { html?: string; htmlId?: number; mode: string }) => {
|
||||||
const { url, height, ...others } = props;
|
const { url, htmlId, mode = 'url', height, html, ...others } = props;
|
||||||
|
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
if (!url) {
|
const api = useAPIClient();
|
||||||
|
const field = useField();
|
||||||
|
|
||||||
|
const src = React.useMemo(() => {
|
||||||
|
if (mode === 'html') {
|
||||||
|
return `/api/iframeHtml:getHtml/${htmlId}?token=${api.auth.getToken()}&v=${field.data?.v || ''}`;
|
||||||
|
}
|
||||||
|
return url;
|
||||||
|
}, [url, mode, htmlId, field.data?.v]);
|
||||||
|
|
||||||
|
if ((mode === 'url' && !url) || (mode === 'html' && !htmlId)) {
|
||||||
return <Card style={{ marginBottom: 24 }}>{t('Please fill in the iframe URL')}</Card>;
|
return <Card style={{ marginBottom: 24 }}>{t('Please fill in the iframe URL')}</Card>;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<RIframe
|
<RIframe
|
||||||
url={url}
|
url={src}
|
||||||
width="100%"
|
width="100%"
|
||||||
display="block"
|
display="block"
|
||||||
position="relative"
|
position="relative"
|
@ -1,9 +1,8 @@
|
|||||||
import { FormOutlined } from '@ant-design/icons';
|
import { FormOutlined } from '@ant-design/icons';
|
||||||
|
import { SchemaInitializer } from '@nocobase/client';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
import { SchemaInitializer } from '../SchemaInitializer';
|
|
||||||
|
|
||||||
export const IframeBlockInitializer = (props) => {
|
export const IframeBlockInitializer = (props) => {
|
||||||
const { insert } = props;
|
const { insert } = props;
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
@ -0,0 +1,18 @@
|
|||||||
|
import { SchemaInitializerContext } from '@nocobase/client';
|
||||||
|
import { useContext } from 'react';
|
||||||
|
|
||||||
|
export const IframeBlockInitializerProvider = (props: any) => {
|
||||||
|
const initializes = useContext(SchemaInitializerContext);
|
||||||
|
const mediaItem = initializes.BlockInitializers.items.find((item) => item.key === 'media');
|
||||||
|
const hasIframeBlockInitializer = mediaItem.children.some(
|
||||||
|
(initialize) => initialize.component === 'IframeBlockInitializer',
|
||||||
|
);
|
||||||
|
!hasIframeBlockInitializer &&
|
||||||
|
mediaItem.children.push({
|
||||||
|
key: 'iframe',
|
||||||
|
type: 'item',
|
||||||
|
title: '{{t("Iframe")}}',
|
||||||
|
component: 'IframeBlockInitializer',
|
||||||
|
});
|
||||||
|
return props.children;
|
||||||
|
};
|
@ -0,0 +1,13 @@
|
|||||||
|
import { SchemaComponentOptions } from '@nocobase/client';
|
||||||
|
import React from 'react';
|
||||||
|
import { Iframe } from './Iframe';
|
||||||
|
import { IframeBlockInitializer } from './IframeBlockInitializer';
|
||||||
|
import { IframeBlockInitializerProvider } from './IframeBlockInitializerProvider';
|
||||||
|
|
||||||
|
export const IframeBlockPlugin = (props: any) => {
|
||||||
|
return (
|
||||||
|
<SchemaComponentOptions components={{ Iframe, IframeBlockInitializer }}>
|
||||||
|
<IframeBlockInitializerProvider>{props.children}</IframeBlockInitializerProvider>
|
||||||
|
</SchemaComponentOptions>
|
||||||
|
);
|
||||||
|
};
|
1
packages/plugins/iframe-block/src/client/index.ts
Normal file
1
packages/plugins/iframe-block/src/client/index.ts
Normal file
@ -0,0 +1 @@
|
|||||||
|
export { IframeBlockPlugin as default } from './IframeBlockPlugin';
|
1
packages/plugins/iframe-block/src/index.ts
Normal file
1
packages/plugins/iframe-block/src/index.ts
Normal file
@ -0,0 +1 @@
|
|||||||
|
export { default } from './server';
|
17
packages/plugins/iframe-block/src/server/actions/index.ts
Normal file
17
packages/plugins/iframe-block/src/server/actions/index.ts
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
import { Context, Next } from '@nocobase/actions';
|
||||||
|
import { Repository } from '@nocobase/database';
|
||||||
|
|
||||||
|
export async function getHtml(ctx: Context, next: Next) {
|
||||||
|
let { filterByTk } = ctx.action.params;
|
||||||
|
const { resourceName } = ctx.action;
|
||||||
|
const repository = ctx.db.getRepository<any>(resourceName) as Repository;
|
||||||
|
const model = await repository.findById(filterByTk);
|
||||||
|
ctx.body = model.get('html');
|
||||||
|
ctx.withoutDataWrapping = true;
|
||||||
|
|
||||||
|
ctx.set({
|
||||||
|
'Content-Type': 'text/html; charset=UTF-8',
|
||||||
|
});
|
||||||
|
|
||||||
|
await next();
|
||||||
|
}
|
@ -0,0 +1,18 @@
|
|||||||
|
import { CollectionOptions } from '@nocobase/database';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'iframeHtml',
|
||||||
|
createdBy: true,
|
||||||
|
updatedBy: true,
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
type: 'uid',
|
||||||
|
name: 'id',
|
||||||
|
primaryKey: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'text',
|
||||||
|
name: 'html',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
} as CollectionOptions;
|
1
packages/plugins/iframe-block/src/server/index.ts
Normal file
1
packages/plugins/iframe-block/src/server/index.ts
Normal file
@ -0,0 +1 @@
|
|||||||
|
export { default } from './plugin';
|
30
packages/plugins/iframe-block/src/server/plugin.ts
Normal file
30
packages/plugins/iframe-block/src/server/plugin.ts
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
import { InstallOptions, Plugin } from '@nocobase/server';
|
||||||
|
import path from 'path';
|
||||||
|
import { getHtml } from './actions';
|
||||||
|
|
||||||
|
export class IframeBlockPlugin extends Plugin {
|
||||||
|
afterAdd() {}
|
||||||
|
|
||||||
|
beforeLoad() {}
|
||||||
|
|
||||||
|
async load() {
|
||||||
|
await this.db.import({
|
||||||
|
directory: path.resolve(__dirname, 'collections'),
|
||||||
|
});
|
||||||
|
this.app.acl.allow('iframeHtml', ['get', 'create', 'update', 'destroy'], 'allowConfigure');
|
||||||
|
this.app.acl.allow('iframeHtml', 'getHtml', 'loggedIn');
|
||||||
|
this.app.actions({
|
||||||
|
'iframeHtml:getHtml': getHtml,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async install(options?: InstallOptions) {}
|
||||||
|
|
||||||
|
async afterEnable() {}
|
||||||
|
|
||||||
|
async afterDisable() {}
|
||||||
|
|
||||||
|
async remove() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default IframeBlockPlugin;
|
@ -31,6 +31,7 @@
|
|||||||
"@nocobase/plugin-verification": "0.8.0-alpha.13",
|
"@nocobase/plugin-verification": "0.8.0-alpha.13",
|
||||||
"@nocobase/plugin-workflow": "0.8.0-alpha.13",
|
"@nocobase/plugin-workflow": "0.8.0-alpha.13",
|
||||||
"@nocobase/plugin-map": "0.8.0-alpha.13",
|
"@nocobase/plugin-map": "0.8.0-alpha.13",
|
||||||
|
"@nocobase/plugin-iframe-block": "0.8.0-alpha.13",
|
||||||
"@nocobase/server": "0.8.0-alpha.13"
|
"@nocobase/server": "0.8.0-alpha.13"
|
||||||
},
|
},
|
||||||
"repository": {
|
"repository": {
|
||||||
|
@ -23,6 +23,7 @@ export class PresetNocoBase extends Plugin {
|
|||||||
'export',
|
'export',
|
||||||
'import',
|
'import',
|
||||||
'audit-logs',
|
'audit-logs',
|
||||||
|
'iframe-block',
|
||||||
].concat(plugins),
|
].concat(plugins),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user