plugin-build-ui-template 1.0.1
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.
- package/client-v2.d.ts +2 -0
- package/client-v2.js +1 -0
- package/client.d.ts +2 -0
- package/client.js +1 -0
- package/dist/client/index.js +10 -0
- package/dist/client-v2/380.b4d1d20b1e27ac78.js +10 -0
- package/dist/client-v2/index.js +10 -0
- package/dist/externalVersion.js +22 -0
- package/dist/index.js +48 -0
- package/dist/server/actions/build.js +422 -0
- package/dist/server/collections/ai-build-ui-template-spaces.js +114 -0
- package/dist/server/index.js +48 -0
- package/dist/server/plugin.js +128 -0
- package/package.json +48 -0
- package/server.d.ts +2 -0
- package/server.js +1 -0
- package/src/client/BuildUITemplateManager.tsx +450 -0
- package/src/client/index.tsx +2 -0
- package/src/client/plugin.tsx +15 -0
- package/src/client-v2/index.tsx +1 -0
- package/src/client-v2/plugin.tsx +24 -0
- package/src/index.ts +2 -0
- package/src/server/actions/build.ts +454 -0
- package/src/server/collections/ai-build-ui-template-spaces.ts +83 -0
- package/src/server/index.ts +2 -0
- package/src/server/plugin.ts +125 -0
package/client-v2.d.ts
ADDED
package/client-v2.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
module.exports = require('./dist/client-v2/index.js');
|
package/client.d.ts
ADDED
package/client.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
module.exports = require('./dist/client/index.js');
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This file is part of the NocoBase (R) project.
|
|
3
|
+
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
|
|
4
|
+
* Authors: NocoBase Team.
|
|
5
|
+
*
|
|
6
|
+
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
|
|
7
|
+
* For more information, please refer to: https://www.nocobase.com/agreement.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t(require("react"),require("antd"),require("@nocobase/client"),require("@ant-design/icons")):"function"==typeof define&&define.amd?define("plugin-build-ui-template",["react","antd","@nocobase/client","@ant-design/icons"],t):"object"==typeof exports?exports["plugin-build-ui-template"]=t(require("react"),require("antd"),require("@nocobase/client"),require("@ant-design/icons")):e["plugin-build-ui-template"]=t(e.react,e.antd,e["@nocobase/client"],e["@ant-design/icons"])}(self,function(e,t,r,n){return function(){"use strict";var a={375:function(e){e.exports=n},342:function(e){e.exports=r},59:function(e){e.exports=t},155:function(t){t.exports=e}},o={};function l(e){var t=o[e];if(void 0!==t)return t.exports;var r=o[e]={exports:{}};return a[e](r,r.exports,l),r.exports}l.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return l.d(t,{a:t}),t},l.d=function(e,t){for(var r in t)l.o(t,r)&&!l.o(e,r)&&Object.defineProperty(e,r,{enumerable:!0,get:t[r]})},l.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||Function("return this")()}catch(e){if("object"==typeof window)return window}}(),l.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},l.r=function(e){"u">typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},l.g.importScripts&&(i=l.g.location+"");var i,c=l.g.document;if(!i&&c&&(c.currentScript&&"SCRIPT"===c.currentScript.tagName.toUpperCase()&&(i=c.currentScript.src),!i)){var u=c.getElementsByTagName("script");if(u.length)for(var s=u.length-1;s>-1&&(!i||!/^http(s?):/.test(i));)i=u[s--].src}if(!i)throw Error("Automatic publicPath is not supported in this browser");l.p=i.replace(/^blob:/,"").replace(/#.*$/,"").replace(/\?.*$/,"").replace(/\/[^\/]+$/,"/");var p={};return!function(){var e="",t="u">typeof document?document.currentScript:null;if(t&&t.src&&(e=t.src.replace(/^blob:/,"").replace(/#.*$/,"").replace(/\?.*$/,"").replace(/\/[^\/]+$/,"/")),!e){var r=window.__webpack_public_path__||"";r&&("/"!==r.charAt(r.length-1)&&(r+="/"),e=r+"static/plugins/plugin-build-ui-template/dist/client/")}if(!e){var n=window.__nocobase_modern_client_prefix__||"v",a="/"+(n=String(n).replace(/^\/+|\/+$/g,"")||"v")+"/";if(!(e=window.__nocobase_public_path__||"")&&window.location&&window.location.pathname){var o=window.location.pathname||"/",i=o.indexOf(a);e=i>=0?o.slice(0,i+1):"/"}e&&(e=e.replace(RegExp("/"+n+"/?$"),"/")),e||(e="/"),"/"!==e.charAt(e.length-1)&&(e+="/"),e+="static/plugins/plugin-build-ui-template/dist/client/"}l.p=e}(),!function(){l.r(p),l.d(p,{PluginBuildUITemplateClient:function(){return w},default:function(){return x}});var e=l(342),t=l(155),r=l.n(t),n=l(59),a=l(375);function o(e,t){(null==t||t>e.length)&&(t=e.length);for(var r=0,n=Array(t);r<t;r++)n[r]=e[r];return n}function i(e,t,r,n,a,o,l){try{var i=e[o](l),c=i.value}catch(e){r(e);return}i.done?t(c):Promise.resolve(c).then(n,a)}function c(e){return function(){var t=this,r=arguments;return new Promise(function(n,a){var o=e.apply(t,r);function l(e){i(o,n,a,l,c,"next",e)}function c(e){i(o,n,a,l,c,"throw",e)}l(void 0)})}}function u(e,t){return function(e){if(Array.isArray(e))return e}(e)||function(e,t){var r,n,a=null==e?null:"u">typeof Symbol&&e[Symbol.iterator]||e["@@iterator"];if(null!=a){var o=[],l=!0,i=!1;try{for(a=a.call(e);!(l=(r=a.next()).done)&&(o.push(r.value),!t||o.length!==t);l=!0);}catch(e){i=!0,n=e}finally{try{l||null==a.return||a.return()}finally{if(i)throw n}}return o}}(e,t)||function(e,t){if(e){if("string"==typeof e)return o(e,t);var r=Object.prototype.toString.call(e).slice(8,-1);if("Object"===r&&e.constructor&&(r=e.constructor.name),"Map"===r||"Set"===r)return Array.from(r);if("Arguments"===r||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(r))return o(e,t)}}(e,t)||function(){throw TypeError("Invalid attempt to destructure non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function s(e,t){var r,n,a,o={label:0,sent:function(){if(1&a[0])throw a[1];return a[1]},trys:[],ops:[]},l=Object.create(("function"==typeof Iterator?Iterator:Object).prototype),i=Object.defineProperty;return i(l,"next",{value:c(0)}),i(l,"throw",{value:c(1)}),i(l,"return",{value:c(2)}),"function"==typeof Symbol&&i(l,Symbol.iterator,{value:function(){return this}}),l;function c(i){return function(c){var u=[i,c];if(r)throw TypeError("Generator is already executing.");for(;l&&(l=0,u[0]&&(o=0)),o;)try{if(r=1,n&&(a=2&u[0]?n.return:u[0]?n.throw||((a=n.return)&&a.call(n),0):n.next)&&!(a=a.call(n,u[1])).done)return a;switch(n=0,a&&(u=[2&u[0],a.value]),u[0]){case 0:case 1:a=u;break;case 4:return o.label++,{value:u[1],done:!1};case 5:o.label++,n=u[1],u=[0];continue;case 7:u=o.ops.pop(),o.trys.pop();continue;default:if(!(a=(a=o.trys).length>0&&a[a.length-1])&&(6===u[0]||2===u[0])){o=0;continue}if(3===u[0]&&(!a||u[1]>a[0]&&u[1]<a[3])){o.label=u[1];break}if(6===u[0]&&o.label<a[1]){o.label=a[1],a=u;break}if(a&&o.label<a[2]){o.label=a[2],o.ops.push(u);break}a[2]&&o.ops.pop(),o.trys.pop();continue}u=t.call(e,o)}catch(e){u=[6,e],n=0}finally{r=a=0}if(5&u[0])throw u[1];return{value:u[0]?u[1]:void 0,done:!0}}}}var d=n.Typography.Title,m=n.Typography.Paragraph,f=n.Typography.Text,y=function(){var o=(0,e.useAPIClient)(),l=u((0,t.useState)([]),2),i=l[0],p=l[1],y=u((0,t.useState)([]),2),g=y[0],b=y[1],h=u((0,t.useState)([]),2),v=h[0],E=h[1],S=u((0,t.useState)([]),2),w=S[0],x=S[1],T=u((0,t.useState)(!1),2),k=T[0],O=T[1],I=u((0,t.useState)(!1),2),P=I[0],C=I[1],B=u((0,t.useState)(null),2),F=B[0],_=B[1],j=u(n.Form.useForm(),1)[0],A=n.Form.useWatch("llmService",j),L=function(){return c(function(){var e,t;return s(this,function(r){switch(r.label){case 0:O(!0),r.label=1;case 1:return r.trys.push([1,3,4,5]),[4,o.resource("aiBuildUiTemplateSpaces").list({sort:["-createdAt"]})];case 2:return p((null==(t=r.sent())||null==(e=t.data)?void 0:e.data)||[]),[3,5];case 3:return console.error("Failed to load spaces:",r.sent()),n.message.error("Failed to load UI generation spaces"),[3,5];case 4:return O(!1),[7];case 5:return[2]}})})()};(0,t.useEffect)(function(){A?o.resource("ai").listModels({llmService:A}).then(function(e){var t;x((null==e||null==(t=e.data)?void 0:t.data)||[])}).catch(function(e){console.error("Failed to load models:",e)}):x([])},[A,o]),(0,t.useEffect)(function(){L(),c(function(){var e,t;return s(this,function(r){switch(r.label){case 0:return r.trys.push([0,2,,3]),[4,o.resource("collections").list()];case 1:return b((null==(t=r.sent())||null==(e=t.data)?void 0:e.data)||[]),[3,3];case 2:return console.error("Failed to load collections:",r.sent()),[3,3];case 3:return[2]}})})(),c(function(){var e,t;return s(this,function(r){switch(r.label){case 0:return r.trys.push([0,2,,3]),[4,o.resource("ai").listLLMServices()];case 1:return E((null==(t=r.sent())||null==(e=t.data)?void 0:e.data)||[]),[3,3];case 2:return console.error("Failed to load LLM services:",r.sent()),[3,3];case 3:return[2]}})})();var e=setInterval(function(){i.some(function(e){return"building"===e.status})&&o.resource("aiBuildUiTemplateSpaces").list({sort:["-createdAt"]}).then(function(e){var t;return p((null==e||null==(t=e.data)?void 0:t.data)||[])}).catch(function(){})},3e3);return function(){return clearInterval(e)}},[i]);var q=function(e){e?(_(e),j.setFieldsValue({title:e.title,llmService:e.llmService,model:e.model,systemPrompt:e.systemPrompt,promptRequirements:e.promptRequirements,type:e.type,targetCollection:e.targetCollection})):(_(null),j.resetFields(),j.setFieldsValue({type:"block"})),C(!0)},M=function(e){switch(e){case"queued":return 10;case"preparing":return 25;case"generating":return 60;case"saving":return 90;case"completed":return 100;default:return 0}};return r().createElement("div",{style:{padding:"24px",maxWidth:"1200px",margin:"0 auto"}},r().createElement("div",{style:{display:"flex",justifyContent:"space-between",alignItems:"center",marginBottom:"24px"}},r().createElement("div",null,r().createElement(d,{level:2},"AI UI Template Builder"),r().createElement(m,{type:"secondary"},"Generate stunning custom UI Blocks and Popups in seconds using state-of-the-art LLMs, then reuse them in NocoBase v2 dynamic forms, dashboards and listings.")),r().createElement(n.Button,{type:"primary",icon:r().createElement(a.PlusOutlined,null),onClick:function(){return q()}},"New Generation Space")),r().createElement(n.List,{loading:k&&0===i.length,dataSource:i,renderItem:function(e){var t,l;return r().createElement(n.Card,{key:e.id,style:{marginBottom:"20px",borderRadius:"12px",boxShadow:"0 4px 12px rgba(0,0,0,0.05)"},actions:[r().createElement(n.Button,{key:"generate",type:"link",icon:r().createElement(a.PlayCircleOutlined,null),onClick:function(){var t;return t=e.id,c(function(){var e;return s(this,function(r){switch(r.label){case 0:return r.trys.push([0,2,,3]),n.message.loading("Triggering AI generation...",1),[4,o.resource("aiBuildUiTemplateSpaces").build({filterByTk:t})];case 1:return r.sent(),n.message.success("UI Template generation task started successfully!"),L(),[3,3];case 2:return e=r.sent(),n.message.error((null==e?void 0:e.message)||"Failed to trigger build"),[3,3];case 3:return[2]}})})()},disabled:"building"===e.status},"Generate"),r().createElement(n.Button,{key:"edit",type:"link",onClick:function(){return q(e)}},"Edit Settings"),r().createElement(n.Button,{key:"delete",type:"link",danger:!0,icon:r().createElement(a.DeleteOutlined,null),onClick:function(){var t;return t=e.id,c(function(){return s(this,function(e){return n.Modal.confirm({title:"Are you sure to delete this generation space?",icon:r().createElement(a.ExclamationCircleOutlined,null),okType:"danger",onOk:function(){return c(function(){return s(this,function(e){switch(e.label){case 0:return e.trys.push([0,2,,3]),[4,o.resource("aiBuildUiTemplateSpaces").destroy({filterByTk:t})];case 1:return e.sent(),n.message.success("Space deleted"),L(),[3,3];case 2:return e.sent(),n.message.error("Failed to delete space"),[3,3];case 3:return[2]}})})()}}),[2]})})()}},"Delete")]},r().createElement("div",{style:{display:"flex",justifyContent:"space-between",alignItems:"start",marginBottom:"16px"}},r().createElement("div",null,r().createElement(n.Space,{align:"baseline"},r().createElement(d,{level:4,style:{margin:0}},e.title),(t=e.status,l=e.buildPhase,"completed"===t?r().createElement(n.Tag,{color:"success",icon:r().createElement(a.CheckCircleOutlined,null)},"Completed"):"error"===t?r().createElement(n.Tag,{color:"error",icon:r().createElement(a.ExclamationCircleOutlined,null)},"Failed"):"building"===t?r().createElement(n.Tag,{color:"processing",icon:r().createElement(a.SyncOutlined,{spin:!0})},"Generating (",l||"queued",")"):r().createElement(n.Tag,{color:"default"},"Draft"))),r().createElement("div",{style:{marginTop:"8px"}},r().createElement(n.Tag,{color:"blue"},"popup"===e.type?"Popup Template":"Block Template"),e.targetCollection&&r().createElement(n.Tag,{color:"purple"},"Collection: ",e.targetCollection),r().createElement(n.Tag,{color:"cyan"},"LLM: ",e.llmService," (",e.model,")"))),e.templateUid&&r().createElement(n.Button,{type:"primary",ghost:!0,icon:r().createElement(a.ArrowRightOutlined,null),href:"/admin/settings/ui-templates.block"},"View Template Library")),r().createElement(m,{style:{background:"#f5f5f5",padding:"12px",borderRadius:"8px",borderLeft:"4px solid #1890ff"}},r().createElement(f,{strong:!0},"User Requirements: "),e.promptRequirements||"No specific requirements typed."),"building"===e.status&&r().createElement("div",{style:{marginTop:"16px",background:"#fafafa",padding:"16px",borderRadius:"8px"}},r().createElement(f,{type:"secondary"},"Build progress: "),r().createElement(n.Progress,{percent:M(e.buildPhase),status:"active",strokeColor:"#1890ff"}),r().createElement("div",{style:{marginTop:"8px",fontFamily:"monospace",color:"#666"}},r().createElement(n.Spin,{size:"small",style:{marginRight:"8px"}}),e.buildLog||"AI is initiating task...")),"completed"===e.status&&e.buildLog&&r().createElement(n.Alert,{message:"Build Complete",description:e.buildLog,type:"success",showIcon:!0,style:{marginTop:"12px"}}),"error"===e.status&&e.buildLog&&r().createElement(n.Alert,{message:"Generation Failed",description:e.buildLog,type:"error",showIcon:!0,style:{marginTop:"12px"}}))}}),r().createElement(n.Modal,{title:F?"Edit Generation Settings":"New UI Generation Space",open:P,onOk:function(){return c(function(){var e,t;return s(this,function(r){switch(r.label){case 0:return r.trys.push([0,6,,7]),[4,j.validateFields()];case 1:if(e=r.sent(),!F)return[3,3];return[4,o.resource("aiBuildUiTemplateSpaces").update({filterByTk:F.id,values:e})];case 2:return r.sent(),n.message.success("Space updated successfully"),[3,5];case 3:return[4,o.resource("aiBuildUiTemplateSpaces").create({values:e})];case 4:r.sent(),n.message.success("Space created successfully"),r.label=5;case 5:return C(!1),L(),[3,7];case 6:return(null==(t=r.sent())?void 0:t.name)!=="ValidateError"&&n.message.error((null==t?void 0:t.message)||"Failed to save space settings"),[3,7];case 7:return[2]}})})()},onCancel:function(){return C(!1)},width:720,destroyOnClose:!0},r().createElement(n.Form,{form:j,layout:"vertical",style:{marginTop:"16px"}},r().createElement(n.Form.Item,{name:"title",label:r().createElement(f,{strong:!0},"Space Name"),rules:[{required:!0,message:"Please enter a space name"}]},r().createElement(n.Input,{placeholder:"e.g. Sales KPI Dashboard, Customer Contact Form"})),r().createElement(n.Space,{size:"large",style:{display:"flex",width:"100%"}},r().createElement(n.Form.Item,{name:"llmService",label:r().createElement(f,{strong:!0},"AI Service"),rules:[{required:!0,message:"Please select an LLM Service"}],style:{flex:1,minWidth:"300px"}},r().createElement(n.Select,{placeholder:"Select Service",onChange:function(){return j.setFieldValue("model",void 0)}},v.map(function(e){return r().createElement(n.Select.Option,{key:e.name,value:e.name},e.title||e.name)}))),r().createElement(n.Form.Item,{name:"model",label:r().createElement(f,{strong:!0},"Model"),rules:[{required:!0,message:"Please select an LLM Model"}],style:{flex:1,minWidth:"300px"}},r().createElement(n.Select,{placeholder:"Select Model",disabled:!A},w.map(function(e){return r().createElement(n.Select.Option,{key:e.id||e.name,value:e.id||e.name},e.id||e.name)})))),r().createElement(n.Space,{size:"large",style:{display:"flex",width:"100%"}},r().createElement(n.Form.Item,{name:"type",label:r().createElement(f,{strong:!0},"Template Type"),rules:[{required:!0}],style:{flex:1}},r().createElement(n.Radio.Group,null,r().createElement(n.Radio.Button,{value:"block"},"Block (V2)"),r().createElement(n.Radio.Button,{value:"popup"},"Popup (V2)"))),r().createElement(n.Form.Item,{name:"targetCollection",label:r().createElement(f,{strong:!0},"Bind Database Collection"),style:{flex:1,minWidth:"300px"}},r().createElement(n.Select,{placeholder:"Select target collection (optional)",allowClear:!0,showSearch:!0},g.map(function(e){return r().createElement(n.Select.Option,{key:e.name,value:e.name},e.title||e.name)})))),r().createElement(n.Form.Item,{name:"promptRequirements",label:r().createElement(f,{strong:!0},"UI Requirements & Features Description"),rules:[{required:!0,message:"Please describe the layout you need AI to generate"}]},r().createElement(n.Input.TextArea,{rows:4,placeholder:"e.g. Build a comprehensive customer feedback form featuring inputs for name, email, rating slider, multi-line comment text area, and an agreement checkbox. Place them in a nice 2-column grid."})),r().createElement(n.Form.Item,{name:"systemPrompt",label:r().createElement(f,{strong:!0},"Advanced System Prompt Override (Optional)")},r().createElement(n.Input.TextArea,{rows:3,placeholder:"Override the default system prompt to customize how the LLM structures the component trees."})))))};function g(e,t,r,n,a,o,l){try{var i=e[o](l),c=i.value}catch(e){r(e);return}i.done?t(c):Promise.resolve(c).then(n,a)}function b(e,t,r){return(b=S()?Reflect.construct:function(e,t,r){var n=[null];n.push.apply(n,t);var a=new(Function.bind.apply(e,n));return r&&v(a,r.prototype),a}).apply(null,arguments)}function h(e){return(h=Object.setPrototypeOf?Object.getPrototypeOf:function(e){return e.__proto__||Object.getPrototypeOf(e)})(e)}function v(e,t){return(v=Object.setPrototypeOf||function(e,t){return e.__proto__=t,e})(e,t)}function E(e){var t="function"==typeof Map?new Map:void 0;return(E=function(e){if(null===e||-1===Function.toString.call(e).indexOf("[native code]"))return e;if("function"!=typeof e)throw TypeError("Super expression must either be null or a function");if(void 0!==t){if(t.has(e))return t.get(e);t.set(e,r)}function r(){return b(e,arguments,h(this).constructor)}return r.prototype=Object.create(e.prototype,{constructor:{value:r,enumerable:!1,writable:!0,configurable:!0}}),v(r,e)})(e)}function S(){try{var e=!Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],function(){}))}catch(e){}return(S=function(){return!!e})()}var w=function(e){var t;if("function"!=typeof e&&null!==e)throw TypeError("Super expression must either be null or a function");function r(){var e,t;if(!(this instanceof r))throw TypeError("Cannot call a class as a function");return e=r,t=arguments,e=h(e),function(e,t){var r;if(t&&("object"==((r=t)&&"u">typeof Symbol&&r.constructor===Symbol?"symbol":typeof r)||"function"==typeof t))return t;if(void 0===e)throw ReferenceError("this hasn't been initialised - super() hasn't been called");return e}(this,S()?Reflect.construct(e,t||[],h(this).constructor):e.apply(this,t))}return r.prototype=Object.create(e&&e.prototype,{constructor:{value:r,writable:!0,configurable:!0}}),e&&v(r,e),t=[{key:"load",value:function(){var e;return(e=function(){return function(e,t){var r,n,a,o={label:0,sent:function(){if(1&a[0])throw a[1];return a[1]},trys:[],ops:[]},l=Object.create(("function"==typeof Iterator?Iterator:Object).prototype),i=Object.defineProperty;return i(l,"next",{value:c(0)}),i(l,"throw",{value:c(1)}),i(l,"return",{value:c(2)}),"function"==typeof Symbol&&i(l,Symbol.iterator,{value:function(){return this}}),l;function c(i){return function(c){var u=[i,c];if(r)throw TypeError("Generator is already executing.");for(;l&&(l=0,u[0]&&(o=0)),o;)try{if(r=1,n&&(a=2&u[0]?n.return:u[0]?n.throw||((a=n.return)&&a.call(n),0):n.next)&&!(a=a.call(n,u[1])).done)return a;switch(n=0,a&&(u=[2&u[0],a.value]),u[0]){case 0:case 1:a=u;break;case 4:return o.label++,{value:u[1],done:!1};case 5:o.label++,n=u[1],u=[0];continue;case 7:u=o.ops.pop(),o.trys.pop();continue;default:if(!(a=(a=o.trys).length>0&&a[a.length-1])&&(6===u[0]||2===u[0])){o=0;continue}if(3===u[0]&&(!a||u[1]>a[0]&&u[1]<a[3])){o.label=u[1];break}if(6===u[0]&&o.label<a[1]){o.label=a[1],a=u;break}if(a&&o.label<a[2]){o.label=a[2],o.ops.push(u);break}a[2]&&o.ops.pop(),o.trys.pop();continue}u=t.call(e,o)}catch(e){u=[6,e],n=0}finally{r=a=0}if(5&u[0])throw u[1];return{value:u[0]?u[1]:void 0,done:!0}}}}(this,function(e){return this.app.pluginSettingsManager.add("ai-build-ui-template",{icon:"LayoutOutlined",title:"Build UI Template",Component:y,aclSnippet:"pm.ai-build-ui-template"}),[2]})},function(){var t=this,r=arguments;return new Promise(function(n,a){var o=e.apply(t,r);function l(e){g(o,n,a,l,i,"next",e)}function i(e){g(o,n,a,l,i,"throw",e)}l(void 0)})}).call(this)}}],function(e,t){for(var r=0;r<t.length;r++){var n=t[r];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(e,n.key,n)}}(r.prototype,t),r}(E(e.Plugin)),x=w}(),p}()});
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This file is part of the NocoBase (R) project.
|
|
3
|
+
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
|
|
4
|
+
* Authors: NocoBase Team.
|
|
5
|
+
*
|
|
6
|
+
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
|
|
7
|
+
* For more information, please refer to: https://www.nocobase.com/agreement.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
"use strict";(self.webpackChunkplugin_build_ui_template_client_v2=self.webpackChunkplugin_build_ui_template_client_v2||[]).push([["380"],{23:function(e,t,r){r.d(t,{BuildUITemplateManager:function(){return y}});var n=r(155),a=r.n(n),l=r(342),i=r(59),o=r(375);function s(e,t){(null==t||t>e.length)&&(t=e.length);for(var r=0,n=Array(t);r<t;r++)n[r]=e[r];return n}function c(e,t,r,n,a,l,i){try{var o=e[l](i),s=o.value}catch(e){r(e);return}o.done?t(s):Promise.resolve(s).then(n,a)}function u(e){return function(){var t=this,r=arguments;return new Promise(function(n,a){var l=e.apply(t,r);function i(e){c(l,n,a,i,o,"next",e)}function o(e){c(l,n,a,i,o,"throw",e)}i(void 0)})}}function m(e,t){return function(e){if(Array.isArray(e))return e}(e)||function(e,t){var r,n,a=null==e?null:"u">typeof Symbol&&e[Symbol.iterator]||e["@@iterator"];if(null!=a){var l=[],i=!0,o=!1;try{for(a=a.call(e);!(i=(r=a.next()).done)&&(l.push(r.value),!t||l.length!==t);i=!0);}catch(e){o=!0,n=e}finally{try{i||null==a.return||a.return()}finally{if(o)throw n}}return l}}(e,t)||function(e,t){if(e){if("string"==typeof e)return s(e,t);var r=Object.prototype.toString.call(e).slice(8,-1);if("Object"===r&&e.constructor&&(r=e.constructor.name),"Map"===r||"Set"===r)return Array.from(r);if("Arguments"===r||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(r))return s(e,t)}}(e,t)||function(){throw TypeError("Invalid attempt to destructure non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function d(e,t){var r,n,a,l={label:0,sent:function(){if(1&a[0])throw a[1];return a[1]},trys:[],ops:[]},i=Object.create(("function"==typeof Iterator?Iterator:Object).prototype),o=Object.defineProperty;return o(i,"next",{value:s(0)}),o(i,"throw",{value:s(1)}),o(i,"return",{value:s(2)}),"function"==typeof Symbol&&o(i,Symbol.iterator,{value:function(){return this}}),i;function s(o){return function(s){var c=[o,s];if(r)throw TypeError("Generator is already executing.");for(;i&&(i=0,c[0]&&(l=0)),l;)try{if(r=1,n&&(a=2&c[0]?n.return:c[0]?n.throw||((a=n.return)&&a.call(n),0):n.next)&&!(a=a.call(n,c[1])).done)return a;switch(n=0,a&&(c=[2&c[0],a.value]),c[0]){case 0:case 1:a=c;break;case 4:return l.label++,{value:c[1],done:!1};case 5:l.label++,n=c[1],c=[0];continue;case 7:c=l.ops.pop(),l.trys.pop();continue;default:if(!(a=(a=l.trys).length>0&&a[a.length-1])&&(6===c[0]||2===c[0])){l=0;continue}if(3===c[0]&&(!a||c[1]>a[0]&&c[1]<a[3])){l.label=c[1];break}if(6===c[0]&&l.label<a[1]){l.label=a[1],a=c;break}if(a&&l.label<a[2]){l.label=a[2],l.ops.push(c);break}a[2]&&l.ops.pop(),l.trys.pop();continue}c=t.call(e,l)}catch(e){c=[6,e],n=0}finally{r=a=0}if(5&c[0])throw c[1];return{value:c[0]?c[1]:void 0,done:!0}}}}var p=i.Typography.Title,f=i.Typography.Paragraph,g=i.Typography.Text,y=function(){var e=(0,l.useAPIClient)(),t=m((0,n.useState)([]),2),r=t[0],s=t[1],c=m((0,n.useState)([]),2),y=c[0],h=c[1],v=m((0,n.useState)([]),2),b=v[0],E=v[1],S=m((0,n.useState)([]),2),x=S[0],k=S[1],T=m((0,n.useState)(!1),2),w=T[0],I=T[1],C=m((0,n.useState)(!1),2),B=C[0],F=C[1],P=m((0,n.useState)(null),2),L=P[0],O=P[1],A=m(i.Form.useForm(),1)[0],U=i.Form.useWatch("llmService",A),M=function(){return u(function(){var t,r;return d(this,function(n){switch(n.label){case 0:I(!0),n.label=1;case 1:return n.trys.push([1,3,4,5]),[4,e.resource("aiBuildUiTemplateSpaces").list({sort:["-createdAt"]})];case 2:return s((null==(r=n.sent())||null==(t=r.data)?void 0:t.data)||[]),[3,5];case 3:return console.error("Failed to load spaces:",n.sent()),i.message.error("Failed to load UI generation spaces"),[3,5];case 4:return I(!1),[7];case 5:return[2]}})})()};(0,n.useEffect)(function(){U?e.resource("ai").listModels({llmService:U}).then(function(e){var t;k((null==e||null==(t=e.data)?void 0:t.data)||[])}).catch(function(e){console.error("Failed to load models:",e)}):k([])},[U,e]),(0,n.useEffect)(function(){M(),u(function(){var t,r;return d(this,function(n){switch(n.label){case 0:return n.trys.push([0,2,,3]),[4,e.resource("collections").list()];case 1:return h((null==(r=n.sent())||null==(t=r.data)?void 0:t.data)||[]),[3,3];case 2:return console.error("Failed to load collections:",n.sent()),[3,3];case 3:return[2]}})})(),u(function(){var t,r;return d(this,function(n){switch(n.label){case 0:return n.trys.push([0,2,,3]),[4,e.resource("ai").listLLMServices()];case 1:return E((null==(r=n.sent())||null==(t=r.data)?void 0:t.data)||[]),[3,3];case 2:return console.error("Failed to load LLM services:",n.sent()),[3,3];case 3:return[2]}})})();var t=setInterval(function(){r.some(function(e){return"building"===e.status})&&e.resource("aiBuildUiTemplateSpaces").list({sort:["-createdAt"]}).then(function(e){var t;return s((null==e||null==(t=e.data)?void 0:t.data)||[])}).catch(function(){})},3e3);return function(){return clearInterval(t)}},[r]);var q=function(e){e?(O(e),A.setFieldsValue({title:e.title,llmService:e.llmService,model:e.model,systemPrompt:e.systemPrompt,promptRequirements:e.promptRequirements,type:e.type,targetCollection:e.targetCollection})):(O(null),A.resetFields(),A.setFieldsValue({type:"block"})),F(!0)},R=function(e){switch(e){case"queued":return 10;case"preparing":return 25;case"generating":return 60;case"saving":return 90;case"completed":return 100;default:return 0}};return a().createElement("div",{style:{padding:"24px",maxWidth:"1200px",margin:"0 auto"}},a().createElement("div",{style:{display:"flex",justifyContent:"space-between",alignItems:"center",marginBottom:"24px"}},a().createElement("div",null,a().createElement(p,{level:2},"AI UI Template Builder"),a().createElement(f,{type:"secondary"},"Generate stunning custom UI Blocks and Popups in seconds using state-of-the-art LLMs, then reuse them in NocoBase v2 dynamic forms, dashboards and listings.")),a().createElement(i.Button,{type:"primary",icon:a().createElement(o.PlusOutlined,null),onClick:function(){return q()}},"New Generation Space")),a().createElement(i.List,{loading:w&&0===r.length,dataSource:r,renderItem:function(t){var r,n;return a().createElement(i.Card,{key:t.id,style:{marginBottom:"20px",borderRadius:"12px",boxShadow:"0 4px 12px rgba(0,0,0,0.05)"},actions:[a().createElement(i.Button,{key:"generate",type:"link",icon:a().createElement(o.PlayCircleOutlined,null),onClick:function(){var r;return r=t.id,u(function(){var t;return d(this,function(n){switch(n.label){case 0:return n.trys.push([0,2,,3]),i.message.loading("Triggering AI generation...",1),[4,e.resource("aiBuildUiTemplateSpaces").build({filterByTk:r})];case 1:return n.sent(),i.message.success("UI Template generation task started successfully!"),M(),[3,3];case 2:return t=n.sent(),i.message.error((null==t?void 0:t.message)||"Failed to trigger build"),[3,3];case 3:return[2]}})})()},disabled:"building"===t.status},"Generate"),a().createElement(i.Button,{key:"edit",type:"link",onClick:function(){return q(t)}},"Edit Settings"),a().createElement(i.Button,{key:"delete",type:"link",danger:!0,icon:a().createElement(o.DeleteOutlined,null),onClick:function(){var r;return r=t.id,u(function(){return d(this,function(t){return i.Modal.confirm({title:"Are you sure to delete this generation space?",icon:a().createElement(o.ExclamationCircleOutlined,null),okType:"danger",onOk:function(){return u(function(){return d(this,function(t){switch(t.label){case 0:return t.trys.push([0,2,,3]),[4,e.resource("aiBuildUiTemplateSpaces").destroy({filterByTk:r})];case 1:return t.sent(),i.message.success("Space deleted"),M(),[3,3];case 2:return t.sent(),i.message.error("Failed to delete space"),[3,3];case 3:return[2]}})})()}}),[2]})})()}},"Delete")]},a().createElement("div",{style:{display:"flex",justifyContent:"space-between",alignItems:"start",marginBottom:"16px"}},a().createElement("div",null,a().createElement(i.Space,{align:"baseline"},a().createElement(p,{level:4,style:{margin:0}},t.title),(r=t.status,n=t.buildPhase,"completed"===r?a().createElement(i.Tag,{color:"success",icon:a().createElement(o.CheckCircleOutlined,null)},"Completed"):"error"===r?a().createElement(i.Tag,{color:"error",icon:a().createElement(o.ExclamationCircleOutlined,null)},"Failed"):"building"===r?a().createElement(i.Tag,{color:"processing",icon:a().createElement(o.SyncOutlined,{spin:!0})},"Generating (",n||"queued",")"):a().createElement(i.Tag,{color:"default"},"Draft"))),a().createElement("div",{style:{marginTop:"8px"}},a().createElement(i.Tag,{color:"blue"},"popup"===t.type?"Popup Template":"Block Template"),t.targetCollection&&a().createElement(i.Tag,{color:"purple"},"Collection: ",t.targetCollection),a().createElement(i.Tag,{color:"cyan"},"LLM: ",t.llmService," (",t.model,")"))),t.templateUid&&a().createElement(i.Button,{type:"primary",ghost:!0,icon:a().createElement(o.ArrowRightOutlined,null),href:"/admin/settings/ui-templates.block"},"View Template Library")),a().createElement(f,{style:{background:"#f5f5f5",padding:"12px",borderRadius:"8px",borderLeft:"4px solid #1890ff"}},a().createElement(g,{strong:!0},"User Requirements: "),t.promptRequirements||"No specific requirements typed."),"building"===t.status&&a().createElement("div",{style:{marginTop:"16px",background:"#fafafa",padding:"16px",borderRadius:"8px"}},a().createElement(g,{type:"secondary"},"Build progress: "),a().createElement(i.Progress,{percent:R(t.buildPhase),status:"active",strokeColor:"#1890ff"}),a().createElement("div",{style:{marginTop:"8px",fontFamily:"monospace",color:"#666"}},a().createElement(i.Spin,{size:"small",style:{marginRight:"8px"}}),t.buildLog||"AI is initiating task...")),"completed"===t.status&&t.buildLog&&a().createElement(i.Alert,{message:"Build Complete",description:t.buildLog,type:"success",showIcon:!0,style:{marginTop:"12px"}}),"error"===t.status&&t.buildLog&&a().createElement(i.Alert,{message:"Generation Failed",description:t.buildLog,type:"error",showIcon:!0,style:{marginTop:"12px"}}))}}),a().createElement(i.Modal,{title:L?"Edit Generation Settings":"New UI Generation Space",open:B,onOk:function(){return u(function(){var t,r;return d(this,function(n){switch(n.label){case 0:return n.trys.push([0,6,,7]),[4,A.validateFields()];case 1:if(t=n.sent(),!L)return[3,3];return[4,e.resource("aiBuildUiTemplateSpaces").update({filterByTk:L.id,values:t})];case 2:return n.sent(),i.message.success("Space updated successfully"),[3,5];case 3:return[4,e.resource("aiBuildUiTemplateSpaces").create({values:t})];case 4:n.sent(),i.message.success("Space created successfully"),n.label=5;case 5:return F(!1),M(),[3,7];case 6:return(null==(r=n.sent())?void 0:r.name)!=="ValidateError"&&i.message.error((null==r?void 0:r.message)||"Failed to save space settings"),[3,7];case 7:return[2]}})})()},onCancel:function(){return F(!1)},width:720,destroyOnClose:!0},a().createElement(i.Form,{form:A,layout:"vertical",style:{marginTop:"16px"}},a().createElement(i.Form.Item,{name:"title",label:a().createElement(g,{strong:!0},"Space Name"),rules:[{required:!0,message:"Please enter a space name"}]},a().createElement(i.Input,{placeholder:"e.g. Sales KPI Dashboard, Customer Contact Form"})),a().createElement(i.Space,{size:"large",style:{display:"flex",width:"100%"}},a().createElement(i.Form.Item,{name:"llmService",label:a().createElement(g,{strong:!0},"AI Service"),rules:[{required:!0,message:"Please select an LLM Service"}],style:{flex:1,minWidth:"300px"}},a().createElement(i.Select,{placeholder:"Select Service",onChange:function(){return A.setFieldValue("model",void 0)}},b.map(function(e){return a().createElement(i.Select.Option,{key:e.name,value:e.name},e.title||e.name)}))),a().createElement(i.Form.Item,{name:"model",label:a().createElement(g,{strong:!0},"Model"),rules:[{required:!0,message:"Please select an LLM Model"}],style:{flex:1,minWidth:"300px"}},a().createElement(i.Select,{placeholder:"Select Model",disabled:!U},x.map(function(e){return a().createElement(i.Select.Option,{key:e.id||e.name,value:e.id||e.name},e.id||e.name)})))),a().createElement(i.Space,{size:"large",style:{display:"flex",width:"100%"}},a().createElement(i.Form.Item,{name:"type",label:a().createElement(g,{strong:!0},"Template Type"),rules:[{required:!0}],style:{flex:1}},a().createElement(i.Radio.Group,null,a().createElement(i.Radio.Button,{value:"block"},"Block (V2)"),a().createElement(i.Radio.Button,{value:"popup"},"Popup (V2)"))),a().createElement(i.Form.Item,{name:"targetCollection",label:a().createElement(g,{strong:!0},"Bind Database Collection"),style:{flex:1,minWidth:"300px"}},a().createElement(i.Select,{placeholder:"Select target collection (optional)",allowClear:!0,showSearch:!0},y.map(function(e){return a().createElement(i.Select.Option,{key:e.name,value:e.name},e.title||e.name)})))),a().createElement(i.Form.Item,{name:"promptRequirements",label:a().createElement(g,{strong:!0},"UI Requirements & Features Description"),rules:[{required:!0,message:"Please describe the layout you need AI to generate"}]},a().createElement(i.Input.TextArea,{rows:4,placeholder:"e.g. Build a comprehensive customer feedback form featuring inputs for name, email, rating slider, multi-line comment text area, and an agreement checkbox. Place them in a nice 2-column grid."})),a().createElement(i.Form.Item,{name:"systemPrompt",label:a().createElement(g,{strong:!0},"Advanced System Prompt Override (Optional)")},a().createElement(i.Input.TextArea,{rows:3,placeholder:"Override the default system prompt to customize how the LLM structures the component trees."})))))}}}]);
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This file is part of the NocoBase (R) project.
|
|
3
|
+
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
|
|
4
|
+
* Authors: NocoBase Team.
|
|
5
|
+
*
|
|
6
|
+
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
|
|
7
|
+
* For more information, please refer to: https://www.nocobase.com/agreement.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t(require("@nocobase/client-v2"),require("react"),require("antd"),require("@nocobase/client"),require("@ant-design/icons")):"function"==typeof define&&define.amd?define("plugin-build-ui-template/client-v2",["@nocobase/client-v2","react","antd","@nocobase/client","@ant-design/icons"],t):"object"==typeof exports?exports["plugin-build-ui-template/client-v2"]=t(require("@nocobase/client-v2"),require("react"),require("antd"),require("@nocobase/client"),require("@ant-design/icons")):e["plugin-build-ui-template/client-v2"]=t(e["@nocobase/client-v2"],e.react,e.antd,e["@nocobase/client"],e["@ant-design/icons"])}(self,function(e,t,n,r,o){return function(){"use strict";var i,u,c,a={375:function(e){e.exports=o},342:function(e){e.exports=r},485:function(t){t.exports=e},59:function(e){e.exports=n},155:function(e){e.exports=t}},l={};function p(e){var t=l[e];if(void 0!==t)return t.exports;var n=l[e]={exports:{}};return a[e](n,n.exports,p),n.exports}p.m=a,p.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return p.d(t,{a:t}),t},p.d=function(e,t){for(var n in t)p.o(t,n)&&!p.o(e,n)&&Object.defineProperty(e,n,{enumerable:!0,get:t[n]})},p.f={},p.e=function(e){return Promise.all(Object.keys(p.f).reduce(function(t,n){return p.f[n](e,t),t},[]))},p.u=function(e){return""+e+".b4d1d20b1e27ac78.js"},p.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||Function("return this")()}catch(e){if("object"==typeof window)return window}}(),p.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},f={},p.l=function(e,t,n,r){if(f[e])return void f[e].push(t);if(void 0!==n)for(var o,i,u=document.getElementsByTagName("script"),c=0;c<u.length;c++){var a=u[c];if(a.getAttribute("src")==e||a.getAttribute("data-rspack")=="plugin-build-ui-template/client-v2:"+n){o=a;break}}o||(i=!0,(o=document.createElement("script")).timeout=120,p.nc&&o.setAttribute("nonce",p.nc),o.setAttribute("data-rspack","plugin-build-ui-template/client-v2:"+n),o.src=e),f[e]=[t];var l=function(t,n){o.onerror=o.onload=null,clearTimeout(s);var r=f[e];if(delete f[e],o.parentNode&&o.parentNode.removeChild(o),r&&r.forEach(function(e){return e(n)}),t)return t(n)},s=setTimeout(l.bind(null,void 0,{type:"timeout",target:o}),12e4);o.onerror=l.bind(null,o.onerror),o.onload=l.bind(null,o.onload),i&&document.head.appendChild(o)},p.r=function(e){"u">typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},p.g.importScripts&&(s=p.g.location+"");var f,s,d=p.g.document;if(!s&&d&&(d.currentScript&&"SCRIPT"===d.currentScript.tagName.toUpperCase()&&(s=d.currentScript.src),!s)){var b=d.getElementsByTagName("script");if(b.length)for(var v=b.length-1;v>-1&&(!s||!/^http(s?):/.test(s));)s=b[v--].src}if(!s)throw Error("Automatic publicPath is not supported in this browser");p.p=s.replace(/^blob:/,"").replace(/#.*$/,"").replace(/\?.*$/,"").replace(/\/[^\/]+$/,"/"),i={889:0},p.f.j=function(e,t){var n=p.o(i,e)?i[e]:void 0;if(0!==n)if(n)t.push(n[2]);else{var r=new Promise(function(t,r){n=i[e]=[t,r]});t.push(n[2]=r);var o=p.p+p.u(e),u=Error();p.l(o,function(t){if(p.o(i,e)&&(0!==(n=i[e])&&(i[e]=void 0),n)){var r=t&&("load"===t.type?"missing":t.type),o=t&&t.target&&t.target.src;u.message="Loading chunk "+e+" failed.\n("+r+": "+o+")",u.name="ChunkLoadError",u.type=r,u.request=o,n[1](u)}},"chunk-"+e,e)}},u=function(e,t){var n,r,o=t[0],u=t[1],c=t[2],a=0;if(o.some(function(e){return 0!==i[e]})){for(n in u)p.o(u,n)&&(p.m[n]=u[n]);c&&c(p)}for(e&&e(t);a<o.length;a++)r=o[a],p.o(i,r)&&i[r]&&i[r][0](),i[r]=0},(c=self.webpackChunkplugin_build_ui_template_client_v2=self.webpackChunkplugin_build_ui_template_client_v2||[]).forEach(u.bind(null,0)),c.push=u.bind(null,c.push.bind(c));var h={};return!function(){var e="",t="u">typeof document?document.currentScript:null;if(t&&t.src&&(e=t.src.replace(/^blob:/,"").replace(/#.*$/,"").replace(/\?.*$/,"").replace(/\/[^\/]+$/,"/")),!e){var n=window.__webpack_public_path__||"";n&&("/"!==n.charAt(n.length-1)&&(n+="/"),e=n+"static/plugins/plugin-build-ui-template/dist/client-v2/")}if(!e){var r=window.__nocobase_modern_client_prefix__||"v",o="/"+(r=String(r).replace(/^\/+|\/+$/g,"")||"v")+"/";if(!(e=window.__nocobase_public_path__||"")&&window.location&&window.location.pathname){var i=window.location.pathname||"/",u=i.indexOf(o);e=u>=0?i.slice(0,u+1):"/"}e&&(e=e.replace(RegExp("/"+r+"/?$"),"/")),e||(e="/"),"/"!==e.charAt(e.length-1)&&(e+="/"),e+="static/plugins/plugin-build-ui-template/dist/client-v2/"}p.p=e}(),!function(){p.r(h),p.d(h,{default:function(){return c}});var e=p(485);function t(e,t,n,r,o,i,u){try{var c=e[i](u),a=c.value}catch(e){n(e);return}c.done?t(a):Promise.resolve(a).then(r,o)}function n(e,t,r){return(n=u()?Reflect.construct:function(e,t,n){var r=[null];r.push.apply(r,t);var i=new(Function.bind.apply(e,r));return n&&o(i,n.prototype),i}).apply(null,arguments)}p(155);function r(e){return(r=Object.setPrototypeOf?Object.getPrototypeOf:function(e){return e.__proto__||Object.getPrototypeOf(e)})(e)}function o(e,t){return(o=Object.setPrototypeOf||function(e,t){return e.__proto__=t,e})(e,t)}function i(e){var t="function"==typeof Map?new Map:void 0;return(i=function(e){if(null===e||-1===Function.toString.call(e).indexOf("[native code]"))return e;if("function"!=typeof e)throw TypeError("Super expression must either be null or a function");if(void 0!==t){if(t.has(e))return t.get(e);t.set(e,i)}function i(){return n(e,arguments,r(this).constructor)}return i.prototype=Object.create(e.prototype,{constructor:{value:i,enumerable:!1,writable:!0,configurable:!0}}),o(i,e)})(e)}function u(){try{var e=!Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],function(){}))}catch(e){}return(u=function(){return!!e})()}var c=function(e){var n;if("function"!=typeof e&&null!==e)throw TypeError("Super expression must either be null or a function");function i(){var e,t;if(!(this instanceof i))throw TypeError("Cannot call a class as a function");return e=i,t=arguments,e=r(e),function(e,t){var n;if(t&&("object"==((n=t)&&"u">typeof Symbol&&n.constructor===Symbol?"symbol":typeof n)||"function"==typeof t))return t;if(void 0===e)throw ReferenceError("this hasn't been initialised - super() hasn't been called");return e}(this,u()?Reflect.construct(e,t||[],r(this).constructor):e.apply(this,t))}return i.prototype=Object.create(e&&e.prototype,{constructor:{value:i,writable:!0,configurable:!0}}),e&&o(i,e),n=[{key:"load",value:function(){var e;return(e=function(){return function(e,t){var n,r,o,i={label:0,sent:function(){if(1&o[0])throw o[1];return o[1]},trys:[],ops:[]},u=Object.create(("function"==typeof Iterator?Iterator:Object).prototype),c=Object.defineProperty;return c(u,"next",{value:a(0)}),c(u,"throw",{value:a(1)}),c(u,"return",{value:a(2)}),"function"==typeof Symbol&&c(u,Symbol.iterator,{value:function(){return this}}),u;function a(c){return function(a){var l=[c,a];if(n)throw TypeError("Generator is already executing.");for(;u&&(u=0,l[0]&&(i=0)),i;)try{if(n=1,r&&(o=2&l[0]?r.return:l[0]?r.throw||((o=r.return)&&o.call(r),0):r.next)&&!(o=o.call(r,l[1])).done)return o;switch(r=0,o&&(l=[2&l[0],o.value]),l[0]){case 0:case 1:o=l;break;case 4:return i.label++,{value:l[1],done:!1};case 5:i.label++,r=l[1],l=[0];continue;case 7:l=i.ops.pop(),i.trys.pop();continue;default:if(!(o=(o=i.trys).length>0&&o[o.length-1])&&(6===l[0]||2===l[0])){i=0;continue}if(3===l[0]&&(!o||l[1]>o[0]&&l[1]<o[3])){i.label=l[1];break}if(6===l[0]&&i.label<o[1]){i.label=o[1],o=l;break}if(o&&i.label<o[2]){i.label=o[2],i.ops.push(l);break}o[2]&&i.ops.pop(),i.trys.pop();continue}l=t.call(e,i)}catch(e){l=[6,e],r=0}finally{n=o=0}if(5&l[0])throw l[1];return{value:l[0]?l[1]:void 0,done:!0}}}}(this,function(e){return this.pluginSettingsManager.addMenuItem({key:"ai-build-ui-template",title:this.t("Build UI Template"),icon:"LayoutOutlined",aclSnippet:"pm.ai-build-ui-template"}),this.pluginSettingsManager.addPageTabItem({menuKey:"ai-build-ui-template",key:"index",title:this.t("Build UI Template"),componentLoader:function(){return p.e("380").then(p.bind(p,23)).then(function(e){return{default:e.BuildUITemplateManager}})}}),[2]})},function(){var n=this,r=arguments;return new Promise(function(o,i){var u=e.apply(n,r);function c(e){t(u,o,i,c,a,"next",e)}function a(e){t(u,o,i,c,a,"throw",e)}c(void 0)})}).call(this)}}],function(e,t){for(var n=0;n<t.length;n++){var r=t[n];r.enumerable=r.enumerable||!1,r.configurable=!0,"value"in r&&(r.writable=!0),Object.defineProperty(e,r.key,r)}}(i.prototype,n),i}(i(e.Plugin))}(),h}()});
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This file is part of the NocoBase (R) project.
|
|
3
|
+
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
|
|
4
|
+
* Authors: NocoBase Team.
|
|
5
|
+
*
|
|
6
|
+
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
|
|
7
|
+
* For more information, please refer to: https://www.nocobase.com/agreement.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
module.exports = {
|
|
11
|
+
"react": "18.2.0",
|
|
12
|
+
"@nocobase/client": "2.1.6",
|
|
13
|
+
"antd": "5.24.2",
|
|
14
|
+
"@ant-design/icons": "5.6.1",
|
|
15
|
+
"@nocobase/client-v2": "2.1.6",
|
|
16
|
+
"@nocobase/server": "2.1.6",
|
|
17
|
+
"@nocobase/actions": "2.1.6",
|
|
18
|
+
"@nocobase/database": "2.1.6",
|
|
19
|
+
"@nocobase/plugin-ai": "2.1.6",
|
|
20
|
+
"@langchain/core": "1.1.48",
|
|
21
|
+
"@nocobase/utils": "2.1.6"
|
|
22
|
+
};
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This file is part of the NocoBase (R) project.
|
|
3
|
+
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
|
|
4
|
+
* Authors: NocoBase Team.
|
|
5
|
+
*
|
|
6
|
+
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
|
|
7
|
+
* For more information, please refer to: https://www.nocobase.com/agreement.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
var __create = Object.create;
|
|
11
|
+
var __defProp = Object.defineProperty;
|
|
12
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
13
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
14
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
15
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
16
|
+
var __export = (target, all) => {
|
|
17
|
+
for (var name in all)
|
|
18
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
19
|
+
};
|
|
20
|
+
var __copyProps = (to, from, except, desc) => {
|
|
21
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
22
|
+
for (let key of __getOwnPropNames(from))
|
|
23
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
24
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
25
|
+
}
|
|
26
|
+
return to;
|
|
27
|
+
};
|
|
28
|
+
var __reExport = (target, mod, secondTarget) => (__copyProps(target, mod, "default"), secondTarget && __copyProps(secondTarget, mod, "default"));
|
|
29
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
30
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
31
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
32
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
33
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
34
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
35
|
+
mod
|
|
36
|
+
));
|
|
37
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
38
|
+
var src_exports = {};
|
|
39
|
+
__export(src_exports, {
|
|
40
|
+
default: () => import_server.default
|
|
41
|
+
});
|
|
42
|
+
module.exports = __toCommonJS(src_exports);
|
|
43
|
+
__reExport(src_exports, require("./server"), module.exports);
|
|
44
|
+
var import_server = __toESM(require("./server"));
|
|
45
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
46
|
+
0 && (module.exports = {
|
|
47
|
+
...require("./server")
|
|
48
|
+
});
|
|
@@ -0,0 +1,422 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This file is part of the NocoBase (R) project.
|
|
3
|
+
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
|
|
4
|
+
* Authors: NocoBase Team.
|
|
5
|
+
*
|
|
6
|
+
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
|
|
7
|
+
* For more information, please refer to: https://www.nocobase.com/agreement.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
var __defProp = Object.defineProperty;
|
|
11
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
12
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
13
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
14
|
+
var __export = (target, all) => {
|
|
15
|
+
for (var name in all)
|
|
16
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
17
|
+
};
|
|
18
|
+
var __copyProps = (to, from, except, desc) => {
|
|
19
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
20
|
+
for (let key of __getOwnPropNames(from))
|
|
21
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
22
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
23
|
+
}
|
|
24
|
+
return to;
|
|
25
|
+
};
|
|
26
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
27
|
+
var build_exports = {};
|
|
28
|
+
__export(build_exports, {
|
|
29
|
+
WORKER_JOB_BUILD_UI_TEMPLATE_PROCESS: () => WORKER_JOB_BUILD_UI_TEMPLATE_PROCESS,
|
|
30
|
+
build: () => build,
|
|
31
|
+
recoverInterruptedBuilds: () => recoverInterruptedBuilds,
|
|
32
|
+
registerBuildTemplateQueue: () => registerBuildTemplateQueue,
|
|
33
|
+
unregisterBuildTemplateQueue: () => unregisterBuildTemplateQueue
|
|
34
|
+
});
|
|
35
|
+
module.exports = __toCommonJS(build_exports);
|
|
36
|
+
var import_messages = require("@langchain/core/messages");
|
|
37
|
+
var import_utils = require("@nocobase/utils");
|
|
38
|
+
const WORKER_JOB_BUILD_UI_TEMPLATE_PROCESS = "build-ui-template:process";
|
|
39
|
+
const BUILD_TEMPLATE_QUEUE_CHANNEL = "plugin-build-ui-template.build";
|
|
40
|
+
const BUILD_TEMPLATE_QUEUE_TIMEOUT_MS = 10 * 60 * 1e3;
|
|
41
|
+
const BUILD_TEMPLATE_QUEUE_POLL_INTERVAL_MS = 5e3;
|
|
42
|
+
const BUILD_TEMPLATE_QUEUE_WAKE_CHANNEL = "plugin-build-ui-template.build.wake";
|
|
43
|
+
let buildQueueTimer = null;
|
|
44
|
+
let buildQueueKickTimer = null;
|
|
45
|
+
let buildQueueProcessing = false;
|
|
46
|
+
let buildQueueWakeHandler = null;
|
|
47
|
+
class StaleBuildRunError extends Error {
|
|
48
|
+
constructor(spaceId, runId) {
|
|
49
|
+
super(`Build run ${runId} for space ${spaceId} is no longer active`);
|
|
50
|
+
this.name = "StaleBuildRunError";
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
async function build(ctx, next) {
|
|
54
|
+
const { filterByTk } = ctx.action.params;
|
|
55
|
+
if (!filterByTk) {
|
|
56
|
+
return ctx.throw(400, "spaceId is required");
|
|
57
|
+
}
|
|
58
|
+
const spaceRepo = ctx.db.getRepository("aiBuildUiTemplateSpaces");
|
|
59
|
+
const space = await spaceRepo.findById(filterByTk);
|
|
60
|
+
if (!space) {
|
|
61
|
+
return ctx.throw(404, "Space not found");
|
|
62
|
+
}
|
|
63
|
+
const runId = (0, import_utils.uid)();
|
|
64
|
+
const now = /* @__PURE__ */ new Date();
|
|
65
|
+
await spaceRepo.update({
|
|
66
|
+
filterByTk,
|
|
67
|
+
values: {
|
|
68
|
+
status: "building",
|
|
69
|
+
buildPhase: "queued",
|
|
70
|
+
buildRunId: runId,
|
|
71
|
+
buildQueuedAt: now,
|
|
72
|
+
buildLog: "Build requested, queuing job..."
|
|
73
|
+
},
|
|
74
|
+
transaction: ctx.transaction
|
|
75
|
+
});
|
|
76
|
+
ctx.body = {
|
|
77
|
+
result: "ok",
|
|
78
|
+
runId
|
|
79
|
+
};
|
|
80
|
+
await next();
|
|
81
|
+
const app = ctx.app;
|
|
82
|
+
setTimeout(() => {
|
|
83
|
+
enqueueLocalBuild(app, { spaceId: String(filterByTk), runId });
|
|
84
|
+
}, 100);
|
|
85
|
+
}
|
|
86
|
+
function enqueueLocalBuild(app, message) {
|
|
87
|
+
var _a;
|
|
88
|
+
(_a = app.log) == null ? void 0 : _a.info(`[plugin-build-ui-template] Enqueued build ${message.runId} for space "${message.spaceId}"`);
|
|
89
|
+
publishBuildQueueWake(app, message);
|
|
90
|
+
}
|
|
91
|
+
async function publishBuildQueueWake(app, message) {
|
|
92
|
+
var _a, _b, _c;
|
|
93
|
+
try {
|
|
94
|
+
await ((_b = (_a = app.pubSubManager) == null ? void 0 : _a.publish) == null ? void 0 : _b.call(
|
|
95
|
+
_a,
|
|
96
|
+
BUILD_TEMPLATE_QUEUE_WAKE_CHANNEL,
|
|
97
|
+
{ spaceId: message == null ? void 0 : message.spaceId, runId: message == null ? void 0 : message.runId }
|
|
98
|
+
));
|
|
99
|
+
} catch (error) {
|
|
100
|
+
(_c = app.log) == null ? void 0 : _c.debug(`[plugin-build-ui-template] Wake publish skipped: ${(error == null ? void 0 : error.message) || error}`);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
function registerBuildTemplateQueue(app) {
|
|
104
|
+
var _a, _b, _c;
|
|
105
|
+
if (buildQueueTimer) return;
|
|
106
|
+
buildQueueWakeHandler = async () => {
|
|
107
|
+
scheduleBuildQueueTick(app, 0);
|
|
108
|
+
};
|
|
109
|
+
const subscribe = (_b = (_a = app.pubSubManager) == null ? void 0 : _a.subscribe) == null ? void 0 : _b.call(_a, BUILD_TEMPLATE_QUEUE_WAKE_CHANNEL, buildQueueWakeHandler);
|
|
110
|
+
if (subscribe == null ? void 0 : subscribe.catch) {
|
|
111
|
+
subscribe.catch((error) => {
|
|
112
|
+
var _a2;
|
|
113
|
+
(_a2 = app.log) == null ? void 0 : _a2.debug(`[plugin-build-ui-template] Wake subscribe skipped: ${(error == null ? void 0 : error.message) || error}`);
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
buildQueueTimer = setInterval(() => scheduleBuildQueueTick(app, 0), BUILD_TEMPLATE_QUEUE_POLL_INTERVAL_MS);
|
|
117
|
+
(_c = buildQueueTimer.unref) == null ? void 0 : _c.call(buildQueueTimer);
|
|
118
|
+
scheduleBuildQueueTick(app, 1e3);
|
|
119
|
+
}
|
|
120
|
+
function unregisterBuildTemplateQueue(app) {
|
|
121
|
+
var _a, _b;
|
|
122
|
+
if (buildQueueTimer) {
|
|
123
|
+
clearInterval(buildQueueTimer);
|
|
124
|
+
buildQueueTimer = null;
|
|
125
|
+
}
|
|
126
|
+
if (buildQueueKickTimer) {
|
|
127
|
+
clearTimeout(buildQueueKickTimer);
|
|
128
|
+
buildQueueKickTimer = null;
|
|
129
|
+
}
|
|
130
|
+
if (buildQueueWakeHandler) {
|
|
131
|
+
(_b = (_a = app.pubSubManager) == null ? void 0 : _a.unsubscribe) == null ? void 0 : _b.call(
|
|
132
|
+
_a,
|
|
133
|
+
BUILD_TEMPLATE_QUEUE_WAKE_CHANNEL,
|
|
134
|
+
buildQueueWakeHandler
|
|
135
|
+
).catch(() => void 0);
|
|
136
|
+
buildQueueWakeHandler = null;
|
|
137
|
+
}
|
|
138
|
+
buildQueueProcessing = false;
|
|
139
|
+
}
|
|
140
|
+
function scheduleBuildQueueTick(app, delayMs) {
|
|
141
|
+
var _a;
|
|
142
|
+
if (buildQueueKickTimer) return;
|
|
143
|
+
buildQueueKickTimer = setTimeout(() => {
|
|
144
|
+
buildQueueKickTimer = null;
|
|
145
|
+
runBuildQueueTick(app).catch((error) => {
|
|
146
|
+
var _a2;
|
|
147
|
+
(_a2 = app.log) == null ? void 0 : _a2.error("[plugin-build-ui-template] Queue tick failed", error);
|
|
148
|
+
});
|
|
149
|
+
}, delayMs);
|
|
150
|
+
(_a = buildQueueKickTimer.unref) == null ? void 0 : _a.call(buildQueueKickTimer);
|
|
151
|
+
}
|
|
152
|
+
async function runBuildQueueTick(app) {
|
|
153
|
+
var _a, _b, _c;
|
|
154
|
+
if (buildQueueProcessing) return;
|
|
155
|
+
buildQueueProcessing = true;
|
|
156
|
+
try {
|
|
157
|
+
const spaceRepo = app.db.getRepository("aiBuildUiTemplateSpaces");
|
|
158
|
+
const queuedSpaces = await spaceRepo.find({
|
|
159
|
+
filter: {
|
|
160
|
+
status: "building",
|
|
161
|
+
buildPhase: "queued"
|
|
162
|
+
},
|
|
163
|
+
sort: ["buildQueuedAt"],
|
|
164
|
+
limit: 1
|
|
165
|
+
});
|
|
166
|
+
if (!queuedSpaces || queuedSpaces.length === 0) {
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
const space = queuedSpaces[0];
|
|
170
|
+
const run = {
|
|
171
|
+
spaceId: String(space.get("id")),
|
|
172
|
+
runId: String(space.get("buildRunId"))
|
|
173
|
+
};
|
|
174
|
+
(_a = app.log) == null ? void 0 : _a.info(`[plugin-build-ui-template] Starting async build for space ${run.spaceId}`);
|
|
175
|
+
const [affected] = await spaceRepo.update({
|
|
176
|
+
filter: {
|
|
177
|
+
id: run.spaceId,
|
|
178
|
+
status: "building",
|
|
179
|
+
buildPhase: "queued",
|
|
180
|
+
buildRunId: run.runId
|
|
181
|
+
},
|
|
182
|
+
values: {
|
|
183
|
+
buildPhase: "running",
|
|
184
|
+
buildStartedAt: /* @__PURE__ */ new Date(),
|
|
185
|
+
buildHeartbeatAt: /* @__PURE__ */ new Date()
|
|
186
|
+
}
|
|
187
|
+
});
|
|
188
|
+
if (affected <= 0) {
|
|
189
|
+
(_b = app.log) == null ? void 0 : _b.warn(`[plugin-build-ui-template] Failed to claim build run ${run.runId}`);
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
const heartbeatTimer = setInterval(() => {
|
|
193
|
+
spaceRepo.update({
|
|
194
|
+
filter: { id: run.spaceId, buildRunId: run.runId },
|
|
195
|
+
values: { buildHeartbeatAt: /* @__PURE__ */ new Date() }
|
|
196
|
+
}).catch(() => void 0);
|
|
197
|
+
}, 1e4);
|
|
198
|
+
try {
|
|
199
|
+
await executeBuild(app, run);
|
|
200
|
+
} catch (err) {
|
|
201
|
+
(_c = app.log) == null ? void 0 : _c.error(`[plugin-build-ui-template] Build ${run.runId} failed`, err);
|
|
202
|
+
await spaceRepo.update({
|
|
203
|
+
filter: { id: run.spaceId, buildRunId: run.runId },
|
|
204
|
+
values: {
|
|
205
|
+
status: "error",
|
|
206
|
+
buildPhase: "error",
|
|
207
|
+
buildLog: `Generation failed: ${err.message || String(err)}`
|
|
208
|
+
}
|
|
209
|
+
}).catch(() => void 0);
|
|
210
|
+
} finally {
|
|
211
|
+
clearInterval(heartbeatTimer);
|
|
212
|
+
}
|
|
213
|
+
} finally {
|
|
214
|
+
buildQueueProcessing = false;
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
async function recoverInterruptedBuilds(app) {
|
|
218
|
+
var _a;
|
|
219
|
+
const spaceRepo = app.db.getRepository("aiBuildUiTemplateSpaces");
|
|
220
|
+
const runningSpaces = await spaceRepo.find({
|
|
221
|
+
filter: {
|
|
222
|
+
status: "building",
|
|
223
|
+
buildPhase: "running"
|
|
224
|
+
}
|
|
225
|
+
});
|
|
226
|
+
for (const space of runningSpaces) {
|
|
227
|
+
const spaceId = String(space.get("id"));
|
|
228
|
+
(_a = app.log) == null ? void 0 : _a.info(`[plugin-build-ui-template] Re-queuing interrupted build for space ${spaceId}`);
|
|
229
|
+
await spaceRepo.update({
|
|
230
|
+
filterByTk: spaceId,
|
|
231
|
+
values: {
|
|
232
|
+
buildPhase: "queued",
|
|
233
|
+
buildQueuedAt: /* @__PURE__ */ new Date(),
|
|
234
|
+
buildLog: "System restarted, re-queuing build job..."
|
|
235
|
+
}
|
|
236
|
+
});
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
async function executeBuild(app, run) {
|
|
240
|
+
const spaceRepo = app.db.getRepository("aiBuildUiTemplateSpaces");
|
|
241
|
+
const space = await spaceRepo.findById(run.spaceId);
|
|
242
|
+
if (!space) throw new Error("Space not found");
|
|
243
|
+
const { title, llmService, model, systemPrompt, promptRequirements, type, targetCollection } = space.get();
|
|
244
|
+
if (!llmService || !model) throw new Error("LLM Service or model is missing in space settings");
|
|
245
|
+
await updateSpace(app, run, "preparing", "Loading target collection metadata...");
|
|
246
|
+
let fieldsMeta = "";
|
|
247
|
+
if (targetCollection) {
|
|
248
|
+
const collection = app.db.getCollection(targetCollection);
|
|
249
|
+
if (collection) {
|
|
250
|
+
const fields = collection.fields;
|
|
251
|
+
fieldsMeta = Array.from(fields.values()).map((f) => {
|
|
252
|
+
var _a;
|
|
253
|
+
return `- Name: ${f.name}, Type: ${f.type}, Title: ${((_a = f.options) == null ? void 0 : _a.title) || f.name}`;
|
|
254
|
+
}).join("\n");
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
await updateSpace(app, run, "generating", "AI is generating UI flow models...");
|
|
258
|
+
const aiPlugin = app.pm.get("ai");
|
|
259
|
+
if (!aiPlugin) throw new Error("Plugin AI is not available");
|
|
260
|
+
const serviceData = await aiPlugin.aiManager.getLLMService({ llmService, model });
|
|
261
|
+
const provider = serviceData.provider;
|
|
262
|
+
const messages = [];
|
|
263
|
+
if (systemPrompt) {
|
|
264
|
+
messages.push(new import_messages.SystemMessage(systemPrompt));
|
|
265
|
+
} else {
|
|
266
|
+
messages.push(
|
|
267
|
+
new import_messages.SystemMessage(
|
|
268
|
+
`You are a senior UI UX developer specializing in NocoBase V2.
|
|
269
|
+
You construct professional block layouts using nested JSON FlowModels.
|
|
270
|
+
|
|
271
|
+
Rules:
|
|
272
|
+
- Return ONLY a valid JSON structure representing the root FlowModel. No markdown code fences, no explanations.
|
|
273
|
+
- The root object must contain "use" representing the block type. Common types: "EditFormModel", "DetailsBlockModel", "TableBlockModel", "GridCardBlockModel".
|
|
274
|
+
- The layout is recursive. Sub-models should be defined in a "subModels" object, mapped by subKey.
|
|
275
|
+
- Every subModel must have a unique "uid" placeholder (you can output temporary strings like "node_1", "node_2").
|
|
276
|
+
- Always include standard grid layouts: a Form or Details block should have a subModel with key "grid" using "ReferenceFormGridModel" or "FormGridModel" containing a grid of fields.
|
|
277
|
+
- Ensure correct collection binding by using target fields provided in the prompt context.
|
|
278
|
+
`
|
|
279
|
+
)
|
|
280
|
+
);
|
|
281
|
+
}
|
|
282
|
+
let prompt = `Create a beautiful UI ${type === "popup" ? "Popup" : "Block"} template for collection "${targetCollection || "unknown"}".
|
|
283
|
+
Requirements: ${promptRequirements || "Create a clean, functional dashboard/form layout"}
|
|
284
|
+
`;
|
|
285
|
+
if (fieldsMeta) {
|
|
286
|
+
prompt += `
|
|
287
|
+
Available Database Fields for collection "${targetCollection}":
|
|
288
|
+
${fieldsMeta}`;
|
|
289
|
+
}
|
|
290
|
+
messages.push(new import_messages.HumanMessage(prompt));
|
|
291
|
+
const response = await provider.chatModel.invoke(messages);
|
|
292
|
+
const rawText = stripThink(toPlainText(response.content));
|
|
293
|
+
await updateSpace(app, run, "saving", "Parsing and storing the new FlowModel...");
|
|
294
|
+
const cleanJsonText = stripFence(rawText);
|
|
295
|
+
const jsonStart = cleanJsonText.indexOf("{");
|
|
296
|
+
const jsonEnd = cleanJsonText.lastIndexOf("}");
|
|
297
|
+
const jsonText = jsonStart >= 0 && jsonEnd > jsonStart ? cleanJsonText.slice(jsonStart, jsonEnd + 1) : cleanJsonText;
|
|
298
|
+
let parsedModel;
|
|
299
|
+
try {
|
|
300
|
+
parsedModel = JSON.parse(jsonText);
|
|
301
|
+
} catch (err) {
|
|
302
|
+
throw new Error(`Failed to parse AI output as JSON: ${rawText.slice(0, 300)}`);
|
|
303
|
+
}
|
|
304
|
+
const uidMap = {};
|
|
305
|
+
const assignUids = (node) => {
|
|
306
|
+
if (!node || typeof node !== "object") return;
|
|
307
|
+
const oldUid = node.uid || node["x-uid"] || (0, import_utils.uid)();
|
|
308
|
+
const newUid = (0, import_utils.uid)();
|
|
309
|
+
uidMap[oldUid] = newUid;
|
|
310
|
+
node.uid = newUid;
|
|
311
|
+
node["x-uid"] = newUid;
|
|
312
|
+
if (node.subModels && typeof node.subModels === "object") {
|
|
313
|
+
for (const val of Object.values(node.subModels)) {
|
|
314
|
+
const items = Array.isArray(val) ? val : [val];
|
|
315
|
+
for (const item of items) {
|
|
316
|
+
assignUids(item);
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
};
|
|
321
|
+
assignUids(parsedModel);
|
|
322
|
+
const replacePlaceholderUids = (val) => {
|
|
323
|
+
if (typeof val === "string") {
|
|
324
|
+
return uidMap[val] || val;
|
|
325
|
+
}
|
|
326
|
+
if (Array.isArray(val)) {
|
|
327
|
+
return val.map(replacePlaceholderUids);
|
|
328
|
+
}
|
|
329
|
+
if (val && typeof val === "object") {
|
|
330
|
+
const next = {};
|
|
331
|
+
for (const [k, v] of Object.entries(val)) {
|
|
332
|
+
next[k] = replacePlaceholderUids(v);
|
|
333
|
+
}
|
|
334
|
+
return next;
|
|
335
|
+
}
|
|
336
|
+
return val;
|
|
337
|
+
};
|
|
338
|
+
parsedModel = replacePlaceholderUids(parsedModel);
|
|
339
|
+
const configureRelations = (node, parentUid, subKey, subType) => {
|
|
340
|
+
if (!node || typeof node !== "object") return;
|
|
341
|
+
if (parentUid && subKey) {
|
|
342
|
+
node.parentId = parentUid;
|
|
343
|
+
node.subKey = subKey;
|
|
344
|
+
node.subType = subType || "object";
|
|
345
|
+
}
|
|
346
|
+
if (node.subModels && typeof node.subModels === "object") {
|
|
347
|
+
for (const [key, val] of Object.entries(node.subModels)) {
|
|
348
|
+
const isArray = Array.isArray(val);
|
|
349
|
+
const items = isArray ? val : [val];
|
|
350
|
+
items.forEach((item, idx) => {
|
|
351
|
+
configureRelations(item, node.uid, key, isArray ? "array" : "object");
|
|
352
|
+
if (isArray) {
|
|
353
|
+
item.sortIndex = idx + 1;
|
|
354
|
+
}
|
|
355
|
+
});
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
};
|
|
359
|
+
configureRelations(parsedModel);
|
|
360
|
+
const flowRepo = app.db.getRepository("flowModels");
|
|
361
|
+
if (!flowRepo || typeof flowRepo.insertModel !== "function") {
|
|
362
|
+
throw new Error("FlowModelRepository or insertModel is not available. Ensure plugin-flow-engine is enabled.");
|
|
363
|
+
}
|
|
364
|
+
const savedModel = await flowRepo.insertModel(parsedModel);
|
|
365
|
+
const targetUid = (savedModel == null ? void 0 : savedModel.uid) || parsedModel.uid;
|
|
366
|
+
const templateRepo = app.db.getRepository("flowModelTemplates");
|
|
367
|
+
const tplUid = (0, import_utils.uid)();
|
|
368
|
+
await templateRepo.create({
|
|
369
|
+
values: {
|
|
370
|
+
uid: tplUid,
|
|
371
|
+
name: `${title || "AI"} Template (${type})`,
|
|
372
|
+
description: `AI-generated template: ${(promptRequirements == null ? void 0 : promptRequirements.slice(0, 100)) || ""}`,
|
|
373
|
+
targetUid,
|
|
374
|
+
useModel: parsedModel.use || "BlockModel",
|
|
375
|
+
type: type || "block",
|
|
376
|
+
collectionName: targetCollection || void 0
|
|
377
|
+
}
|
|
378
|
+
});
|
|
379
|
+
await spaceRepo.update({
|
|
380
|
+
filterByTk: run.spaceId,
|
|
381
|
+
values: {
|
|
382
|
+
status: "completed",
|
|
383
|
+
buildPhase: "completed",
|
|
384
|
+
templateUid: tplUid,
|
|
385
|
+
buildLog: `Template generated successfully! Target root FlowModel UID: ${targetUid}`
|
|
386
|
+
}
|
|
387
|
+
});
|
|
388
|
+
}
|
|
389
|
+
async function updateSpace(app, run, phase, log) {
|
|
390
|
+
const spaceRepo = app.db.getRepository("aiBuildUiTemplateSpaces");
|
|
391
|
+
await spaceRepo.update({
|
|
392
|
+
filter: { id: run.spaceId, buildRunId: run.runId },
|
|
393
|
+
values: {
|
|
394
|
+
buildPhase: phase,
|
|
395
|
+
buildLog: log
|
|
396
|
+
}
|
|
397
|
+
}).catch(() => void 0);
|
|
398
|
+
}
|
|
399
|
+
function toPlainText(value) {
|
|
400
|
+
if (typeof value === "string") return value;
|
|
401
|
+
if (Array.isArray(value)) {
|
|
402
|
+
return value.map((item) => (item == null ? void 0 : item.text) || (item == null ? void 0 : item.content) || "").filter(Boolean).join("\n");
|
|
403
|
+
}
|
|
404
|
+
if (value && typeof value === "object") {
|
|
405
|
+
return value.text || value.content || JSON.stringify(value);
|
|
406
|
+
}
|
|
407
|
+
return String(value);
|
|
408
|
+
}
|
|
409
|
+
function stripThink(text) {
|
|
410
|
+
return text.replace(/<think>[\s\S]*?(?:<\/think>|$)/gi, "").trim();
|
|
411
|
+
}
|
|
412
|
+
function stripFence(text) {
|
|
413
|
+
return text.replace(/^```(?:json|markdown|md)?\s*/i, "").replace(/```\s*$/i, "").trim();
|
|
414
|
+
}
|
|
415
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
416
|
+
0 && (module.exports = {
|
|
417
|
+
WORKER_JOB_BUILD_UI_TEMPLATE_PROCESS,
|
|
418
|
+
build,
|
|
419
|
+
recoverInterruptedBuilds,
|
|
420
|
+
registerBuildTemplateQueue,
|
|
421
|
+
unregisterBuildTemplateQueue
|
|
422
|
+
});
|