plugin-build-guide-block 1.0.9 → 1.0.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. package/README.md +74 -74
  2. package/dist/client/index.js +1 -1
  3. package/dist/client/models/index.d.ts +1 -3
  4. package/dist/externalVersion.js +7 -7
  5. package/dist/locale/en-US.json +28 -27
  6. package/dist/locale/vi-VN.json +28 -27
  7. package/dist/locale/zh-CN.json +28 -27
  8. package/dist/node_modules/sanitize-html/index.js +2 -2
  9. package/dist/node_modules/sanitize-html/package.json +1 -1
  10. package/dist/server/actions/build.js +3 -0
  11. package/dist/server/index.d.ts +1 -0
  12. package/dist/server/index.js +7 -1
  13. package/dist/server/plugin.js +14 -0
  14. package/package.json +31 -31
  15. package/src/client/UserGuideBlock.tsx +53 -53
  16. package/src/client/UserGuideBlockInitializer.tsx +26 -26
  17. package/src/client/UserGuideBlockProvider.tsx +12 -12
  18. package/src/client/UserGuideManager.tsx +128 -107
  19. package/src/client/components/BuildButton.tsx +78 -43
  20. package/src/client/components/LLMServiceSelect.tsx +44 -44
  21. package/src/client/components/ModelSelect.tsx +41 -41
  22. package/src/client/components/StatusTag.tsx +17 -17
  23. package/src/client/models/UserGuideBlockModel.ts +54 -54
  24. package/src/client/models/index.ts +1 -3
  25. package/src/client/plugin.tsx +30 -30
  26. package/src/client/schemas/spacesSchema.ts +316 -316
  27. package/src/locale/en-US.json +28 -27
  28. package/src/locale/vi-VN.json +28 -27
  29. package/src/locale/zh-CN.json +28 -27
  30. package/src/server/actions/build.ts +176 -171
  31. package/src/server/actions/getHtml.ts +26 -26
  32. package/src/server/collections/ai-build-guide-spaces.ts +50 -50
  33. package/src/server/index.ts +1 -0
  34. package/src/server/plugin.ts +76 -60
@@ -1 +1 @@
1
- {"name":"sanitize-html","version":"2.17.2","description":"Clean up user-submitted HTML, preserving allowlisted elements and allowlisted attributes on a per-element basis","sideEffects":false,"main":"index.js","files":["index.js"],"repository":{"type":"git","url":"https://github.com/apostrophecms/apostrophe.git","directory":"packages/sanitize-html"},"homepage":"https://github.com/apostrophecms/apostrophe/tree/main/packages/sanitize-html#readme","keywords":["html","parser","sanitizer","sanitize"],"author":"Apostrophe Technologies, Inc.","license":"MIT","dependencies":{"deepmerge":"^4.2.2","escape-string-regexp":"^4.0.0","htmlparser2":"^10.1.0","is-plain-object":"^5.0.0","parse-srcset":"^1.0.2","postcss":"^8.3.11"},"devDependencies":{"eslint":"^9.39.1","mocha":"^10.2.0","sinon":"^9.0.2","eslint-config-apostrophe":"^6.0.2"},"apostropheTestConfig":{"requiresMongo":false},"scripts":{"test":"npm run lint && mocha","lint":"eslint ."},"_lastModified":"2026-04-09T19:44:45.769Z"}
1
+ {"name":"sanitize-html","version":"2.17.3","description":"Clean up user-submitted HTML, preserving allowlisted elements and allowlisted attributes on a per-element basis","sideEffects":false,"main":"index.js","files":["index.js"],"repository":{"type":"git","url":"https://github.com/apostrophecms/apostrophe.git","directory":"packages/sanitize-html"},"homepage":"https://github.com/apostrophecms/apostrophe/tree/main/packages/sanitize-html#readme","keywords":["html","parser","sanitizer","sanitize"],"author":"Apostrophe Technologies, Inc.","license":"MIT","dependencies":{"deepmerge":"^4.2.2","escape-string-regexp":"^4.0.0","htmlparser2":"^10.1.0","is-plain-object":"^5.0.0","parse-srcset":"^1.0.2","postcss":"^8.3.11"},"devDependencies":{"eslint":"^9.39.1","mocha":"^11.7.5","sinon":"^9.0.2","eslint-config-apostrophe":"^6.0.2"},"apostropheTestConfig":{"requiresMongo":false},"scripts":{"test":"npm run lint && mocha","lint":"eslint ."},"_lastModified":"2026-04-18T11:47:25.046Z"}
@@ -73,6 +73,9 @@ async function build(ctx, next) {
73
73
  if (!space) {
74
74
  ctx.throw(404, "Space not found");
75
75
  }
76
+ if (space.get("status") === "building") {
77
+ ctx.throw(409, "A build is already in progress for this space");
78
+ }
76
79
  const app = ctx.app;
77
80
  const db = ctx.db;
78
81
  try {
@@ -1 +1,2 @@
1
1
  export { default } from './plugin';
2
+ export declare const namespace = "plugin-build-guide-block";
@@ -36,7 +36,13 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
36
36
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
37
37
  var server_exports = {};
38
38
  __export(server_exports, {
39
- default: () => import_plugin.default
39
+ default: () => import_plugin.default,
40
+ namespace: () => namespace
40
41
  });
41
42
  module.exports = __toCommonJS(server_exports);
42
43
  var import_plugin = __toESM(require("./plugin"));
44
+ const namespace = "plugin-build-guide-block";
45
+ // Annotate the CommonJS export names for ESM import in node:
46
+ 0 && (module.exports = {
47
+ namespace
48
+ });
@@ -55,6 +55,20 @@ class PluginBuildGuideBlockServer extends import_server.Plugin {
55
55
  "aiBuildGuideSpaces:build"
56
56
  ]
57
57
  });
58
+ this.app.on("afterStart", async () => {
59
+ try {
60
+ const repo = this.db.getRepository("aiBuildGuideSpaces");
61
+ await repo.update({
62
+ filter: { status: "building" },
63
+ values: {
64
+ status: "error",
65
+ buildLog: "Build interrupted by server restart"
66
+ }
67
+ });
68
+ } catch (err) {
69
+ this.app.logger.warn("[plugin-build-guide-block] Failed to recover stale builds", err);
70
+ }
71
+ });
58
72
  }
59
73
  async install(options) {
60
74
  const collection = this.db.getCollection("aiBuildGuideSpaces");
package/package.json CHANGED
@@ -1,31 +1,31 @@
1
- {
2
- "name": "plugin-build-guide-block",
3
- "version": "1.0.9",
4
- "main": "dist/server/index.js",
5
- "files": [
6
- "dist",
7
- "src",
8
- "client.js",
9
- "server.js",
10
- "client.d.ts",
11
- "server.d.ts"
12
- ],
13
- "dependencies": {
14
- "dompurify": "^3.1.2",
15
- "sanitize-html": "^2.13.0"
16
- },
17
- "devDependencies": {
18
- "@types/dompurify": "^3.0.4",
19
- "@types/sanitize-html": "^2.9.5"
20
- },
21
- "peerDependencies": {
22
- "@nocobase/client": "2.x",
23
- "@nocobase/server": "2.x",
24
- "@nocobase/database": "2.x",
25
- "@nocobase/test": "2.x",
26
- "@nocobase/plugin-ai": "2.x",
27
- "@nocobase/plugin-file-manager": "2.x",
28
- "@langchain/core": "*",
29
- "axios": "*"
30
- }
31
- }
1
+ {
2
+ "name": "plugin-build-guide-block",
3
+ "version": "1.0.11",
4
+ "main": "dist/server/index.js",
5
+ "files": [
6
+ "dist",
7
+ "src",
8
+ "client.js",
9
+ "server.js",
10
+ "client.d.ts",
11
+ "server.d.ts"
12
+ ],
13
+ "dependencies": {
14
+ "dompurify": "^3.1.2",
15
+ "sanitize-html": "^2.13.0"
16
+ },
17
+ "devDependencies": {
18
+ "@types/dompurify": "^3.0.4",
19
+ "@types/sanitize-html": "^2.9.5"
20
+ },
21
+ "peerDependencies": {
22
+ "@nocobase/client": "2.x",
23
+ "@nocobase/server": "2.x",
24
+ "@nocobase/database": "2.x",
25
+ "@nocobase/test": "2.x",
26
+ "@nocobase/plugin-ai": "2.x",
27
+ "@nocobase/plugin-file-manager": "2.x",
28
+ "@langchain/core": "*",
29
+ "axios": "*"
30
+ }
31
+ }
@@ -1,53 +1,53 @@
1
- import React from 'react';
2
- import { Card, Spin } from 'antd';
3
- import { useRequest } from '@nocobase/client';
4
- import { observer } from '@formily/react';
5
- import { useTranslation } from 'react-i18next';
6
- import DOMPurify from 'dompurify';
7
-
8
- export const UserGuideBlock = observer(
9
- (props: any) => {
10
- const { spaceId } = props;
11
- const { t } = useTranslation();
12
-
13
- const { loading, data: htmlContent } = useRequest(
14
- {
15
- url: `aiBuildGuideSpaces:getHtml/${spaceId}`,
16
- },
17
- {
18
- refreshDeps: [spaceId],
19
- ready: !!spaceId,
20
- }
21
- );
22
-
23
- if (!spaceId) {
24
- return (
25
- <Card style={{ padding: 24, textAlign: 'center', color: '#888' }}>
26
- {t('Please select a User Guide Space in block settings')}
27
- </Card>
28
- );
29
- }
30
-
31
- if (loading) {
32
- return (
33
- <Card style={{ padding: 24, textAlign: 'center' }}>
34
- <Spin size="large" />
35
- </Card>
36
- );
37
- }
38
-
39
- return (
40
- <Card
41
- bordered={false}
42
- className="user-guide-block"
43
- style={{ width: '100%', minHeight: 300 }}
44
- >
45
- <div
46
- className="user-guide-content"
47
- dangerouslySetInnerHTML={{ __html: DOMPurify.sanitize((htmlContent as any)?.data || '') }}
48
- />
49
- </Card>
50
- );
51
- },
52
- { displayName: 'UserGuideBlock' }
53
- );
1
+ import React from 'react';
2
+ import { Card, Spin } from 'antd';
3
+ import { useRequest } from '@nocobase/client';
4
+ import { observer } from '@formily/react';
5
+ import { useTranslation } from 'react-i18next';
6
+ import DOMPurify from 'dompurify';
7
+
8
+ export const UserGuideBlock = observer(
9
+ (props: any) => {
10
+ const { spaceId } = props;
11
+ const { t } = useTranslation();
12
+
13
+ const { loading, data: htmlContent } = useRequest(
14
+ {
15
+ url: `aiBuildGuideSpaces:getHtml/${spaceId}`,
16
+ },
17
+ {
18
+ refreshDeps: [spaceId],
19
+ ready: !!spaceId,
20
+ }
21
+ );
22
+
23
+ if (!spaceId) {
24
+ return (
25
+ <Card style={{ padding: 24, textAlign: 'center', color: '#888' }}>
26
+ {t('Please select a User Guide Space in block settings')}
27
+ </Card>
28
+ );
29
+ }
30
+
31
+ if (loading) {
32
+ return (
33
+ <Card style={{ padding: 24, textAlign: 'center' }}>
34
+ <Spin size="large" />
35
+ </Card>
36
+ );
37
+ }
38
+
39
+ return (
40
+ <Card
41
+ bordered={false}
42
+ className="user-guide-block"
43
+ style={{ width: '100%', minHeight: 300 }}
44
+ >
45
+ <div
46
+ className="user-guide-content"
47
+ dangerouslySetInnerHTML={{ __html: DOMPurify.sanitize((htmlContent as any)?.data || '') }}
48
+ />
49
+ </Card>
50
+ );
51
+ },
52
+ { displayName: 'UserGuideBlock' }
53
+ );
@@ -1,26 +1,26 @@
1
- import React from 'react';
2
- import { SchemaInitializerItem, useSchemaInitializer, useSchemaInitializerItem } from '@nocobase/client';
3
- import { ReadOutlined } from '@ant-design/icons';
4
-
5
- export const UserGuideBlockInitializer = () => {
6
- const { insert } = useSchemaInitializer();
7
- const itemConfig = useSchemaInitializerItem();
8
- return (
9
- <SchemaInitializerItem
10
- {...itemConfig}
11
- icon={<ReadOutlined />}
12
- onClick={() => {
13
- insert({
14
- type: 'void',
15
- 'x-settings': 'userGuideBlockSettings',
16
- 'x-decorator': 'BlockItem',
17
- 'x-decorator-props': {
18
- name: 'userGuide',
19
- },
20
- 'x-component': 'UserGuideBlock',
21
- 'x-component-props': {},
22
- });
23
- }}
24
- />
25
- );
26
- };
1
+ import React from 'react';
2
+ import { SchemaInitializerItem, useSchemaInitializer, useSchemaInitializerItem } from '@nocobase/client';
3
+ import { ReadOutlined } from '@ant-design/icons';
4
+
5
+ export const UserGuideBlockInitializer = () => {
6
+ const { insert } = useSchemaInitializer();
7
+ const itemConfig = useSchemaInitializerItem();
8
+ return (
9
+ <SchemaInitializerItem
10
+ {...itemConfig}
11
+ icon={<ReadOutlined />}
12
+ onClick={() => {
13
+ insert({
14
+ type: 'void',
15
+ 'x-settings': 'userGuideBlockSettings',
16
+ 'x-decorator': 'BlockItem',
17
+ 'x-decorator-props': {
18
+ name: 'userGuide',
19
+ },
20
+ 'x-component': 'UserGuideBlock',
21
+ 'x-component-props': {},
22
+ });
23
+ }}
24
+ />
25
+ );
26
+ };
@@ -1,12 +1,12 @@
1
- import React from 'react';
2
- import { SchemaComponentOptions } from '@nocobase/client';
3
- import { UserGuideBlock } from './UserGuideBlock';
4
- import { UserGuideBlockInitializer } from './UserGuideBlockInitializer';
5
-
6
- export const UserGuideBlockProvider = (props: any) => {
7
- return (
8
- <SchemaComponentOptions components={{ UserGuideBlock, UserGuideBlockInitializer }}>
9
- {props.children}
10
- </SchemaComponentOptions>
11
- );
12
- };
1
+ import React from 'react';
2
+ import { SchemaComponentOptions } from '@nocobase/client';
3
+ import { UserGuideBlock } from './UserGuideBlock';
4
+ import { UserGuideBlockInitializer } from './UserGuideBlockInitializer';
5
+
6
+ export const UserGuideBlockProvider = (props: any) => {
7
+ return (
8
+ <SchemaComponentOptions components={{ UserGuideBlock, UserGuideBlockInitializer }}>
9
+ {props.children}
10
+ </SchemaComponentOptions>
11
+ );
12
+ };
@@ -1,107 +1,128 @@
1
- import React, { useMemo } from 'react';
2
- import {
3
- SchemaComponent,
4
- useActionContext,
5
- useCollectionRecordData,
6
- useDataBlockRequest,
7
- useDataBlockResource,
8
- useDestroyActionProps,
9
- useTableBlockProps,
10
- } from '@nocobase/client';
11
- import { createForm } from '@formily/core';
12
- import { App } from 'antd';
13
- import { useTranslation } from 'react-i18next';
14
- import { spacesSchema } from './schemas/spacesSchema';
15
- import { LLMServiceSelect } from './components/LLMServiceSelect';
16
- import { ModelSelect } from './components/ModelSelect';
17
- import { StatusTag } from './components/StatusTag';
18
- import { BuildButton } from './components/BuildButton';
19
-
20
- export const UserGuideManager = () => {
21
- const { t } = useTranslation();
22
-
23
- const useCreateFormProps = () => {
24
- const form = useMemo(() => createForm(), []);
25
- return { form };
26
- };
27
-
28
- const useEditFormProps = () => {
29
- const record = useCollectionRecordData();
30
- const form = useMemo(() => createForm({ initialValues: record }), [record]);
31
- return { form };
32
- };
33
-
34
- const useCancelActionProps = () => {
35
- const { setVisible } = useActionContext();
36
- return {
37
- type: 'default',
38
- onClick() {
39
- setVisible(false);
40
- },
41
- };
42
- };
43
-
44
- const useCreateActionProps = () => {
45
- const { setVisible } = useActionContext();
46
- const { message } = App.useApp();
47
- const resource = useDataBlockResource();
48
- const { refresh } = useDataBlockRequest();
49
-
50
- return {
51
- type: 'primary',
52
- async onClick() {
53
- const form = (this as any).form;
54
- await form.submit();
55
- await resource.create({ values: form.values });
56
- refresh();
57
- message.success(t('Saved successfully'));
58
- setVisible(false);
59
- },
60
- };
61
- };
62
-
63
- const useUpdateActionProps = () => {
64
- const { setVisible } = useActionContext();
65
- const { message } = App.useApp();
66
- const resource = useDataBlockResource();
67
- const { refresh } = useDataBlockRequest();
68
- const record = useCollectionRecordData();
69
-
70
- return {
71
- type: 'primary',
72
- async onClick() {
73
- const form = (this as any).form;
74
- await form.submit();
75
- await resource.update({
76
- filterByTk: record.id,
77
- values: form.values,
78
- });
79
- refresh();
80
- message.success(t('Saved successfully'));
81
- setVisible(false);
82
- },
83
- };
84
- };
85
-
86
- return (
87
- <SchemaComponent
88
- schema={spacesSchema}
89
- components={{
90
- LLMServiceSelect,
91
- ModelSelect,
92
- StatusTag,
93
- BuildButton,
94
- }}
95
- scope={{
96
- t,
97
- useCreateFormProps,
98
- useEditFormProps,
99
- useCancelActionProps,
100
- useCreateActionProps,
101
- useUpdateActionProps,
102
- useDestroyActionProps,
103
- useTableBlockProps,
104
- }}
105
- />
106
- );
107
- };
1
+ import React, { useMemo } from 'react';
2
+ import {
3
+ SchemaComponent,
4
+ useActionContext,
5
+ useCollectionRecordData,
6
+ useDataBlockRequest,
7
+ useDataBlockResource,
8
+ useDestroyActionProps,
9
+ useTableBlockProps,
10
+ } from '@nocobase/client';
11
+ import { createForm } from '@formily/core';
12
+ import { useForm } from '@formily/react';
13
+ import { App } from 'antd';
14
+ import { useTranslation } from 'react-i18next';
15
+ import { spacesSchema } from './schemas/spacesSchema';
16
+ import { LLMServiceSelect } from './components/LLMServiceSelect';
17
+ import { ModelSelect } from './components/ModelSelect';
18
+ import { StatusTag } from './components/StatusTag';
19
+ import { BuildButton } from './components/BuildButton';
20
+
21
+ export const UserGuideManager = () => {
22
+ const { t } = useTranslation();
23
+
24
+ const useCreateFormProps = () => {
25
+ const form = useMemo(() => createForm(), []);
26
+ return { form };
27
+ };
28
+
29
+ const useEditFormProps = () => {
30
+ const record = useCollectionRecordData();
31
+ const form = useMemo(() => createForm({ initialValues: record }), [record]);
32
+ return { form };
33
+ };
34
+
35
+ const useCancelActionProps = () => {
36
+ const { setVisible } = useActionContext();
37
+ return {
38
+ type: 'default',
39
+ onClick() {
40
+ setVisible(false);
41
+ },
42
+ };
43
+ };
44
+
45
+ const normalizeValues = (values: any) => {
46
+ const { documents, ...rest } = values;
47
+ if (Array.isArray(documents)) {
48
+ rest.documents = documents.map((doc: any) => (typeof doc === 'object' && doc?.id ? { id: doc.id } : doc));
49
+ }
50
+ return rest;
51
+ };
52
+
53
+ const useCreateActionProps = () => {
54
+ const { setVisible } = useActionContext();
55
+ const { message } = App.useApp();
56
+ const resource = useDataBlockResource();
57
+ const { refresh } = useDataBlockRequest();
58
+ const form = useForm();
59
+
60
+ return {
61
+ type: 'primary',
62
+ async onClick() {
63
+ try {
64
+ await form.submit();
65
+ await resource.create({ values: normalizeValues(form.values) });
66
+ refresh();
67
+ message.success(t('Saved successfully'));
68
+ setVisible(false);
69
+ } catch (err: any) {
70
+ if (err?.name !== 'ValidateError') {
71
+ message.error(err?.message || t('Save failed'));
72
+ }
73
+ }
74
+ },
75
+ };
76
+ };
77
+
78
+ const useUpdateActionProps = () => {
79
+ const { setVisible } = useActionContext();
80
+ const { message } = App.useApp();
81
+ const resource = useDataBlockResource();
82
+ const { refresh } = useDataBlockRequest();
83
+ const record = useCollectionRecordData();
84
+ const form = useForm();
85
+
86
+ return {
87
+ type: 'primary',
88
+ async onClick() {
89
+ try {
90
+ await form.submit();
91
+ await resource.update({
92
+ filterByTk: record.id,
93
+ values: normalizeValues(form.values),
94
+ });
95
+ refresh();
96
+ message.success(t('Saved successfully'));
97
+ setVisible(false);
98
+ } catch (err: any) {
99
+ if (err?.name !== 'ValidateError') {
100
+ message.error(err?.message || t('Save failed'));
101
+ }
102
+ }
103
+ },
104
+ };
105
+ };
106
+
107
+ return (
108
+ <SchemaComponent
109
+ schema={spacesSchema}
110
+ components={{
111
+ LLMServiceSelect,
112
+ ModelSelect,
113
+ StatusTag,
114
+ BuildButton,
115
+ }}
116
+ scope={{
117
+ t,
118
+ useCreateFormProps,
119
+ useEditFormProps,
120
+ useCancelActionProps,
121
+ useCreateActionProps,
122
+ useUpdateActionProps,
123
+ useDestroyActionProps,
124
+ useTableBlockProps,
125
+ }}
126
+ />
127
+ );
128
+ };