@mbwilding/tool-early-bound-generator 0.0.4 → 0.0.6

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.
Binary file
@@ -1,15 +1,37 @@
1
- <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" fill="none">
2
- <!-- Full-bleed blue background -->
3
- <rect width="32" height="32" fill="#0078d4"/>
4
- <g>
5
- <!-- Code brackets: < > -->
6
- <path d="M7 16 L11 12 L11 13.5 L8.5 16 L11 18.5 L11 20 Z" fill="white"/>
7
- <path d="M25 16 L21 12 L21 13.5 L23.5 16 L21 18.5 L21 20 Z" fill="white"/>
8
- <!-- Three lines representing generated code -->
9
- <rect x="13" y="12" width="6" height="1.5" rx="0.75" fill="white" fill-opacity="0.9"/>
10
- <rect x="13" y="15.25" width="6" height="1.5" rx="0.75" fill="white" fill-opacity="0.9"/>
11
- <rect x="13" y="18.5" width="6" height="1.5" rx="0.75" fill="white" fill-opacity="0.9"/>
12
- <!-- Small "C#" label bottom-right -->
13
- <text x="18.5" y="28" font-family="Segoe UI, Arial, sans-serif" font-size="5.5" font-weight="700" fill="white" fill-opacity="0.85">C#</text>
14
- </g>
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64" width="512px" height="512px">
2
+ <defs>
3
+ <linearGradient id="lineGrad" x1="8" x2="56" y1="8" y2="56" gradientUnits="userSpaceOnUse" spreadMethod="reflect">
4
+ <stop offset="0" stop-color="#5b9bff" />
5
+ <stop offset="1" stop-color="#d47fff" />
6
+ </linearGradient>
7
+ <linearGradient id="csharpGrad" x1="10" x2="54" y1="20" y2="52" gradientUnits="userSpaceOnUse" spreadMethod="reflect">
8
+ <stop offset="0" stop-color="#1a6dff" />
9
+ <stop offset="1" stop-color="#c822ff" />
10
+ </linearGradient>
11
+ </defs>
12
+
13
+ <!-- Code line decorations -->
14
+ <!-- Top section -->
15
+ <rect x="8" y="8" width="22" height="2.5" rx="1.25" fill="url(#lineGrad)" opacity="0.55" />
16
+ <rect x="8" y="13" width="16" height="2.5" rx="1.25" fill="url(#lineGrad)" opacity="0.38" />
17
+ <rect x="8" y="18" width="10" height="2.5" rx="1.25" fill="url(#lineGrad)" opacity="0.28" />
18
+ <!-- Bottom section -->
19
+ <rect x="8" y="46" width="10" height="2.5" rx="1.25" fill="url(#lineGrad)" opacity="0.28" />
20
+ <rect x="8" y="51" width="16" height="2.5" rx="1.25" fill="url(#lineGrad)" opacity="0.38" />
21
+ <rect x="8" y="56" width="10" height="2.5" rx="1.25" fill="url(#lineGrad)" opacity="0.22" />
22
+
23
+ <!-- C# symbol scaled up ~1.6x, centred on 32,32 -->
24
+ <g transform="translate(32,32) scale(1.6) translate(-32,-32)">
25
+ <!-- C letter -->
26
+ <path fill="url(#csharpGrad)"
27
+ d="M27.75,41c-4.687,0-8-3.533-8-8.5c0-4.967,3.313-8.5,8-8.5c2.2,0,4.02,0.76,5.34,2.1l-1.88,1.96
28
+ c-0.9-0.9-2.07-1.46-3.46-1.46c-2.97,0-5,2.26-5,5.9c0,3.64,2.03,5.9,5,5.9c1.39,0,2.56-0.56,3.46-1.46l1.88,1.96
29
+ C31.77,40.24,29.95,41,27.75,41z" />
30
+
31
+ <!-- Hash # symbol -->
32
+ <polygon points="36,24 38,24 37.5,40 35.5,40" fill="url(#csharpGrad)" />
33
+ <polygon points="40.5,24 42.5,24 42,40 40,40" fill="url(#csharpGrad)" />
34
+ <rect x="34.25" y="28.5" width="10" height="2.2" rx="1.1" fill="url(#csharpGrad)" />
35
+ <rect x="34.25" y="33.5" width="10" height="2.2" rx="1.1" fill="url(#csharpGrad)" />
36
+ </g>
15
37
  </svg>
package/dist/index.js CHANGED
@@ -79,5 +79,5 @@ ${o}/// </summary>
79
79
  `}const Tc='Namespace="http://schemas.microsoft.com/xrm/2011/new/"',Tf={"System.String":"string","System.Boolean":"bool","System.Int32":"int","System.Int64":"long","System.Double":"double","System.Decimal":"decimal","System.Single":"float","System.Guid":"System.Guid","System.DateTime":"System.DateTime","System.Object":"object"};function Mc(l){if(!l)return"object";const o=l.split(",")[0].trim();return Tf[o]??o}function _c(l,o,a,p){const f=l.Request.Name,d=p.camelCase(f),c=[...l.Request.Fields].sort((j,L)=>p.camelCase(j.Name).localeCompare(p.camelCase(L.Name))),k=d+"Request",v=d+"Response",m=En(o.namespace);if(m.push(`${V}`),m.push(`${V}`),m.push(`${V}[System.Runtime.Serialization.DataContractAttribute(${Tc})]`),m.push(`${V}[Microsoft.Xrm.Sdk.Client.RequestProxyAttribute("${f}")]`),o.suppressGeneratedCodeAttribute||m.push(`${V}[System.CodeDom.Compiler.GeneratedCodeAttribute("${Wr}", "${a}")]`),m.push(`${V}public partial class ${k} : Microsoft.Xrm.Sdk.OrganizationRequest`),m.push(`${V}{`),m.push(`${C}`),o.generateMessageAttributeNameConsts){m.push(`${C}public static class Fields`),m.push(`${C}{`);for(const j of c){const L=p.camelCase(j.Name);m.push(`${O}public const string ${L} = "${j.Name}";`)}m.push(`${C}}`),m.push(`${C}`)}m.push(`${C}public const string ActionLogicalName = "${f}";`),m.push(`${C}`);for(const j of c){const L=Mc(j.ClrFormatter),g=p.camelCase(j.Name);m.push(`${C}public ${L}? ${g}`),m.push(`${C}{`),m.push(`${O}get`),m.push(`${O}{`),m.push(`${B}if (this.Parameters.Contains("${j.Name}"))`),m.push(`${B}{`),m.push(`${B}${V}return ((${L})(this.Parameters["${j.Name}"]));`),m.push(`${B}}`),m.push(`${B}else`),m.push(`${B}{`),m.push(`${B}${V}return default(${L});`),m.push(`${B}}`),m.push(`${O}}`),m.push(`${O}set`),m.push(`${O}{`),m.push(`${B}this.Parameters["${j.Name}"] = value;`),m.push(`${O}}`),m.push(`${C}}`),m.push(`${C}`)}m.push(`${C}public ${k}()`),m.push(`${C}{`),m.push(`${O}this.RequestName = "${f}";`);for(const j of c)if(!j.IsOptional){const L=Mc(j.ClrFormatter),g=p.camelCase(j.Name);m.push(`${O}this.${g} = default(${L});`)}return m.push(`${C}}`),m.push(`${V}}`),m.push(`${V}`),m.push(`${V}[System.Runtime.Serialization.DataContractAttribute(${Tc})]`),m.push(`${V}[Microsoft.Xrm.Sdk.Client.ResponseProxyAttribute("${f}")]`),o.suppressGeneratedCodeAttribute||m.push(`${V}[System.CodeDom.Compiler.GeneratedCodeAttribute("${Wr}", "${a}")]`),m.push(`${V}public partial class ${v} : Microsoft.Xrm.Sdk.OrganizationResponse`),m.push(`${V}{`),m.push(`${C}`),m.push(`${C}public const string ActionLogicalName = "${f}";`),m.push(`${C}`),m.push(`${C}public ${v}()`),m.push(`${C}{`),m.push(`${C}}`),m.push(`${V}}`),m.push("}"),m.push("#pragma warning restore CS1591"),m.push(""),m.join(`
80
80
  `)}function Mf(l,o,a,p){const f=En(o.namespace);for(const d of l){const c=_c(d,o,a,p),k=Rc(c,o.namespace);k&&f.push(k)}return f.push("}"),f.push("#pragma warning restore CS1591"),f.join(`
81
81
  `)}async function Ff(l,o){const a=`EntityDefinitions(LogicalName='${l}')`,p=["PicklistAttributeMetadata","StatusAttributeMetadata","StateAttributeMetadata","BooleanAttributeMetadata","MultiSelectPicklistAttributeMetadata"],[f,d,c,k,v,m,...j]=await Promise.all([window.dataverseAPI.getEntityMetadata(l,!0),window.dataverseAPI.getEntityRelatedMetadata(l,"Attributes"),window.dataverseAPI.getEntityRelatedMetadata(l,"OneToManyRelationships"),window.dataverseAPI.getEntityRelatedMetadata(l,"ManyToOneRelationships"),window.dataverseAPI.getEntityRelatedMetadata(l,"ManyToManyRelationships"),window.dataverseAPI.getEntityRelatedMetadata(l,"Keys"),...p.map(se=>window.dataverseAPI.queryData(`${a}/Attributes/Microsoft.Dynamics.CRM.${se}?$select=LogicalName&$expand=OptionSet`))]),L=f,g=new Map;for(const se of j)for(const pe of se.value){const A=pe.LogicalName,ee=pe.OptionSet;if(A&&ee){const Ne=Dc(ee);Ne.Options.length>0&&g.set(A,Ne)}}const q=(d.value??[]).map(se=>{const pe=jf(se),A=g.get(pe.LogicalName);return A&&(pe.OptionSet=A),pe});if(o){const se=q.filter(pe=>pe.OptionSet&&pe.OptionSet.Options.length>0).length;o(` [${l}] attrs=${q.length} withOptions=${se}`)}const D=ua(c.value),Q=ua(k.value),Se=ua(v.value);return{LogicalName:L.LogicalName??l,SchemaName:L.SchemaName??l,DisplayName:L.DisplayName,Description:L.Description,LogicalCollectionName:L.LogicalCollectionName,EntitySetName:L.EntitySetName,PrimaryIdAttribute:L.PrimaryIdAttribute,PrimaryNameAttribute:L.PrimaryNameAttribute,Attributes:q,OneToManyRelationships:D,ManyToOneRelationships:Q,ManyToManyRelationships:Se,Keys:(m.value??[]).map(se=>({MetadataId:se.MetadataId,KeyAttributes:se.KeyAttributes}))}}function jf(l){const o=l.OptionSet;let a;return o&&(a=Dc(o)),{LogicalName:l.LogicalName??"",SchemaName:l.SchemaName??"",DisplayName:l.DisplayName,Description:l.Description,AttributeType:l.AttributeType??"String",AttributeTypeName:l.AttributeTypeName,AttributeOf:l.AttributeOf,IsValidForCreate:l.IsValidForCreate,IsValidForUpdate:l.IsValidForUpdate,IsValidForRead:l.IsValidForRead,IsPrimaryId:l.IsPrimaryId,IsPrimaryName:l.IsPrimaryName,IsRenameable:l.IsRenameable,Targets:l.Targets,OptionSet:a,DeprecatedVersion:l.DeprecatedVersion}}function Dc(l){const o=Array.isArray(l.Options)?l.Options:[];return{MetadataId:l.MetadataId??"",Name:l.Name??"",DisplayName:l.DisplayName,Description:l.Description,OptionSetType:l.OptionSetType??"Picklist",IsGlobal:l.IsGlobal,Options:o.map(a=>({Value:a.Value,Label:a.Label,Description:a.Description,Color:a.Color,DisplayOrder:a.DisplayOrder}))}}function ua(l){return Array.isArray(l)?l.map(o=>({SchemaName:o.SchemaName??"",RelationshipType:o.RelationshipType,ReferencedEntity:o.ReferencedEntity,ReferencingEntity:o.ReferencingEntity,ReferencedEntityNavigationPropertyName:o.ReferencedEntityNavigationPropertyName,ReferencingEntityNavigationPropertyName:o.ReferencingEntityNavigationPropertyName,Entity1LogicalName:o.Entity1LogicalName,Entity2LogicalName:o.Entity2LogicalName,Entity1NavigationPropertyName:o.Entity1NavigationPropertyName,Entity2NavigationPropertyName:o.Entity2NavigationPropertyName})):[]}async function cn(l,o,a){try{await window.toolboxAPI.fileSystem.writeText(l,o),a(` Code written to ${l}.`)}catch(p){const f=String(p);if(f.includes("Access denied")||f.includes("permission")){const d=l.includes("/")?l.substring(0,l.lastIndexOf("/")):l;if(a(` Access denied — requesting permission for: ${d}`),!await window.toolboxAPI.fileSystem.selectPath({type:"folder",title:"Grant access to output folder",defaultPath:d}))throw new Error(`Access denied to ${d} and permission request was cancelled.`);await window.toolboxAPI.fileSystem.writeText(l,o),a(` Code written to ${l}.`)}else throw p}}function ca(l,o){const a=l.replace(/\\/g,"/").trim();if(a.endsWith(".cs")){const p=a.lastIndexOf("/");return p>=0?{dir:a.slice(0,p),filename:a.slice(p+1)}:{dir:"",filename:a}}return{dir:a,filename:o}}async function Rf(l,o,a,p,f){var Ne;p("=== Early Bound Generator ==="),p("Loading dictionary...");const d=[...l.tokenCapitalizationOverrides].sort((z,ie)=>ie.length-z.length),c=async()=>{const z=await fetch("/DLaB.Dictionary.txt");if(!z.ok)throw new Error(`HTTP ${z.status}`);return z.text()};let k;try{let z;const ie=(Ne=l.camelCaseNamesDictionaryRelativePath)==null?void 0:Ne.trim();if(ie&&window.toolboxAPI){const le=Ke(o,ie);await window.toolboxAPI.fileSystem.exists(le).catch(()=>!1)?(p(` Loaded custom dictionary: ${le}`),z=await window.toolboxAPI.fileSystem.readText(le)):(p(` Custom dictionary not found (${le}), using built-in.`),z=await c())}else z=await c();k=new Pc(yf(z,l.camelCaseCustomWords),d)}catch(z){p(` Warning: could not load dictionary (${String(z)}), falling back to title-case only.`),k=new Pc(new Map,d)}const v=new pf(l,k),m=new hf(l);p("Fetching entity list...");const g=(await window.dataverseAPI.getAllEntitiesMetadata(["LogicalName","SchemaName","DisplayName"])).value.map(z=>({logicalName:z.LogicalName.toLowerCase(),schemaName:z.SchemaName??""})).filter(z=>m.shouldGenerateEntity({LogicalName:z.logicalName,SchemaName:z.schemaName,DisplayName:{LocalizedLabels:[]},Attributes:[]}));p(`Fetching metadata for ${g.length} entities...`);const I=new Map,q=[],D=5;for(let z=0;z<g.length;z+=D){const ie=g.slice(z,z+D),le=await Promise.all(ie.map(re=>Ff(re.logicalName,p)));for(const re of le)I.set(re.LogicalName.toLowerCase(),re),q.push(re);p(` Fetched ${Math.min(z+D,g.length)} / ${g.length}`)}const Q=ca(l.entityTypesFolder,"Entities.cs"),Se=Q.dir?Ke(a,Q.dir):a;if(l.createOneFilePerEntity){p(`--- Entities (${q.length}) ---`);for(const z of q){const ie=v.getNameForEntity(z),le=Lc(z,I,{settings:l,namingService:v,filterService:m,suppressGeneratedCode:l.suppressGeneratedCodeAttribute,appVersion:f}),re=Ke(Se,`${ie}.cs`);await cn(re,le,p)}}else{p("--- Entities (combined) ---");const z=["#nullable enable","#pragma warning disable CS1591","//------------------------------------------------------------------------------","// <auto-generated>","// This code was generated by a tool.","//","// Changes to this file may cause incorrect behavior and will be lost if","// the code is regenerated.","// </auto-generated>","//------------------------------------------------------------------------------","",`namespace ${l.namespace}`,"{"];for(const ie of q){const le=Lc(ie,I,{settings:l,namingService:v,filterService:m,suppressGeneratedCode:l.suppressGeneratedCodeAttribute,appVersion:f}),re=Rc(le,l.namespace);re&&z.push(re)}z.push("}"),z.push("#pragma warning restore CS1591"),await cn(Ke(Se,Q.filename),z.join(`
82
- `),p)}const se=ca(l.optionSetsTypesFolder,"OptionSet.cs"),pe=se.dir?Ke(a,se.dir):a,A=Af(q,l);if(l.createOneFilePerOptionSet)if(p(`--- Option Sets (${A.length}) ---`),l.groupLocalOptionSetsByEntity){const z=new Map;for(const{entity:ie,optionSet:le}of A){const re=(ie==null?void 0:ie.LogicalName)??"__global__";z.has(re)||z.set(re,[]),z.get(re).push(le)}for(const[ie,le]of z){const re=ie!=="__global__"?I.get(ie.toLowerCase())??null:null,Ce=re?v.getNameForEntity(re):"GlobalOptionSets",Xe=Pf(re??{LogicalName:"global",SchemaName:"global",DisplayName:{LocalizedLabels:[]},Attributes:[]},le,v,l,f);await cn(Ke(pe,`${Ce}.cs`),Xe,p)}}else for(const{entity:z,optionSet:ie}of A){const le=v.getNameForOptionSet(z,ie),re=Of(z,ie,v,l,f);await cn(Ke(pe,`${le}.cs`),re,p)}else{p("--- Option Sets (combined) ---");const z=$f(A,v,l,f);await cn(Ke(pe,se.filename),z,p)}p("--- Service Context ---");const ee=Lf(q,v,l,f);if(await cn(Ke(a,`${l.serviceContextName}.cs`),ee,p),l.generateMessages){const z=await _f(l,m,p),ie=ca(l.messageTypesFolder,"Messages.cs"),le=ie.dir?Ke(a,ie.dir):a;if(z.length>0)if(l.createOneFilePerMessage){p(`--- Messages (${z.length}) ---`);for(const re of z){const Ce=_c(re,l,f,v),Xe=v.camelCase(re.Request.Name);await cn(Ke(le,`${Xe}.cs`),Ce,p)}}else{p("--- Messages (combined) ---");const re=Mf(z,l,f,v);await cn(Ke(le,ie.filename),re,p)}else p(" No messages matched the filter.")}p("=== Generation Complete ===")}async function _f(l,o,a){try{const p=Df(l),f=`sdkmessages?$select=name,sdkmessageid&$filter=${encodeURIComponent(p)}&$top=500`,c=(await window.dataverseAPI.queryData(f)).value,k=[];for(const v of c){const m=v.name;if(!o.shouldGenerateMessage(m))continue;const j=await If(m,v.sdkmessageid);j&&k.push(j)}return k}catch(p){return a(` Warning: Could not fetch SDK messages: ${Jn(p)}`),[]}}function Df(l){return l.messagesWhitelist.length>0?l.messagesWhitelist.map(a=>`name eq '${a.replace(/'/g,"''")}'`).join(" or "):"autotransact eq true"}async function If(l,o){try{const p=(await window.dataverseAPI.queryData(`sdkmessagepairs?$select=sdkmessagepairid&$filter=_sdkmessageid_value eq ${o}&$top=1`)).value;if(!p.length)return null;const f=p[0].sdkmessagepairid,c=(await window.dataverseAPI.queryData(`sdkmessagerequests?$select=sdkmessagerequestid&$filter=_sdkmessagepairid_value eq ${f}&$top=1`)).value;if(!c.length)return null;const k=c[0].sdkmessagerequestid,v=await window.dataverseAPI.queryData(`sdkmessagerequestfields?$select=name,clrparser,optional,position&$filter=_sdkmessagerequestid_value eq ${k}&$orderby=position`),j=(await window.dataverseAPI.queryData(`sdkmessageresponses?$select=sdkmessageresponseid&$filter=_sdkmessagerequestid_value eq ${k}&$top=1`)).value;let L=[];if(j.length){const g=j[0].sdkmessageresponseid;L=(await window.dataverseAPI.queryData(`sdkmessageresponsefields?$select=name,clrformatter,position&$filter=_sdkmessageresponseid_value eq ${g}&$orderby=position`)).value}return{Request:{Name:l,Fields:v.value.map(g=>({Name:g.name??"",ClrFormatter:g.clrparser,IsOptional:g.optional??!1,Index:g.position}))},Response:{Fields:L.map(g=>({Name:g.name??"",ClrFormatter:g.clrformatter,Index:g.position}))}}}catch{return null}}const is="DLaB.EarlyBoundGeneratorV2.DefaultSettings.xml";function bf(){const[l,o]=ve.useState(Fc),[a,p]=ve.useState(""),[f,d]=ve.useState(is),[c,k]=ve.useState([]),[v,m]=ve.useState(""),[j,L]=ve.useState(!1),[g,I]=ve.useState(""),[q,D]=ve.useState(!0),[Q,Se]=ve.useState(!1),[se,pe]=ve.useState(null),A=S=>{o(fe=>({...fe,...S}))},ee=ve.useCallback(async(S,fe)=>{if(window.toolboxAPI)try{const xe=await window.toolboxAPI.fileSystem.readText(Ke(S,fe)),{settings:Ee}=tf(xe);o(Ee),d(fe),I("")}catch(xe){const Ee=Jn(xe);I(`Failed to load settings: ${Ee}`)}},[]),Ne=ve.useCallback(async S=>{if(window.toolboxAPI)try{const xe=(await window.toolboxAPI.fileSystem.readDirectory(S)).filter(Ee=>Ee.type==="file"&&Ee.name.toLowerCase().endsWith(".xml")).map(Ee=>Ee.name);p(S),k([]),xe.length===0?(d(is),I("")):xe.length===1?await ee(S,xe[0]):k(xe)}catch(fe){const xe=Jn(fe);I(`Failed to read directory: ${xe}`)}},[ee]);ve.useEffect(()=>{(async()=>{if(!window.toolboxAPI){I("Power Platform ToolBox context not detected. Launch this tool inside PPTB."),D(!1);return}D(!1)})()},[Ne]);const z=async()=>{if(window.toolboxAPI)try{const S=await window.toolboxAPI.fileSystem.selectPath({type:"folder",title:"Select EBG Settings Folder"});if(!S)return;await Ne(S)}catch(S){const fe=Jn(S);I(fe)}},ie=async()=>{if(!window.toolboxAPI)return;const S=Sc(l,"0.0.4");try{if(a){const fe=Ke(a,f);await window.toolboxAPI.fileSystem.writeText(fe,S),await window.toolboxAPI.utils.showNotification({title:"Saved",body:fe,type:"success"})}else{const fe=await window.toolboxAPI.fileSystem.saveFile(is,S,[{name:"XML files",extensions:["xml"]}]);if(fe){const xe=nf(fe),Ee=fe.replace(/^.*[/\\]/,"");p(xe),d(Ee)}}}catch(fe){const xe=Jn(fe);I(xe)}},le=async()=>{if(!window.toolboxAPI){I("Power Platform ToolBox context not detected.");return}if(!a){I("Open a settings folder before generating.");return}L(!0),I(""),m("");try{const S=await window.toolboxAPI.connections.getActiveConnection();if(!(S!=null&&S.url)){I("No active Dataverse connection. Connect to an environment in PPTB first."),L(!1);return}const fe=Ke(a,f);await window.toolboxAPI.fileSystem.writeText(fe,Sc(l,"0.0.4"));const xe=l.outputRelativeDirectory?Ke(a,l.outputRelativeDirectory):a;await Rf(l,a,xe,Oe=>{m(b=>b?b+`
83
- `+Oe:Oe)},"0.0.4"),await window.toolboxAPI.utils.showNotification({title:"Generation complete",body:`Output written to ${xe}`,type:"success"})}catch(S){const fe=Jn(S);I(fe),m(fe)}finally{L(!1)}},re=S=>{pe(S),Se(!0)},Ce=S=>{se==="entitiesWhitelist"?A({entitiesWhitelist:S}):se==="entitiesToSkip"&&A({entitiesToSkip:S}),Se(!1),pe(null)},Xe=()=>{Se(!1),pe(null)};return q?h.jsxs("div",{className:"loading-container",children:[h.jsx("div",{className:"loading-spinner"}),h.jsx("span",{children:"Loading..."})]}):h.jsxs("div",{className:"page-layout",children:[h.jsx(rf,{isGenerating:j,settingsPath:a?Ke(a,f):"",onOpenSettings:z,onSaveSettings:ie}),g&&h.jsx("div",{className:"error-banner",children:g}),h.jsxs("div",{className:"content-area",children:[h.jsxs("div",{className:"settings-panel",children:[h.jsxs(Yn,{title:"Global",children:[h.jsx(ue,{label:"Namespace",hint:"C# namespace for all generated classes",children:h.jsx("input",{className:"form-input",value:l.namespace,onChange:S=>A({namespace:S.target.value})})}),h.jsx(ue,{label:"Service Context Name",hint:"Name of the generated IOrganizationService context class",children:h.jsx("input",{className:"form-input",value:l.serviceContextName,onChange:S=>A({serviceContextName:S.target.value})})}),h.jsx(ue,{label:"Output Directory",hint:"Directory for generated files — relative to the settings file",children:h.jsx(ts,{value:l.outputRelativeDirectory,onChange:S=>A({outputRelativeDirectory:S}),settingsDir:a,type:"folder",placeholder:"(same folder as settings file)",title:"Select output directory"})}),h.jsx(ue,{label:"Builder Settings JSON Path",hint:"Path for the builderSettings.json file written before pac modelbuilder runs",children:h.jsx(ts,{value:l.builderSettingsJsonRelativePath,onChange:S=>A({builderSettingsJsonRelativePath:S}),settingsDir:a,type:"file",filters:[{name:"JSON files",extensions:["json"]}],title:"Select builder settings JSON file"})}),h.jsx(ne,{label:"Suppress Generated Code Attribute",hint:"Omit [System.CodeDom.Compiler.GeneratedCode] from generated files",checked:l.suppressGeneratedCodeAttribute,onChange:S=>A({suppressGeneratedCodeAttribute:S})}),h.jsx(ne,{label:"Remove Runtime Version Comment",hint:"Strip the runtime version comment from generated file headers",checked:l.removeRuntimeVersionComment,onChange:S=>A({removeRuntimeVersionComment:S})}),h.jsx(ne,{label:"Suppress Auto-Generated File Header",hint:"Suppress the auto-generated file header comment entirely",checked:l.suppressAutogeneratedFileHeaderComment,onChange:S=>A({suppressAutogeneratedFileHeaderComment:S})}),h.jsx(ne,{label:"Generate Types As Internal",hint:"Emit all generated types with internal rather than public visibility",checked:l.generateTypesAsInternal,onChange:S=>A({generateTypesAsInternal:S})}),h.jsx(ne,{label:"Include Command Line",hint:"Embed the pac command line in generated file headers",checked:l.includeCommandLine,onChange:S=>A({includeCommandLine:S})}),h.jsx(ue,{label:"File Prefix Text",hint:"Text prepended to every generated file name",children:h.jsx("input",{className:"form-input",value:l.filePrefixText,placeholder:"(none)",onChange:S=>A({filePrefixText:S.target.value})})}),h.jsx(ne,{label:"Make Reference Types Nullable",hint:"Add C# nullable annotations to reference-type properties",checked:l.makeReferenceTypesNullable,onChange:S=>A({makeReferenceTypesNullable:S})}),h.jsx(ne,{label:"Use Display Name For BPF Name",hint:"Use the display name when naming Business Process Flow entities",checked:l.useDisplayNameForBpfName,onChange:S=>A({useDisplayNameForBpfName:S})}),h.jsx(ne,{label:"Add New Files To Project",hint:"Add newly generated .cs files to the target .csproj automatically",checked:l.addNewFilesToProject,onChange:S=>A({addNewFilesToProject:S})}),h.jsx(ne,{label:"Delete Files From Output Folders",hint:"Remove stale generated files from output folders",checked:l.deleteFilesFromOutputFolders,onChange:S=>A({deleteFilesFromOutputFolders:S})}),h.jsx(ue,{label:"Project Name For Early-Bound Files",hint:".csproj name to add generated files to (leave blank to auto-detect)",children:h.jsx("input",{className:"form-input",value:l.projectNameForEarlyBoundFiles,placeholder:"(auto-detect)",onChange:S=>A({projectNameForEarlyBoundFiles:S.target.value})})}),h.jsx(ue,{label:"Token Capitalisation Overrides",hint:"Words treated as known tokens during CamelCase naming (e.g. SlaId, VoiceMail)",children:h.jsx(Nt,{items:l.tokenCapitalizationOverrides,onChange:S=>A({tokenCapitalizationOverrides:S}),placeholder:"Add token..."})}),h.jsx(ne,{label:"CamelCase Class Names",hint:"Apply CamelCase formatting to generated class names",checked:l.camelCaseClassNames,onChange:S=>A({camelCaseClassNames:S})}),h.jsx(ne,{label:"CamelCase Member Names",hint:"Apply CamelCase formatting to generated property and member names",checked:l.camelCaseMemberNames,onChange:S=>A({camelCaseMemberNames:S})}),h.jsx(ue,{label:"CamelCase Custom Words",hint:"Additional words recognised as tokens during CamelCase naming",children:h.jsx(Nt,{items:l.camelCaseCustomWords,onChange:S=>A({camelCaseCustomWords:S}),placeholder:"Add word..."})}),h.jsx(ue,{label:"CamelCase Dictionary Path",hint:"Relative path to a custom CamelCase dictionary file. Leave blank to use the built-in dictionary.",children:h.jsx(ts,{value:l.camelCaseNamesDictionaryRelativePath,onChange:S=>A({camelCaseNamesDictionaryRelativePath:S}),settingsDir:a,type:"file",filters:[{name:"Text files",extensions:["txt"]}],placeholder:"(built-in dictionary)",title:"Select CamelCase dictionary file"})})]}),h.jsxs(Yn,{title:"Entities",children:[h.jsx(ue,{label:"Entity Types Folder",hint:"Sub-folder name for generated entity class files",children:h.jsx("input",{className:"form-input",value:l.entityTypesFolder,onChange:S=>A({entityTypesFolder:S.target.value})})}),h.jsx(ne,{label:"One File Per Entity",hint:"Emit a separate .cs file for each entity (vs a single combined file)",checked:l.createOneFilePerEntity,onChange:S=>A({createOneFilePerEntity:S})}),h.jsx(ue,{label:"Entities Whitelist",hint:"Generate only these entities — leave empty to generate all entities",children:h.jsxs("div",{className:"entity-picker-row",children:[h.jsx(Nt,{items:l.entitiesWhitelist,onChange:S=>A({entitiesWhitelist:S}),placeholder:"Add entity logical name..."}),h.jsx("button",{className:"entity-picker-btn",onClick:()=>re("entitiesWhitelist"),children:"Browse Entities"})]})}),h.jsx(ue,{label:"Entities To Skip",hint:"Always exclude these entities even when they appear in other filters",children:h.jsxs("div",{className:"entity-picker-row",children:[h.jsx(Nt,{items:l.entitiesToSkip,onChange:S=>A({entitiesToSkip:S}),placeholder:"Add entity logical name..."}),h.jsx("button",{className:"entity-picker-btn",onClick:()=>re("entitiesToSkip"),children:"Browse Entities"})]})}),h.jsx(ue,{label:"Entity Prefixes To Skip",hint:"Skip all entities whose logical name starts with these prefixes",children:h.jsx(Nt,{items:l.entityPrefixesToSkip,onChange:S=>A({entityPrefixesToSkip:S}),placeholder:"Add prefix..."})}),h.jsx(ue,{label:"Entity Prefixes Whitelist",hint:"Only generate entities whose logical name starts with these prefixes",children:h.jsx(Nt,{items:l.entityPrefixesWhitelist,onChange:S=>A({entityPrefixesWhitelist:S}),placeholder:"Add prefix..."})}),h.jsx(ue,{label:"Entity Class Name Overrides",hint:"Map entity logical names to custom C# class names",children:h.jsx(sa,{entries:l.entityClassNameOverrides,onChange:S=>A({entityClassNameOverrides:S}),keyHeader:"Logical Name",valueHeader:"Class Name",keyPlaceholder:"e.g. account",valuePlaceholder:"e.g. MyAccount"})}),h.jsx(ue,{label:"Entity Attribute Specified Names",hint:"For each entity, limit generation to only these attributes. Leave empty to generate all attributes.",children:h.jsx(uf,{entries:l.entityAttributeSpecifiedNames,onChange:S=>A({entityAttributeSpecifiedNames:S})})}),h.jsx(ue,{label:"Attribute Blacklist",hint:"Attribute logical names to always exclude across all entities",children:h.jsx(Nt,{items:l.attributeBlacklist,onChange:S=>A({attributeBlacklist:S}),placeholder:"Add attribute logical name..."})}),h.jsx(ne,{label:"Generate Attribute Name Consts",hint:"Generate a Fields inner class with attribute logical name string constants",checked:l.generateAttributeNameConsts,onChange:S=>A({generateAttributeNameConsts:S})}),h.jsx(ne,{label:"Generate Anonymous Type Constructor",hint:"Generate a constructor that accepts an anonymous type initialiser",checked:l.generateAnonymousTypeConstructor,onChange:S=>A({generateAnonymousTypeConstructor:S})}),h.jsx(ne,{label:"Generate Constructors Sans Logical Name",hint:"Generate constructors that do not require the entity logical name argument",checked:l.generateConstructorsSansLogicalName,onChange:S=>A({generateConstructorsSansLogicalName:S})}),h.jsx(ne,{label:"Generate Entity Relationships",hint:"Generate relationship navigation properties on entity classes",checked:l.generateEntityRelationships,onChange:S=>A({generateEntityRelationships:S})}),h.jsx(ne,{label:"Generate Enum Properties",hint:"Generate typed enum properties for option set attributes",checked:l.generateEnumProperties,onChange:S=>A({generateEnumProperties:S})}),h.jsx(ne,{label:"Replace Option Set Properties With Enum",hint:"Replace OptionSetValue properties with the generated enum type",checked:l.replaceOptionSetPropertiesWithEnum,onChange:S=>A({replaceOptionSetPropertiesWithEnum:S})}),h.jsx(ne,{label:"Generate INotify Pattern",hint:"Implement INotifyPropertyChanged on all entity classes",checked:l.generateINotifyPattern,onChange:S=>A({generateINotifyPattern:S})}),h.jsx(ne,{label:"Emit Virtual Attributes",hint:"Include virtual/composite attributes (e.g. fullname) in generated classes",checked:l.emitVirtualAttributes,onChange:S=>A({emitVirtualAttributes:S})}),h.jsx(ne,{label:"Emit Entity ETC",hint:"Emit the entity type code constant in generated classes",checked:l.emitEntityETC,onChange:S=>A({emitEntityETC:S})}),h.jsx(ne,{label:"Make All Fields Editable",hint:"Generate all fields (including calculated/rollup) as settable properties",checked:l.makeAllFieldsEditable,onChange:S=>A({makeAllFieldsEditable:S})}),h.jsx(ne,{label:"Make Read-Only Fields Editable",hint:"Generate read-only fields as settable properties",checked:l.makeReadonlyFieldsEditable,onChange:S=>A({makeReadonlyFieldsEditable:S})}),h.jsx(ne,{label:"Use Logical Names",hint:"Name generated properties using attribute logical names instead of schema names",checked:l.useLogicalNames,onChange:S=>A({useLogicalNames:S})}),h.jsx(ne,{label:"Use Enum For State Codes",hint:"Generate enums for statecode and statuscode attributes",checked:l.useEnumForStateCodes,onChange:S=>A({useEnumForStateCodes:S})}),h.jsx(ne,{label:"Use CrmSvcUtil State Enum Naming",hint:"Use CrmSvcUtil-compatible naming convention for state/status enums",checked:l.useCrmSvcUtilStateEnumNamingConvention,onChange:S=>A({useCrmSvcUtilStateEnumNamingConvention:S})}),h.jsx(ne,{label:"Obsolete Deprecated",hint:"Mark deprecated entities and attributes with [Obsolete]",checked:l.obsoleteDeprecated,onChange:S=>A({obsoleteDeprecated:S})}),h.jsx(ue,{label:"Obsolete Tokens",hint:"Display name tokens that flag deprecation (e.g. *(Deprecated)*)",children:h.jsx(Nt,{items:l.obsoleteTokens,onChange:S=>A({obsoleteTokens:S}),placeholder:"Add token..."})}),h.jsx(ue,{label:"Property Enum Mappings",hint:"Manual enum-to-property mappings (format: EntityName.PropertyName=EnumType)",children:h.jsx(Nt,{items:l.propertyEnumMappings,onChange:S=>A({propertyEnumMappings:S}),placeholder:"Add mapping..."})}),h.jsx(ne,{label:"Add Debugger Non-User Code",hint:"Apply [DebuggerNonUserCode] to suppress stepping into generated code",checked:l.addDebuggerNonUserCode,onChange:S=>A({addDebuggerNonUserCode:S})})]}),h.jsxs(Yn,{title:"Option Sets",children:[h.jsx(ue,{label:"Option Sets Folder",hint:"Sub-folder name for generated option set enum files",children:h.jsx("input",{className:"form-input",value:l.optionSetsTypesFolder,onChange:S=>A({optionSetsTypesFolder:S.target.value})})}),h.jsx(ne,{label:"One File Per Option Set",hint:"Emit a separate .cs file for each option set enum",checked:l.createOneFilePerOptionSet,onChange:S=>A({createOneFilePerOptionSet:S})}),h.jsx(ne,{label:"Generate Global Option Sets",hint:"Include global (not entity-local) option sets in the output",checked:l.generateGlobalOptionSets,onChange:S=>A({generateGlobalOptionSets:S})}),h.jsx(ne,{label:"Generate Option Set Metadata Attribute",hint:"Generate metadata attributes on generated enum values",checked:l.generateOptionSetMetadataAttribute,onChange:S=>A({generateOptionSetMetadataAttribute:S})}),h.jsx(ne,{label:"Add Option Set Metadata Attribute",hint:"Apply [OptionSetMetadataAttribute] to generated enums",checked:l.addOptionSetMetadataAttribute,onChange:S=>A({addOptionSetMetadataAttribute:S})}),h.jsx(ne,{label:"Generate All Option Set Label Metadata",hint:"Include all language labels for option set values (not just the default language)",checked:l.generateAllOptionSetLabelMetadata,onChange:S=>A({generateAllOptionSetLabelMetadata:S})}),h.jsx(ne,{label:"Adjust Casing For Enum Options",hint:"Apply CamelCase formatting to enum value names",checked:l.adjustCasingForEnumOptions,onChange:S=>A({adjustCasingForEnumOptions:S})}),h.jsx(ne,{label:"Group Local Option Sets By Entity",hint:"Place local option sets inside an entity-named sub-namespace",checked:l.groupLocalOptionSetsByEntity,onChange:S=>A({groupLocalOptionSetsByEntity:S})}),h.jsx(ne,{label:"Cleanup CrmSvcUtil Local Option Sets",hint:"Remove old CrmSvcUtil-generated local option set files on regeneration",checked:l.cleanupCrmSvcUtilLocalOptionSets,onChange:S=>A({cleanupCrmSvcUtilLocalOptionSets:S})}),h.jsx(ue,{label:"Invalid C# Name Prefix",hint:"Prefix applied to enum values that start with an invalid C# identifier character",children:h.jsx("input",{className:"form-input",value:l.invalidCSharpNamePrefix,onChange:S=>A({invalidCSharpNamePrefix:S.target.value})})}),h.jsx(ue,{label:"Local Option Set Format",hint:"Format string for local option set names: {0}=entity name, {1}=attribute name",children:h.jsx("input",{className:"form-input",value:l.localOptionSetFormat,onChange:S=>A({localOptionSetFormat:S.target.value})})}),h.jsx(ue,{label:"Language Code Override",hint:"Override the language code used for option set labels (blank = environment default)",children:h.jsx("input",{type:"number",className:"form-input",value:l.optionSetLanguageCodeOverride??"",placeholder:"(environment default)",onChange:S=>A({optionSetLanguageCodeOverride:S.target.value?parseInt(S.target.value,10):null})})}),h.jsx(ue,{label:"Option Set Names",hint:"Override the generated C# name for a conflicting option set. Key: generated name (lowercase). Value: replacement class name.",children:h.jsx(sa,{entries:l.optionSetNames,onChange:S=>A({optionSetNames:S}),keyHeader:"Option Set Name",valueHeader:"Class Name",keyPlaceholder:"e.g. account_rating",valuePlaceholder:"e.g. AccountRating"})}),h.jsx(ue,{label:"Option Name Overrides",hint:"Fix casing of enum member name tokens. Key: lowercase token to match. Value: correctly-cased replacement (e.g. fedex → FedEx).",children:h.jsx(sa,{entries:l.optionNameOverrides,onChange:S=>A({optionNameOverrides:S}),keyHeader:"Token (lowercase)",valueHeader:"Replacement",keyPlaceholder:"e.g. fedex",valuePlaceholder:"e.g. FedEx"})}),h.jsx(ue,{label:"Transliteration Path",hint:"Relative path to a transliteration file for non-Latin characters",children:h.jsx(ts,{value:l.transliterationRelativePath,onChange:S=>A({transliterationRelativePath:S}),settingsDir:a,type:"file",placeholder:"(none)",title:"Select transliteration file"})})]}),h.jsxs(Yn,{title:"Messages",children:[h.jsx(ne,{label:"Generate Messages",hint:"Generate Request/Response classes for Dataverse messages, Actions, and Custom APIs",checked:l.generateMessages,onChange:S=>A({generateMessages:S})}),h.jsx(ue,{label:"Message Types Folder",hint:"Sub-folder name for generated message class files",children:h.jsx("input",{className:"form-input",value:l.messageTypesFolder,onChange:S=>A({messageTypesFolder:S.target.value})})}),h.jsx(ne,{label:"One File Per Message",hint:"Emit a separate .cs file for each message",checked:l.createOneFilePerMessage,onChange:S=>A({createOneFilePerMessage:S})}),h.jsx(ue,{label:"Messages Whitelist",hint:"Only generate these messages — leave empty to generate all messages",children:h.jsx(Nt,{items:l.messagesWhitelist,onChange:S=>A({messagesWhitelist:S}),placeholder:"Add message name..."})}),h.jsx(ue,{label:"Messages To Skip",hint:"Always exclude these messages from generation",children:h.jsx(Nt,{items:l.messagesToSkip,onChange:S=>A({messagesToSkip:S}),placeholder:"Add message name..."})}),h.jsx(ue,{label:"Message Prefixes Whitelist",hint:"Only generate messages whose name starts with these prefixes",children:h.jsx(Nt,{items:l.messagePrefixesWhitelist,onChange:S=>A({messagePrefixesWhitelist:S}),placeholder:"Add prefix..."})}),h.jsx(ne,{label:"Group Request With Response",hint:"Place Request and Response classes in the same generated file",checked:l.groupMessageRequestWithResponse,onChange:S=>A({groupMessageRequestWithResponse:S})}),h.jsx(ne,{label:"Generate Message Attribute Name Consts",hint:"Generate a Fields inner class for message parameter name constants",checked:l.generateMessageAttributeNameConsts,onChange:S=>A({generateMessageAttributeNameConsts:S})}),h.jsx(ne,{label:"Make Response Messages Editable",hint:"Generate settable properties on Response message classes",checked:l.makeResponseMessagesEditable,onChange:S=>A({makeResponseMessagesEditable:S})})]}),h.jsxs(Yn,{title:"Service Classes",defaultExpanded:!1,children:[h.jsxs("div",{className:"prop-row",children:[h.jsx("div",{}),h.jsx("p",{className:"form-hint",children:"These values are saved to the settings file for compatibility with XrmToolBox EarlyBoundGeneratorV2 but have no effect on code generation in Power Platform ToolBox, which implements generation directly without calling PAC CLI."})]}),h.jsx(ue,{label:"Code Customisation Service",hint:"Assembly-qualified type name for DLaB.ModelBuilderExtensions.CustomizeCodeDomService",children:h.jsx("input",{className:"form-input",value:l.codeCustomizationService,onChange:S=>A({codeCustomizationService:S.target.value})})}),h.jsx(ue,{label:"Code Generation Service",hint:"Assembly-qualified type name for the code generation service",children:h.jsx("input",{className:"form-input",value:l.codeGenerationService,onChange:S=>A({codeGenerationService:S.target.value})})}),h.jsx(ue,{label:"Code Writer Filter Service",hint:"Assembly-qualified type name for the code writer filter service",children:h.jsx("input",{className:"form-input",value:l.codeWriterFilterService,onChange:S=>A({codeWriterFilterService:S.target.value})})}),h.jsx(ue,{label:"Code Writer Message Filter Service",hint:"Assembly-qualified type name for the message filter service",children:h.jsx("input",{className:"form-input",value:l.codeWriterMessageFilterService,onChange:S=>A({codeWriterMessageFilterService:S.target.value})})}),h.jsx(ue,{label:"Metadata Provider Service",hint:"Assembly-qualified type name for the metadata provider service",children:h.jsx("input",{className:"form-input",value:l.metadataProviderService,onChange:S=>A({metadataProviderService:S.target.value})})}),h.jsx(ue,{label:"Metadata Query Provider Service",hint:"Assembly-qualified type name for the metadata query provider service",children:h.jsx("input",{className:"form-input",value:l.metadataQueryProviderService,onChange:S=>A({metadataQueryProviderService:S.target.value})})}),h.jsx(ue,{label:"Naming Service",hint:"Assembly-qualified type name for the naming service",children:h.jsx("input",{className:"form-input",value:l.namingService,onChange:S=>A({namingService:S.target.value})})})]}),h.jsxs(Yn,{title:"Debug",defaultExpanded:!1,children:[h.jsx(ue,{label:"Model Builder Log Level",hint:"Verbosity for pac modelbuilder logging: 0 = quiet, 5 = verbose",children:h.jsx("input",{className:"form-input",value:l.modelBuilderLogLevel,onChange:S=>A({modelBuilderLogLevel:S.target.value})})}),h.jsx(ne,{label:"Update Builder Settings JSON",hint:"Write the builderSettings.json file before running pac modelbuilder",checked:l.updateBuilderSettingsJson,onChange:S=>A({updateBuilderSettingsJson:S})}),h.jsx(ne,{label:"Read Serialised Metadata",hint:"Read metadata from a previously serialised file instead of from Dataverse",checked:l.readSerializedMetadata,onChange:S=>A({readSerializedMetadata:S})}),h.jsx(ne,{label:"Serialise Metadata",hint:"Write the retrieved metadata to disk for use with Read Serialised Metadata",checked:l.serializeMetadata,onChange:S=>A({serializeMetadata:S})}),h.jsx(ne,{label:"Wait For Attached Debugger",hint:"Pause pac modelbuilder at startup until a .NET debugger attaches",checked:l.waitForAttachedDebugger,onChange:S=>A({waitForAttachedDebugger:S})})]})]}),h.jsx(sf,{output:v,onClear:()=>m(""),onCopy:()=>{var S;(S=window.toolboxAPI)==null||S.utils.copyToClipboard(v)}})]}),h.jsx("div",{className:"bottom-bar",children:h.jsx("button",{className:"toolbar-btn primary",onClick:le,disabled:j,title:"Generate early-bound classes",children:j?h.jsxs(h.Fragment,{children:[h.jsx("span",{className:"toolbar-spinner"}),"Generating..."]}):"Generate"})}),h.jsx(of,{isOpen:Q,selectedEntities:se?l[se]:[],onConfirm:Ce,onClose:Xe}),c.length>0&&h.jsx("div",{className:"dialog-overlay",children:h.jsxs("div",{className:"dialog",style:{width:380},children:[h.jsx("div",{className:"dialog-header",children:h.jsx("span",{style:{fontWeight:600,fontSize:13},children:"Multiple XML files found"})}),h.jsxs("div",{className:"dialog-body",children:[h.jsx("p",{style:{margin:"0 0 10px",fontSize:12,color:"var(--text-secondary)"},children:"Select which settings file to load:"}),h.jsx("div",{className:"string-list",children:c.map(S=>h.jsxs("label",{className:"string-list-item",style:{cursor:"pointer",gap:8},children:[h.jsx("input",{type:"radio",name:"xml-pick",value:S,onChange:()=>{k([]),ee(a,S)}}),S]},S))})]}),h.jsx("div",{className:"dialog-footer",children:h.jsx("button",{className:"btn-secondary",onClick:()=>{k([]),d(is)},children:"Use Defaults"})})]})})]})}const Ic=l=>{l==="dark"?document.body.classList.add("dark-theme"):document.body.classList.remove("dark-theme")},bc=async()=>{if(window.toolboxAPI){const l=await window.toolboxAPI.utils.getCurrentTheme();Ic(l)}},zf=(l,o)=>{var f;const a=o;if(a.event!=="settings:updated")return;const p=(f=a.data)==null?void 0:f.theme;p?Ic(p):bc()},Bf=()=>{window.toolboxAPI&&window.toolboxAPI.events.on(zf)};bc();Bf();Hp.createRoot(document.getElementById("root")).render(h.jsx(ve.StrictMode,{children:h.jsx(bf,{})}));
82
+ `),p)}const se=ca(l.optionSetsTypesFolder,"OptionSet.cs"),pe=se.dir?Ke(a,se.dir):a,A=Af(q,l);if(l.createOneFilePerOptionSet)if(p(`--- Option Sets (${A.length}) ---`),l.groupLocalOptionSetsByEntity){const z=new Map;for(const{entity:ie,optionSet:le}of A){const re=(ie==null?void 0:ie.LogicalName)??"__global__";z.has(re)||z.set(re,[]),z.get(re).push(le)}for(const[ie,le]of z){const re=ie!=="__global__"?I.get(ie.toLowerCase())??null:null,Ce=re?v.getNameForEntity(re):"GlobalOptionSets",Xe=Pf(re??{LogicalName:"global",SchemaName:"global",DisplayName:{LocalizedLabels:[]},Attributes:[]},le,v,l,f);await cn(Ke(pe,`${Ce}.cs`),Xe,p)}}else for(const{entity:z,optionSet:ie}of A){const le=v.getNameForOptionSet(z,ie),re=Of(z,ie,v,l,f);await cn(Ke(pe,`${le}.cs`),re,p)}else{p("--- Option Sets (combined) ---");const z=$f(A,v,l,f);await cn(Ke(pe,se.filename),z,p)}p("--- Service Context ---");const ee=Lf(q,v,l,f);if(await cn(Ke(a,`${l.serviceContextName}.cs`),ee,p),l.generateMessages){const z=await _f(l,m,p),ie=ca(l.messageTypesFolder,"Messages.cs"),le=ie.dir?Ke(a,ie.dir):a;if(z.length>0)if(l.createOneFilePerMessage){p(`--- Messages (${z.length}) ---`);for(const re of z){const Ce=_c(re,l,f,v),Xe=v.camelCase(re.Request.Name);await cn(Ke(le,`${Xe}.cs`),Ce,p)}}else{p("--- Messages (combined) ---");const re=Mf(z,l,f,v);await cn(Ke(le,ie.filename),re,p)}else p(" No messages matched the filter.")}p("=== Generation Complete ===")}async function _f(l,o,a){try{const p=Df(l),f=`sdkmessages?$select=name,sdkmessageid&$filter=${encodeURIComponent(p)}&$top=500`,c=(await window.dataverseAPI.queryData(f)).value,k=[];for(const v of c){const m=v.name;if(!o.shouldGenerateMessage(m))continue;const j=await If(m,v.sdkmessageid);j&&k.push(j)}return k}catch(p){return a(` Warning: Could not fetch SDK messages: ${Jn(p)}`),[]}}function Df(l){return l.messagesWhitelist.length>0?l.messagesWhitelist.map(a=>`name eq '${a.replace(/'/g,"''")}'`).join(" or "):"autotransact eq true"}async function If(l,o){try{const p=(await window.dataverseAPI.queryData(`sdkmessagepairs?$select=sdkmessagepairid&$filter=_sdkmessageid_value eq ${o}&$top=1`)).value;if(!p.length)return null;const f=p[0].sdkmessagepairid,c=(await window.dataverseAPI.queryData(`sdkmessagerequests?$select=sdkmessagerequestid&$filter=_sdkmessagepairid_value eq ${f}&$top=1`)).value;if(!c.length)return null;const k=c[0].sdkmessagerequestid,v=await window.dataverseAPI.queryData(`sdkmessagerequestfields?$select=name,clrparser,optional,position&$filter=_sdkmessagerequestid_value eq ${k}&$orderby=position`),j=(await window.dataverseAPI.queryData(`sdkmessageresponses?$select=sdkmessageresponseid&$filter=_sdkmessagerequestid_value eq ${k}&$top=1`)).value;let L=[];if(j.length){const g=j[0].sdkmessageresponseid;L=(await window.dataverseAPI.queryData(`sdkmessageresponsefields?$select=name,clrformatter,position&$filter=_sdkmessageresponseid_value eq ${g}&$orderby=position`)).value}return{Request:{Name:l,Fields:v.value.map(g=>({Name:g.name??"",ClrFormatter:g.clrparser,IsOptional:g.optional??!1,Index:g.position}))},Response:{Fields:L.map(g=>({Name:g.name??"",ClrFormatter:g.clrformatter,Index:g.position}))}}}catch{return null}}const is="DLaB.EarlyBoundGeneratorV2.DefaultSettings.xml";function bf(){const[l,o]=ve.useState(Fc),[a,p]=ve.useState(""),[f,d]=ve.useState(is),[c,k]=ve.useState([]),[v,m]=ve.useState(""),[j,L]=ve.useState(!1),[g,I]=ve.useState(""),[q,D]=ve.useState(!0),[Q,Se]=ve.useState(!1),[se,pe]=ve.useState(null),A=S=>{o(fe=>({...fe,...S}))},ee=ve.useCallback(async(S,fe)=>{if(window.toolboxAPI)try{const xe=await window.toolboxAPI.fileSystem.readText(Ke(S,fe)),{settings:Ee}=tf(xe);o(Ee),d(fe),I("")}catch(xe){const Ee=Jn(xe);I(`Failed to load settings: ${Ee}`)}},[]),Ne=ve.useCallback(async S=>{if(window.toolboxAPI)try{const xe=(await window.toolboxAPI.fileSystem.readDirectory(S)).filter(Ee=>Ee.type==="file"&&Ee.name.toLowerCase().endsWith(".xml")).map(Ee=>Ee.name);p(S),k([]),xe.length===0?(d(is),I("")):xe.length===1?await ee(S,xe[0]):k(xe)}catch(fe){const xe=Jn(fe);I(`Failed to read directory: ${xe}`)}},[ee]);ve.useEffect(()=>{(async()=>{if(!window.toolboxAPI){I("Power Platform ToolBox context not detected. Launch this tool inside PPTB."),D(!1);return}D(!1)})()},[Ne]);const z=async()=>{if(window.toolboxAPI)try{const S=await window.toolboxAPI.fileSystem.selectPath({type:"folder",title:"Select EBG Settings Folder"});if(!S)return;await Ne(S)}catch(S){const fe=Jn(S);I(fe)}},ie=async()=>{if(!window.toolboxAPI)return;const S=Sc(l,"0.0.6");try{if(a){const fe=Ke(a,f);await window.toolboxAPI.fileSystem.writeText(fe,S),await window.toolboxAPI.utils.showNotification({title:"Saved",body:fe,type:"success"})}else{const fe=await window.toolboxAPI.fileSystem.saveFile(is,S,[{name:"XML files",extensions:["xml"]}]);if(fe){const xe=nf(fe),Ee=fe.replace(/^.*[/\\]/,"");p(xe),d(Ee)}}}catch(fe){const xe=Jn(fe);I(xe)}},le=async()=>{if(!window.toolboxAPI){I("Power Platform ToolBox context not detected.");return}if(!a){I("Open a settings folder before generating.");return}L(!0),I(""),m("");try{const S=await window.toolboxAPI.connections.getActiveConnection();if(!(S!=null&&S.url)){I("No active Dataverse connection. Connect to an environment in PPTB first."),L(!1);return}const fe=Ke(a,f);await window.toolboxAPI.fileSystem.writeText(fe,Sc(l,"0.0.6"));const xe=l.outputRelativeDirectory?Ke(a,l.outputRelativeDirectory):a;await Rf(l,a,xe,Oe=>{m(b=>b?b+`
83
+ `+Oe:Oe)},"0.0.6"),await window.toolboxAPI.utils.showNotification({title:"Generation complete",body:`Output written to ${xe}`,type:"success"})}catch(S){const fe=Jn(S);I(fe),m(fe)}finally{L(!1)}},re=S=>{pe(S),Se(!0)},Ce=S=>{se==="entitiesWhitelist"?A({entitiesWhitelist:S}):se==="entitiesToSkip"&&A({entitiesToSkip:S}),Se(!1),pe(null)},Xe=()=>{Se(!1),pe(null)};return q?h.jsxs("div",{className:"loading-container",children:[h.jsx("div",{className:"loading-spinner"}),h.jsx("span",{children:"Loading..."})]}):h.jsxs("div",{className:"page-layout",children:[h.jsx(rf,{isGenerating:j,settingsPath:a?Ke(a,f):"",onOpenSettings:z,onSaveSettings:ie}),g&&h.jsx("div",{className:"error-banner",children:g}),h.jsxs("div",{className:"content-area",children:[h.jsxs("div",{className:"settings-panel",children:[h.jsxs(Yn,{title:"Global",children:[h.jsx(ue,{label:"Namespace",hint:"C# namespace for all generated classes",children:h.jsx("input",{className:"form-input",value:l.namespace,onChange:S=>A({namespace:S.target.value})})}),h.jsx(ue,{label:"Service Context Name",hint:"Name of the generated IOrganizationService context class",children:h.jsx("input",{className:"form-input",value:l.serviceContextName,onChange:S=>A({serviceContextName:S.target.value})})}),h.jsx(ue,{label:"Output Directory",hint:"Directory for generated files — relative to the settings file",children:h.jsx(ts,{value:l.outputRelativeDirectory,onChange:S=>A({outputRelativeDirectory:S}),settingsDir:a,type:"folder",placeholder:"(same folder as settings file)",title:"Select output directory"})}),h.jsx(ue,{label:"Builder Settings JSON Path",hint:"Path for the builderSettings.json file written before pac modelbuilder runs",children:h.jsx(ts,{value:l.builderSettingsJsonRelativePath,onChange:S=>A({builderSettingsJsonRelativePath:S}),settingsDir:a,type:"file",filters:[{name:"JSON files",extensions:["json"]}],title:"Select builder settings JSON file"})}),h.jsx(ne,{label:"Suppress Generated Code Attribute",hint:"Omit [System.CodeDom.Compiler.GeneratedCode] from generated files",checked:l.suppressGeneratedCodeAttribute,onChange:S=>A({suppressGeneratedCodeAttribute:S})}),h.jsx(ne,{label:"Remove Runtime Version Comment",hint:"Strip the runtime version comment from generated file headers",checked:l.removeRuntimeVersionComment,onChange:S=>A({removeRuntimeVersionComment:S})}),h.jsx(ne,{label:"Suppress Auto-Generated File Header",hint:"Suppress the auto-generated file header comment entirely",checked:l.suppressAutogeneratedFileHeaderComment,onChange:S=>A({suppressAutogeneratedFileHeaderComment:S})}),h.jsx(ne,{label:"Generate Types As Internal",hint:"Emit all generated types with internal rather than public visibility",checked:l.generateTypesAsInternal,onChange:S=>A({generateTypesAsInternal:S})}),h.jsx(ne,{label:"Include Command Line",hint:"Embed the pac command line in generated file headers",checked:l.includeCommandLine,onChange:S=>A({includeCommandLine:S})}),h.jsx(ue,{label:"File Prefix Text",hint:"Text prepended to every generated file name",children:h.jsx("input",{className:"form-input",value:l.filePrefixText,placeholder:"(none)",onChange:S=>A({filePrefixText:S.target.value})})}),h.jsx(ne,{label:"Make Reference Types Nullable",hint:"Add C# nullable annotations to reference-type properties",checked:l.makeReferenceTypesNullable,onChange:S=>A({makeReferenceTypesNullable:S})}),h.jsx(ne,{label:"Use Display Name For BPF Name",hint:"Use the display name when naming Business Process Flow entities",checked:l.useDisplayNameForBpfName,onChange:S=>A({useDisplayNameForBpfName:S})}),h.jsx(ne,{label:"Add New Files To Project",hint:"Add newly generated .cs files to the target .csproj automatically",checked:l.addNewFilesToProject,onChange:S=>A({addNewFilesToProject:S})}),h.jsx(ne,{label:"Delete Files From Output Folders",hint:"Remove stale generated files from output folders",checked:l.deleteFilesFromOutputFolders,onChange:S=>A({deleteFilesFromOutputFolders:S})}),h.jsx(ue,{label:"Project Name For Early-Bound Files",hint:".csproj name to add generated files to (leave blank to auto-detect)",children:h.jsx("input",{className:"form-input",value:l.projectNameForEarlyBoundFiles,placeholder:"(auto-detect)",onChange:S=>A({projectNameForEarlyBoundFiles:S.target.value})})}),h.jsx(ue,{label:"Token Capitalisation Overrides",hint:"Words treated as known tokens during CamelCase naming (e.g. SlaId, VoiceMail)",children:h.jsx(Nt,{items:l.tokenCapitalizationOverrides,onChange:S=>A({tokenCapitalizationOverrides:S}),placeholder:"Add token..."})}),h.jsx(ne,{label:"CamelCase Class Names",hint:"Apply CamelCase formatting to generated class names",checked:l.camelCaseClassNames,onChange:S=>A({camelCaseClassNames:S})}),h.jsx(ne,{label:"CamelCase Member Names",hint:"Apply CamelCase formatting to generated property and member names",checked:l.camelCaseMemberNames,onChange:S=>A({camelCaseMemberNames:S})}),h.jsx(ue,{label:"CamelCase Custom Words",hint:"Additional words recognised as tokens during CamelCase naming",children:h.jsx(Nt,{items:l.camelCaseCustomWords,onChange:S=>A({camelCaseCustomWords:S}),placeholder:"Add word..."})}),h.jsx(ue,{label:"CamelCase Dictionary Path",hint:"Relative path to a custom CamelCase dictionary file. Leave blank to use the built-in dictionary.",children:h.jsx(ts,{value:l.camelCaseNamesDictionaryRelativePath,onChange:S=>A({camelCaseNamesDictionaryRelativePath:S}),settingsDir:a,type:"file",filters:[{name:"Text files",extensions:["txt"]}],placeholder:"(built-in dictionary)",title:"Select CamelCase dictionary file"})})]}),h.jsxs(Yn,{title:"Entities",children:[h.jsx(ue,{label:"Entity Types Folder",hint:"Sub-folder name for generated entity class files",children:h.jsx("input",{className:"form-input",value:l.entityTypesFolder,onChange:S=>A({entityTypesFolder:S.target.value})})}),h.jsx(ne,{label:"One File Per Entity",hint:"Emit a separate .cs file for each entity (vs a single combined file)",checked:l.createOneFilePerEntity,onChange:S=>A({createOneFilePerEntity:S})}),h.jsx(ue,{label:"Entities Whitelist",hint:"Generate only these entities — leave empty to generate all entities",children:h.jsxs("div",{className:"entity-picker-row",children:[h.jsx(Nt,{items:l.entitiesWhitelist,onChange:S=>A({entitiesWhitelist:S}),placeholder:"Add entity logical name..."}),h.jsx("button",{className:"entity-picker-btn",onClick:()=>re("entitiesWhitelist"),children:"Browse Entities"})]})}),h.jsx(ue,{label:"Entities To Skip",hint:"Always exclude these entities even when they appear in other filters",children:h.jsxs("div",{className:"entity-picker-row",children:[h.jsx(Nt,{items:l.entitiesToSkip,onChange:S=>A({entitiesToSkip:S}),placeholder:"Add entity logical name..."}),h.jsx("button",{className:"entity-picker-btn",onClick:()=>re("entitiesToSkip"),children:"Browse Entities"})]})}),h.jsx(ue,{label:"Entity Prefixes To Skip",hint:"Skip all entities whose logical name starts with these prefixes",children:h.jsx(Nt,{items:l.entityPrefixesToSkip,onChange:S=>A({entityPrefixesToSkip:S}),placeholder:"Add prefix..."})}),h.jsx(ue,{label:"Entity Prefixes Whitelist",hint:"Only generate entities whose logical name starts with these prefixes",children:h.jsx(Nt,{items:l.entityPrefixesWhitelist,onChange:S=>A({entityPrefixesWhitelist:S}),placeholder:"Add prefix..."})}),h.jsx(ue,{label:"Entity Class Name Overrides",hint:"Map entity logical names to custom C# class names",children:h.jsx(sa,{entries:l.entityClassNameOverrides,onChange:S=>A({entityClassNameOverrides:S}),keyHeader:"Logical Name",valueHeader:"Class Name",keyPlaceholder:"e.g. account",valuePlaceholder:"e.g. MyAccount"})}),h.jsx(ue,{label:"Entity Attribute Specified Names",hint:"For each entity, limit generation to only these attributes. Leave empty to generate all attributes.",children:h.jsx(uf,{entries:l.entityAttributeSpecifiedNames,onChange:S=>A({entityAttributeSpecifiedNames:S})})}),h.jsx(ue,{label:"Attribute Blacklist",hint:"Attribute logical names to always exclude across all entities",children:h.jsx(Nt,{items:l.attributeBlacklist,onChange:S=>A({attributeBlacklist:S}),placeholder:"Add attribute logical name..."})}),h.jsx(ne,{label:"Generate Attribute Name Consts",hint:"Generate a Fields inner class with attribute logical name string constants",checked:l.generateAttributeNameConsts,onChange:S=>A({generateAttributeNameConsts:S})}),h.jsx(ne,{label:"Generate Anonymous Type Constructor",hint:"Generate a constructor that accepts an anonymous type initialiser",checked:l.generateAnonymousTypeConstructor,onChange:S=>A({generateAnonymousTypeConstructor:S})}),h.jsx(ne,{label:"Generate Constructors Sans Logical Name",hint:"Generate constructors that do not require the entity logical name argument",checked:l.generateConstructorsSansLogicalName,onChange:S=>A({generateConstructorsSansLogicalName:S})}),h.jsx(ne,{label:"Generate Entity Relationships",hint:"Generate relationship navigation properties on entity classes",checked:l.generateEntityRelationships,onChange:S=>A({generateEntityRelationships:S})}),h.jsx(ne,{label:"Generate Enum Properties",hint:"Generate typed enum properties for option set attributes",checked:l.generateEnumProperties,onChange:S=>A({generateEnumProperties:S})}),h.jsx(ne,{label:"Replace Option Set Properties With Enum",hint:"Replace OptionSetValue properties with the generated enum type",checked:l.replaceOptionSetPropertiesWithEnum,onChange:S=>A({replaceOptionSetPropertiesWithEnum:S})}),h.jsx(ne,{label:"Generate INotify Pattern",hint:"Implement INotifyPropertyChanged on all entity classes",checked:l.generateINotifyPattern,onChange:S=>A({generateINotifyPattern:S})}),h.jsx(ne,{label:"Emit Virtual Attributes",hint:"Include virtual/composite attributes (e.g. fullname) in generated classes",checked:l.emitVirtualAttributes,onChange:S=>A({emitVirtualAttributes:S})}),h.jsx(ne,{label:"Emit Entity ETC",hint:"Emit the entity type code constant in generated classes",checked:l.emitEntityETC,onChange:S=>A({emitEntityETC:S})}),h.jsx(ne,{label:"Make All Fields Editable",hint:"Generate all fields (including calculated/rollup) as settable properties",checked:l.makeAllFieldsEditable,onChange:S=>A({makeAllFieldsEditable:S})}),h.jsx(ne,{label:"Make Read-Only Fields Editable",hint:"Generate read-only fields as settable properties",checked:l.makeReadonlyFieldsEditable,onChange:S=>A({makeReadonlyFieldsEditable:S})}),h.jsx(ne,{label:"Use Logical Names",hint:"Name generated properties using attribute logical names instead of schema names",checked:l.useLogicalNames,onChange:S=>A({useLogicalNames:S})}),h.jsx(ne,{label:"Use Enum For State Codes",hint:"Generate enums for statecode and statuscode attributes",checked:l.useEnumForStateCodes,onChange:S=>A({useEnumForStateCodes:S})}),h.jsx(ne,{label:"Use CrmSvcUtil State Enum Naming",hint:"Use CrmSvcUtil-compatible naming convention for state/status enums",checked:l.useCrmSvcUtilStateEnumNamingConvention,onChange:S=>A({useCrmSvcUtilStateEnumNamingConvention:S})}),h.jsx(ne,{label:"Obsolete Deprecated",hint:"Mark deprecated entities and attributes with [Obsolete]",checked:l.obsoleteDeprecated,onChange:S=>A({obsoleteDeprecated:S})}),h.jsx(ue,{label:"Obsolete Tokens",hint:"Display name tokens that flag deprecation (e.g. *(Deprecated)*)",children:h.jsx(Nt,{items:l.obsoleteTokens,onChange:S=>A({obsoleteTokens:S}),placeholder:"Add token..."})}),h.jsx(ue,{label:"Property Enum Mappings",hint:"Manual enum-to-property mappings (format: EntityName.PropertyName=EnumType)",children:h.jsx(Nt,{items:l.propertyEnumMappings,onChange:S=>A({propertyEnumMappings:S}),placeholder:"Add mapping..."})}),h.jsx(ne,{label:"Add Debugger Non-User Code",hint:"Apply [DebuggerNonUserCode] to suppress stepping into generated code",checked:l.addDebuggerNonUserCode,onChange:S=>A({addDebuggerNonUserCode:S})})]}),h.jsxs(Yn,{title:"Option Sets",children:[h.jsx(ue,{label:"Option Sets Folder",hint:"Sub-folder name for generated option set enum files",children:h.jsx("input",{className:"form-input",value:l.optionSetsTypesFolder,onChange:S=>A({optionSetsTypesFolder:S.target.value})})}),h.jsx(ne,{label:"One File Per Option Set",hint:"Emit a separate .cs file for each option set enum",checked:l.createOneFilePerOptionSet,onChange:S=>A({createOneFilePerOptionSet:S})}),h.jsx(ne,{label:"Generate Global Option Sets",hint:"Include global (not entity-local) option sets in the output",checked:l.generateGlobalOptionSets,onChange:S=>A({generateGlobalOptionSets:S})}),h.jsx(ne,{label:"Generate Option Set Metadata Attribute",hint:"Generate metadata attributes on generated enum values",checked:l.generateOptionSetMetadataAttribute,onChange:S=>A({generateOptionSetMetadataAttribute:S})}),h.jsx(ne,{label:"Add Option Set Metadata Attribute",hint:"Apply [OptionSetMetadataAttribute] to generated enums",checked:l.addOptionSetMetadataAttribute,onChange:S=>A({addOptionSetMetadataAttribute:S})}),h.jsx(ne,{label:"Generate All Option Set Label Metadata",hint:"Include all language labels for option set values (not just the default language)",checked:l.generateAllOptionSetLabelMetadata,onChange:S=>A({generateAllOptionSetLabelMetadata:S})}),h.jsx(ne,{label:"Adjust Casing For Enum Options",hint:"Apply CamelCase formatting to enum value names",checked:l.adjustCasingForEnumOptions,onChange:S=>A({adjustCasingForEnumOptions:S})}),h.jsx(ne,{label:"Group Local Option Sets By Entity",hint:"Place local option sets inside an entity-named sub-namespace",checked:l.groupLocalOptionSetsByEntity,onChange:S=>A({groupLocalOptionSetsByEntity:S})}),h.jsx(ne,{label:"Cleanup CrmSvcUtil Local Option Sets",hint:"Remove old CrmSvcUtil-generated local option set files on regeneration",checked:l.cleanupCrmSvcUtilLocalOptionSets,onChange:S=>A({cleanupCrmSvcUtilLocalOptionSets:S})}),h.jsx(ue,{label:"Invalid C# Name Prefix",hint:"Prefix applied to enum values that start with an invalid C# identifier character",children:h.jsx("input",{className:"form-input",value:l.invalidCSharpNamePrefix,onChange:S=>A({invalidCSharpNamePrefix:S.target.value})})}),h.jsx(ue,{label:"Local Option Set Format",hint:"Format string for local option set names: {0}=entity name, {1}=attribute name",children:h.jsx("input",{className:"form-input",value:l.localOptionSetFormat,onChange:S=>A({localOptionSetFormat:S.target.value})})}),h.jsx(ue,{label:"Language Code Override",hint:"Override the language code used for option set labels (blank = environment default)",children:h.jsx("input",{type:"number",className:"form-input",value:l.optionSetLanguageCodeOverride??"",placeholder:"(environment default)",onChange:S=>A({optionSetLanguageCodeOverride:S.target.value?parseInt(S.target.value,10):null})})}),h.jsx(ue,{label:"Option Set Names",hint:"Override the generated C# name for a conflicting option set. Key: generated name (lowercase). Value: replacement class name.",children:h.jsx(sa,{entries:l.optionSetNames,onChange:S=>A({optionSetNames:S}),keyHeader:"Option Set Name",valueHeader:"Class Name",keyPlaceholder:"e.g. account_rating",valuePlaceholder:"e.g. AccountRating"})}),h.jsx(ue,{label:"Option Name Overrides",hint:"Fix casing of enum member name tokens. Key: lowercase token to match. Value: correctly-cased replacement (e.g. fedex → FedEx).",children:h.jsx(sa,{entries:l.optionNameOverrides,onChange:S=>A({optionNameOverrides:S}),keyHeader:"Token (lowercase)",valueHeader:"Replacement",keyPlaceholder:"e.g. fedex",valuePlaceholder:"e.g. FedEx"})}),h.jsx(ue,{label:"Transliteration Path",hint:"Relative path to a transliteration file for non-Latin characters",children:h.jsx(ts,{value:l.transliterationRelativePath,onChange:S=>A({transliterationRelativePath:S}),settingsDir:a,type:"file",placeholder:"(none)",title:"Select transliteration file"})})]}),h.jsxs(Yn,{title:"Messages",children:[h.jsx(ne,{label:"Generate Messages",hint:"Generate Request/Response classes for Dataverse messages, Actions, and Custom APIs",checked:l.generateMessages,onChange:S=>A({generateMessages:S})}),h.jsx(ue,{label:"Message Types Folder",hint:"Sub-folder name for generated message class files",children:h.jsx("input",{className:"form-input",value:l.messageTypesFolder,onChange:S=>A({messageTypesFolder:S.target.value})})}),h.jsx(ne,{label:"One File Per Message",hint:"Emit a separate .cs file for each message",checked:l.createOneFilePerMessage,onChange:S=>A({createOneFilePerMessage:S})}),h.jsx(ue,{label:"Messages Whitelist",hint:"Only generate these messages — leave empty to generate all messages",children:h.jsx(Nt,{items:l.messagesWhitelist,onChange:S=>A({messagesWhitelist:S}),placeholder:"Add message name..."})}),h.jsx(ue,{label:"Messages To Skip",hint:"Always exclude these messages from generation",children:h.jsx(Nt,{items:l.messagesToSkip,onChange:S=>A({messagesToSkip:S}),placeholder:"Add message name..."})}),h.jsx(ue,{label:"Message Prefixes Whitelist",hint:"Only generate messages whose name starts with these prefixes",children:h.jsx(Nt,{items:l.messagePrefixesWhitelist,onChange:S=>A({messagePrefixesWhitelist:S}),placeholder:"Add prefix..."})}),h.jsx(ne,{label:"Group Request With Response",hint:"Place Request and Response classes in the same generated file",checked:l.groupMessageRequestWithResponse,onChange:S=>A({groupMessageRequestWithResponse:S})}),h.jsx(ne,{label:"Generate Message Attribute Name Consts",hint:"Generate a Fields inner class for message parameter name constants",checked:l.generateMessageAttributeNameConsts,onChange:S=>A({generateMessageAttributeNameConsts:S})}),h.jsx(ne,{label:"Make Response Messages Editable",hint:"Generate settable properties on Response message classes",checked:l.makeResponseMessagesEditable,onChange:S=>A({makeResponseMessagesEditable:S})})]}),h.jsxs(Yn,{title:"Service Classes",defaultExpanded:!1,children:[h.jsxs("div",{className:"prop-row",children:[h.jsx("div",{}),h.jsx("p",{className:"form-hint",children:"These values are saved to the settings file for compatibility with XrmToolBox EarlyBoundGeneratorV2 but have no effect on code generation in Power Platform ToolBox, which implements generation directly without calling PAC CLI."})]}),h.jsx(ue,{label:"Code Customisation Service",hint:"Assembly-qualified type name for DLaB.ModelBuilderExtensions.CustomizeCodeDomService",children:h.jsx("input",{className:"form-input",value:l.codeCustomizationService,onChange:S=>A({codeCustomizationService:S.target.value})})}),h.jsx(ue,{label:"Code Generation Service",hint:"Assembly-qualified type name for the code generation service",children:h.jsx("input",{className:"form-input",value:l.codeGenerationService,onChange:S=>A({codeGenerationService:S.target.value})})}),h.jsx(ue,{label:"Code Writer Filter Service",hint:"Assembly-qualified type name for the code writer filter service",children:h.jsx("input",{className:"form-input",value:l.codeWriterFilterService,onChange:S=>A({codeWriterFilterService:S.target.value})})}),h.jsx(ue,{label:"Code Writer Message Filter Service",hint:"Assembly-qualified type name for the message filter service",children:h.jsx("input",{className:"form-input",value:l.codeWriterMessageFilterService,onChange:S=>A({codeWriterMessageFilterService:S.target.value})})}),h.jsx(ue,{label:"Metadata Provider Service",hint:"Assembly-qualified type name for the metadata provider service",children:h.jsx("input",{className:"form-input",value:l.metadataProviderService,onChange:S=>A({metadataProviderService:S.target.value})})}),h.jsx(ue,{label:"Metadata Query Provider Service",hint:"Assembly-qualified type name for the metadata query provider service",children:h.jsx("input",{className:"form-input",value:l.metadataQueryProviderService,onChange:S=>A({metadataQueryProviderService:S.target.value})})}),h.jsx(ue,{label:"Naming Service",hint:"Assembly-qualified type name for the naming service",children:h.jsx("input",{className:"form-input",value:l.namingService,onChange:S=>A({namingService:S.target.value})})})]}),h.jsxs(Yn,{title:"Debug",defaultExpanded:!1,children:[h.jsx(ue,{label:"Model Builder Log Level",hint:"Verbosity for pac modelbuilder logging: 0 = quiet, 5 = verbose",children:h.jsx("input",{className:"form-input",value:l.modelBuilderLogLevel,onChange:S=>A({modelBuilderLogLevel:S.target.value})})}),h.jsx(ne,{label:"Update Builder Settings JSON",hint:"Write the builderSettings.json file before running pac modelbuilder",checked:l.updateBuilderSettingsJson,onChange:S=>A({updateBuilderSettingsJson:S})}),h.jsx(ne,{label:"Read Serialised Metadata",hint:"Read metadata from a previously serialised file instead of from Dataverse",checked:l.readSerializedMetadata,onChange:S=>A({readSerializedMetadata:S})}),h.jsx(ne,{label:"Serialise Metadata",hint:"Write the retrieved metadata to disk for use with Read Serialised Metadata",checked:l.serializeMetadata,onChange:S=>A({serializeMetadata:S})}),h.jsx(ne,{label:"Wait For Attached Debugger",hint:"Pause pac modelbuilder at startup until a .NET debugger attaches",checked:l.waitForAttachedDebugger,onChange:S=>A({waitForAttachedDebugger:S})})]})]}),h.jsx(sf,{output:v,onClear:()=>m(""),onCopy:()=>{var S;(S=window.toolboxAPI)==null||S.utils.copyToClipboard(v)}})]}),h.jsx("div",{className:"bottom-bar",children:h.jsx("button",{className:"toolbar-btn primary",onClick:le,disabled:j,title:"Generate early-bound classes",children:j?h.jsxs(h.Fragment,{children:[h.jsx("span",{className:"toolbar-spinner"}),"Generating..."]}):"Generate"})}),h.jsx(of,{isOpen:Q,selectedEntities:se?l[se]:[],onConfirm:Ce,onClose:Xe}),c.length>0&&h.jsx("div",{className:"dialog-overlay",children:h.jsxs("div",{className:"dialog",style:{width:380},children:[h.jsx("div",{className:"dialog-header",children:h.jsx("span",{style:{fontWeight:600,fontSize:13},children:"Multiple XML files found"})}),h.jsxs("div",{className:"dialog-body",children:[h.jsx("p",{style:{margin:"0 0 10px",fontSize:12,color:"var(--text-secondary)"},children:"Select which settings file to load:"}),h.jsx("div",{className:"string-list",children:c.map(S=>h.jsxs("label",{className:"string-list-item",style:{cursor:"pointer",gap:8},children:[h.jsx("input",{type:"radio",name:"xml-pick",value:S,onChange:()=>{k([]),ee(a,S)}}),S]},S))})]}),h.jsx("div",{className:"dialog-footer",children:h.jsx("button",{className:"btn-secondary",onClick:()=>{k([]),d(is)},children:"Use Defaults"})})]})})]})}const Ic=l=>{l==="dark"?document.body.classList.add("dark-theme"):document.body.classList.remove("dark-theme")},bc=async()=>{if(window.toolboxAPI){const l=await window.toolboxAPI.utils.getCurrentTheme();Ic(l)}},zf=(l,o)=>{var f;const a=o;if(a.event!=="settings:updated")return;const p=(f=a.data)==null?void 0:f.theme;p?Ic(p):bc()},Bf=()=>{window.toolboxAPI&&window.toolboxAPI.events.on(zf)};bc();Bf();Hp.createRoot(document.getElementById("root")).render(h.jsx(ve.StrictMode,{children:h.jsx(bf,{})}));
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@mbwilding/tool-early-bound-generator",
3
- "version": "0.0.4",
3
+ "version": "0.0.6",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "@mbwilding/tool-early-bound-generator",
9
- "version": "0.0.4",
9
+ "version": "0.0.6",
10
10
  "license": "GPL-2.0",
11
11
  "dependencies": {
12
12
  "react": "^18.3.1",
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@mbwilding/tool-early-bound-generator",
3
3
  "displayName": "Early Bound Generator",
4
- "version": "0.0.4",
4
+ "version": "0.0.6",
5
5
  "description": "Generate strongly-typed C# early-bound classes for Dataverse entities, option sets, and messages",
6
6
  "icon": "icons/ebg.svg",
7
7
  "contributors": [