[{"content":"JSON files are one of the most common and convenient ways to store structured data. They’re lightweight, human-readable, and easy to parse in JavaScript. In PCF Control development, they can be used a quick and convenient way to store and access static data.\nIn this post, I’ll show you how to easily configure your PCF control projects to bundle static JSON files and resolve their contents at runtime.\nHow it started It all started when I began receiving complaints that my open-source Country Picker PCF control had suddenly stopped working properly. After some investigation, I realized the issue came from its dependency on a free third-party service used to query the country data— restcountries.\nUnfortunately, the owner recently introduced a breaking change that completely broke the control.\nTo make the control more stable and self-contained, I decided to remove the dependency on the external API and instead embed a static JSON file containing the list of countries directly into the project. This would ensures the control always loads reliably—no external calls, no surprises.\nEnable JSON import support It is quite straightforward to configure your PCF project to use JSON files. Simply update your tsconfig.json file with these 2 parameters :\n\u0026#34;resolveJsonModule\u0026#34;: true, \u0026#34;allowSyntheticDefaultImports\u0026#34;: true \u0026quot;resolveJsonModule\u0026quot; : true\u0026quot; allows TypeScript to import .json files as modules, just like .ts or .tsx files.\n\u0026quot;allowSyntheticDefaultImports\u0026quot;: true tells TypeScript to allow default-style imports even when the module being imported doesn’t actually have a default export.\nThis is especially useful for JSON files, because they aren’t native TypeScript modules and don’t provide explicit export syntax.\nWith these options enabled, it\u0026rsquo;s now possible to import and consume the content of JSON files like this:\nimport countriesData from \u0026#39;./countries_data.json\u0026#39; export const getAllCountries = ():Country[] =\u0026gt; { return countriesData as Country[] } This will :\nRecognize the JSON file as a valid module, Automatically infer the correct types from the file content (e.g., arrays, objects), Allow you to work with the data just like a regular object. Without these options turned on, you would get a compile-time error when trying to import a JSON file, like:\nCannot find module './countries_data.json'. Consider using '--resolveJsonModule' to import module.\nThat\u0026rsquo;s all there is! Now, just add the JSON files to your project — unlike CSS or RESX files, there’s no need to reference them in your control manifest. With resolveJsonModule enabled, TypeScript will automatically bundle the JSON content with your other project files, making it ready to use at runtime.\nTake Away Using this approach, I was able to overcome the issue with my CountryPicker PCF and remove the dependency on restcountries to make the control more performant and reliable.\nI also recently ported the control to FluentUI V9 ensuring it blends seamlessly with other fields in model-driven app forms. 👉 Check out the latest release here\nThere are several use cases where static JSON data can be particularly useful in PCF projects, such as storing environment variables, reference data, or mocking API calls. Just be careful not to bloat your project with unnecessary data, as large JSON files can increase load times\nHope this helps! GitHub - drivardxrm/CountryPicker.PCF: Country Picker PCF Country Picker PCF. Contribute to drivardxrm/CountryPicker.PCF development by creating an account on GitHub. github.com REST Countries - Country data API REST Countries provides country data through a simple API. restcountries.com The \u0026#34;all\u0026#34; endpoints will return 400 if no fields are specified (#265) · Issues · restcountries / restcountries · GitLab The REST Countries issue describing the breaking change to the all endpoints. gitlab.com Photo by RealToughCandy.com\n","date":"2025-10-19T21:21:41Z","image":"/pcf-controls-tips-tricks-how-to-bundle-and-resolve-static-json-files/pexels-realtoughcandy-11035481-scaled.jpg","permalink":"/pcf-controls-tips-tricks-how-to-bundle-and-resolve-static-json-files/","title":"PCF Controls Tips \u0026 Tricks: How to Bundle and Resolve Static JSON Files"},{"content":"Have you ever been unable to properly build a PCF control because of linting errors? Well, lately I have, and it can get really frustrating. Especially when the errors have nothing to do with your code, but are caused by an unexpected failure in the way the PCF framework handles the linting process.\nTurns out I\u0026rsquo;m not alone as other members of the PCF community like Charles Channon have recently flagged linting issues with recent pcf-scripts releases.\nIn this post, I’ll show you how I found a way to skip linting during the PCF control build process. This keeps you focused on building and deploying your controls, even if the linter crashes.\nBut while we are at it, let’s talk about what linting is and how it’s implemented in PCF projects.\nLinting in PCF controls In a nutshell, linting is a static code analysis process that checks your code for errors, potential bugs, and style violations. By enforcing coding standards, it helps catch problems early in the development cycle, and improve overall code quality.\nMany projects run linting automatically during builds, commits, and even within the IDE during development to catch issues early.\nThe PCF framework integrates ESLint, a popular linting tool, into the scaffolded code generated by the pac pcf init command. When a PCF project is initialized, a file named eslint.config.mjs is added to the project structure.\nThe eslint.config.mjs file contains a set of recommended rules, along with a rules section that you can customize to your liking. There’s a lot more more to dive into, but that’s beyond the scope of this post.\nWith proper setup in your IDE this will make you editor scream when rules are infringed.\nIn typical TypeScript projects, linting is generally under your control and can be executed on demand. But in PCF control development, linting is baked into the build process. The pcf-scripts package runs ESLint every single time you call npm run build.\nWhile this setup works well in an ideal world, I’ve occasionally run into unexpected crashes during the linting step.\nIn my experience, these issues rarely relate to actual linting rules. They usually stem from deeper configuration quirks or conflicts with other dependencies. It’s really annoying and makes it impossible to move on.\nSo, let’s look at how we can separate the linting step from the PCF build,\nSkipping Linting during PCF Build With a bit of reverse engineering, I tracked down the part of the pcf-scripts package where the linting task is invoked during the build.\nLocated deep in node_modules\\pcf-scripts\\tasks\\validateTask.js, I discovered that linting could be skipped if context.getSkipBuildLinting() returned true. Looks promising, but how is this property set ?\nI figured out that the build context was defined in this file node_modules\\pcf-scripts\\buildContext.js, and found that getSkipBuildLinting() gets is value from a configuration switch. Getting closer\u0026hellip;\nDigging further, I found that the context object is configured in node_modules\\pcf-scripts\\buildConfig.js. I’m nearly there, I can tell\u0026hellip;\nFrom there, I traced the configuration source to node_modules\\pcf-scripts\\constants.js, where the constant CONFIGURATION_FILE_NAME revealed that the settings are loaded from the project’s own pcfconfig.json. BINGO!.\n💡That’s when it clicked— and I knew I had blog post material on my hands.\nNow, by simply adding a line of code to the pcfconfig.json and setting skipBuildLinting to true\u0026hellip;\n\u0026hellip;we can see that the Linting step gets properly skipped when we build the control. 😎\nBy doing this, I was able to decouple linting from the build, and go back to the real development of the control.\nAlso, like Charles Channon pointed out in the LinkedIn post mentioned earlier, you can still run EsLint manually at any time using a command that doesn\u0026rsquo;t rely on the PCF framework. The best of both worlds!\nnpx eslint \u0026#39;./**/*.{ts,tsx}\u0026#39; --format stylish TakeAway Linting is a powerful tool that helps keep your code clean, consistent, and error-free. It’s important for any serious project. But sometimes, you just need to get things done and can’t afford to be blocked by unexpected linting crashes.\nIn PCF projects, linting is enforced as part of the build by default. But, you can skip the linting step by adding \u0026quot;skipBuildLinting\u0026quot;: true to your pcfconfig.json file—something that’s not officially documented, but works.\nYou can still run linting manually at any time using a standalone command that bypasses the PCF Framework scripts.\nHope this helps!\nI haven\u0026#39;t needed to build a #PCF in a few months, but just initted one and hit a strange error related to the eslint formatter. | Charles Channon I haven\u0026#39;t needed to build a #PCF in a few months, but just initted one and hit a strange error related to the eslint formatter. For some reason, it kept spitting out an empty error (no warnings or errors, just a flat failure) - this appears to be an issue in the pcf-scripts invocation of eslint and the default formatter. The fix is easy: don\u0026#39;t rely on pcf-scripts to lint for you: just invoke eslint yourself with: ``` npx eslint \u0026#39;./**/*.{ts,tsx}\u0026#39; --format stylish ``` www.linkedin.com Find and fix problems in your JavaScript code - ESLint - Pluggable JavaScript Linter A pluggable and configurable linter tool for identifying and reporting on patterns in JavaScript. Maintain your code quality with ease. eslint.org ","date":"2025-07-08T01:09:42Z","image":"/pcf-controls-tips-and-tricks-how-to-skip-linting-at-build-time/lint_feathers_finger_white.jpg","permalink":"/pcf-controls-tips-and-tricks-how-to-skip-linting-at-build-time/","title":"PCF Controls Tips and Tricks : How to skip Linting at Build-Time"},{"content":"When you configure a PCF control on a Dataverse model-driven app, the form designer will try to render the control even though it\u0026rsquo;s not running in the actual app context.\nThis usually isn\u0026rsquo;t a problem, but for complex controls that depend on runtime data, it can cause errors—and even break the form designer.\nMoreover, as a PCF developer, you might want to show a simplified or placeholder version of your control in the form designer to help makers understand how it will look when the app actually runs.\nIn this post, we’ll explore how to detect authoring mode during a PCF control’s initialization. That way, the code can be adjusted to avoid design time issues and provide a better configuration experience.\nDetecting Authoring Mode I\u0026rsquo;m not the first to highlight this issue— Andrew Butenko wrote an excellent post about it and proposed a nice solution.\n🔗PCF: Design time vs run time - Andrew Butenko\u0026rsquo;s Blog\nIn fact, I’ve been using a slightly tweaked version of his approach in many of the controls I’ve developed. I use the following code in the init method of my PCF controls to set a variable isDesignMode that I can use afterward in the component logic. It looked something like this :\n//https://butenko.pro/2023/01/08/pcf-design-time-vs-run-time/ if (location.ancestorOrigins?.[0] === \u0026#34;https://make.powerapps.com\u0026#34; || location.ancestorOrigins?.[0] === \u0026#34;https://make.preview.powerapps.com\u0026#34;) { this._isDesignMode = true; } While his method works well, it depends on checking the origin URL (e.g., make.powerapps.com) to determine if the control is rendering in the form designer ( design time) or in the actual app itself ( run time). This works for now, but if Microsoft ever changes the URL structure, the logic could break unexpectedly.\nFortunately, while debugging a PCF control in the browser dev tools, I stumbled across an undocumented property of the PCF context.mode object called isAuthoringMode—and it immediately caught my attention. I’m not sure how long it’s been there, but I had never seen it before.\nSo I decided to try it out and I simplified my detection logic to use isAuthoringMode instead of checking the origin URL.\nMy new version is quite simple and looks like this :\nif ((context.mode as any).isAuthoringMode === true) { this._isDesignMode = true; } Unfortunately since this property is not documented thus not part of the Typescript typings of the context object, the context.mode needs to be casted as any for the value to be accessed.\nAnd it works exactly as expected. As you can see, the value of isAuthoringMode changes accordingly.\nWhereas the control is rendered in the form designer ( design time) :\nOr in the actual application ( run time) :\nIt\u0026rsquo;s as simple as that. I find this new approach concise, resilient, and future-proof. Hopefully, Microsoft will eventually release official documentation and typings for this property to simplify things further.\nHope this helps,\nLinks PCF: Design time vs run time - Andrew Butenko’s Blog Recently I developed quite a complex and quite flexible PCF control for my customer. I did all the testing and everything was working fine for me according to the provided requirements. I notified the customer that the latest version of the control was pushed to the environment and started to wait on the feedback. In… butenko.pro Image by rawpixel.com on Freepik\n","date":"2025-06-02T02:57:10Z","image":"/pcf-controls-tips-tricks-how-to-detect-authoring-mode/aerial-view-man-typing-retro-typewriter-scaled.jpg","permalink":"/pcf-controls-tips-tricks-how-to-detect-authoring-mode/","title":"PCF Controls Tips \u0026 Tricks : How to detect Authoring Mode"},{"content":"It is a common requirement for SaaS platform that exposes form over data to be able to share a secure link (a.k.a. Deep Link) to access a given record. That way, links can be shared publicly— via email or Teams message for example—but clicking them still requires the user to authenticate and have the right permissions to access the record.\nFor instance, Power Platform model-driven apps have this functionality built in. You can simply copy and share the URL exposed in the browser while looking at a specific record. If the recipient has the right credentials, they can click the link and go straight to the record. This predictable URL format also makes it super handy to build automations.\nUnfortunately, it\u0026rsquo;s a bit more complex with D365 Finance and Operations since the URL shown in the browser while viewing a record doesn’t contain any specific record information and will not open the record if shared to another user.\nIn this post, I\u0026rsquo;ll explain how to use Dataverse virtual tables to create secure deep links to D365 F\u0026amp;O records.\nI’ll guide you through an example using Power Automate to demonstrate how it works in practice. Plus, I will show you how to easily create deep links using the Finance and Operations Virtual Entity Manager for XrmToolBox.\nDeep links in D365 Finance (F\u0026amp;O) According to the official documentation there are 2 ways to create deep links in D365 Finance (F\u0026amp;O), the URL Generator and System Entity Navigation.\n🔗Create shareable, secured URLs (deep links) - Finance \u0026amp; Operations | Dynamics 365 | Microsoft Learn\nThe URL Generator is a .NET library you can use from X++ code to create links in D365 F\u0026amp;O. But it only works within the F\u0026amp;O platform—like in user sessions or batch jobs. Since I’m not an X++ developer, we’ll skip this technique for this blog post.\nInstead we will focus on the more versatile System Entity Navigation approach that leverages Dataverse Virtual Tables. This method lets you build deep link URLs dynamically— outside of the F\u0026amp;O runtime and without writing any X++ code.\nPrerequisite This System Entity Navigation feature was introduced in v10.41 of F\u0026amp;O. If you\u0026rsquo;re running an older version and try to access a link that relies on this feature, you’ll get the following error.\nIf its not already the case, you will also need to enable Dataverse virtual tables in your environment. (see docs below)\n🔗Enable Microsoft Dataverse virtual entities - Finance \u0026amp; Operations | Dynamics 365 | Microsoft Learn\nOnce virtual tables are configured, you\u0026rsquo;ll need to enable any tables that you want to expose as a deep link on the Dataverse side. For our example, I\u0026rsquo;ll enable the VendVendorV2Entity, that corresponds to vendor accounts.\nTo enable a table, you could take the hard route and use Power Platform’s old-school Advanced Find method (see documentation)—or, you could make your life easier and use my FinOps Virtual Entity Manager tool for XrmToolBox, which offers a much smoother experience and many other nifty features (shameless plug ☺️).\nThis will expose a table called mserp_vendvendorv2entity in the linked Dataverse environment.\nSystem Entity Navigation URL Schema Now that everything’s set up, you can start building deep links to F\u0026amp;O records—like vendor accounts. Just use the following URL schema:\nhttps://[FinOpsUrl]/?cmp=[Dataarea]\u0026amp;mi=action:SysEntityNavigation\u0026amp;entityName=[EntityCollectionName]\u0026amp;entityGuid=[Guid]\nFinOpsUrl : This is the root URL of the F\u0026amp;O environment. ex. https://myfinopsenv.operations.dynamics.com 💡There is function part of the Dataverse Web Api called RetrieveFinanceAndOperationsIntegrationDetails. You can use this function to dynamically get RootUrl of the linked F\u0026amp;O environment of a given Dataverse environment.\nDataarea : This is the company name (legal entity) associated with the record. Note that this parameter is optional, and we won’t be using it in the examples below.\nEntityCollectionName : The plural of the schema name of the Dataverse virtual table\nFor the vendor account table, the plural name is mserp_vendvendorv2entities\nYou can find the plural name of a given table \u0026lsquo;buried\u0026rsquo; in the maker portal, by navigating to a Virtual table properties and select \u0026rsquo; Advanced/Tools/Copy set name\u0026rsquo;\nBut again I would advise you to use my XrmToolBox tool to get this info as it will save you a lot of time.\nGuid : the unique identifier property of the selected record in the Dataverse virtual table Every record in a virtual table gets a GUID assigned by the Dataverse engine in the identity field. By convention, the field name is the name of the virtual table suffixed with \u0026lsquo;id\u0026rsquo;. So, for the Vendor Account table, the field would be mserp_vendvendorv2entityid.\nYou can see this in action with a query on the virtual table using the epic SQL 4 CDS tool by Mark Carrington\nExample with Power Automate Time to try it out!\nAnother great feature of F\u0026amp;O Virtual tables is that once a table is enabled, you can create Power Automate flows that treat these F\u0026amp;O tables just like regular Dataverse tables.\nTo illustrate this I will create a Power Automate flow that triggers on every Vendor Account creation and send an email to an agent. Note that I\u0026rsquo;m using the Dataverse connector and not the classic F\u0026amp;O connector.\nSince I\u0026rsquo;m using the virtual table in the trigger, I\u0026rsquo;m able to get the appropriate Guid of the record to compose the link, directly from the available values received by the trigger action.\nIn the Compose block, I’m hardcoding thee FinOpsUrl and the EntityCollectionName just to keep things simple—but keep in mind, there are ways to make this more dynamic and generic if needed.\nOnce the link is composed, it’s added as a hyperlink in an email message, which is sent to the agent.\nAnd that’s it! I now get an email every time a new Vendor account is created in the system, and I can easily navigate to the record— provided my security role allows it.\nCreate DeepLinks with FinOps Virtual Entity Manager for XrmToolBox To wrap up this post:\nIn the latest version of my FinOps Virtual Entity Manager Tool for XrmToolBox, I added a new feature to create DeepLinks on the fly.\nWhen using the tool, just select an F\u0026amp;O entity that as been enabled for virtual entity. Notice that the FinOpsUrl and the EntityCollectionName are already available.\nIn the Deep Link section of the tool, you can select a given record and a deep link to that record will be generated. This will give the Guid of the record and complete the deep link.\nNote that not all enabled virtual entities will generate valid deep links. For the link to work, the entity must correspond to a valid menu item in F\u0026amp;O. If it doesn\u0026rsquo;t, you\u0026rsquo;ll run into an error like below. This means the system couldn’t figure out where to send the user, so it’s important to test and verify which table supports deep linking.\nTake Away That’s all for now!\nDeep links for D365 F\u0026amp;O records are a great way to deliver a slick user experience and take your automations to the next level.\nI’m excited to see how the community puts this feature to use and what creative scenarios it will unlock.\nLinks Create shareable, secured URLs (deep links) - Finance \u0026amp; Operations | Dynamics 365 Learn how to create shareable, secured URLs to Finance and Operations forms and records. learn.microsoft.com Enable Microsoft Dataverse virtual entities - Finance \u0026amp; Operations | Dynamics 365 Learn how to enable Finance and Operations virtual entities in Microsoft Dataverse. learn.microsoft.com GitHub - drivardxrm/Driv.XTB.FinOpsVirtualEntityManager: XrmToolBox tool to manage Finance and Operations Dataverse Virtual Entities XrmToolBox tool to manage Finance and Operations Dataverse virtual entities. github.com Finance and Operations Virtual Entity Manager for XrmToolBox Manage Finance and Operations Dataverse virtual entities with XrmToolBox. itmustbecode.com SQL 4 CDS · XrmToolBox Use standard SQL syntax to query and manipulate data and metadata in Dataverse. www.xrmtoolbox.com RetrieveFinanceAndOperationsIntegrationDetailsResponse ComplexType (Microsoft.Dynamics.CRM) Contains the response from the RetrieveFinanceAndOperationsIntegrationDetails function. learn.microsoft.com Photo by Edge2Edge Media on Unsplash\n","date":"2025-04-23T02:30:01Z","image":"/how-to-create-deep-links-to-d365-fo-records-with-dataverse-virtual-tables/edge2edge-media-t1OalCBUYRc-unsplash-1.jpg","permalink":"/how-to-create-deep-links-to-d365-fo-records-with-dataverse-virtual-tables/","title":"How to Create Deep Links to D365 F\u0026O Records with Dataverse Virtual Tables"},{"content":"I recently encountered a requirement on a model-driven app project to display a custom ribbon button only when the form had no unsaved changes—in other words, the button needed to be hidden whenever the form was dirty.\nWhile the solution is quite simple, I thought it would be a good idea to write about it and put all the pieces of the puzzle together. I also explore and provide a solution for the 2 current button extension models—the Classic Ribbon and the Modern commanding .\nClassic Ribbon vs Modern Commanding If you\u0026rsquo;re familiar with custom button development for model-driven apps, you know there are currently two extension models: the Classic Ribbon and the Modern commanding experience. See the official doc below.\n🔗Command designer overview - Power Apps | Microsoft Learn\n🔗Command bar customization limitations - Power Apps | Microsoft Learn\n🔗Customize commands and the ribbon (model-driven apps) - Power Apps | Microsoft Learn\nDespite Microsoft advocating for Modern commanding over the Classic Ribbon, I personally feel more comfortable with the classic approach and have often encountered limitations with the Modern experience.\nBut let’s not dive into politics here (we’ve already got enough of that these days 😉). Instead, I’ll walk through solutions for both extension models, so you can choose the best fit for your needs.\nDetecting Form State - Classic Ribbon The first step is quite obvious, we need to check the form\u0026rsquo;s state to see if there are any unsaved changes. Fortunately, the client API provides a method that can be used in both form and ribbon JavaScript customizations to accomplish this.\nformContext.data.entity.getIsDirty(); 🔗entity.getIsDirty (Client API reference) - Power Apps | Microsoft Learn\nUsing this method, let\u0026rsquo;s create a simple function in a JavaScript web resource that will assess whether our button should be shown or not, depending on the getIsDirty status. We will use it to configure the button enable rule in the next step.\n//Ribbon Enable Rule function ShowWhenNotDirty(primaryControl) { let formContext = primaryControl let isDirty = formContext.data.entity.getIsDirty() return !isDirty } Configuring the button Enable Rule Of course I will be using the amazing Ribbon Workbench for XrmToolBox by Scott Durow. If you\u0026rsquo;ve been living under a rock, mastering this tool is an absolute must for anyone serious about Model-driven app ribbon customization.\n🔗Develop 1 Ltd | Ribbon Workbench for Dynamics 365 \u0026amp; Dynamics CRM\nSince there are plenty of great resources available to help you get started with custom buttons and actions, I’ll skip the basics and focus solely on setting up the enable rule of the button.\nLet\u0026rsquo;s say we already created a button and its command using the Ribbon Workbench. For now the button\u0026rsquo;s command only executes a custom JavaScript function when clicked.\nTo set a dynamic visibility rule for the button, simply add an Enable Rule to the command\nAnd add a Custom Rule step\nHook the custom rule to the ShowWhenNotDirty JavaScript function defined earlier. Don\u0026rsquo;t forget to add the Crm Parameter named PrimaryControl to the rule parameters otherwise the form context will not be passed to the function.\nAnd that\u0026rsquo;s all there is for the button configuration. Now let\u0026rsquo;s achieve the same functionality using the Modern commanding experience.\nDetecting Form State - Modern Commanding Things are a bit different with the Modern commanding model. At the time of writing, even if it is possible to link a custom JavaScript function to the button command (action), only PowerFx functions are allowed for the visibility rules.\nNo issue here since there is an Unsaved form state provided by the Selected object injected by the host and available in PowerFx expressions.\nOur visibility rule can now be expressed like this.\nNot(Self.Selected.Unsaved) 🔗Use Power Fx with commands - Power Apps | Microsoft Learn\nAgain, I won’t go into all the details of setting up the button and will focus only on configuring the visibility rule.\nStarting with an existing button that has no visibility rule ( Visibility is set to Show).\nChange the Visibility to Show on condition from formula and put the PowerFx expression specified above.\nSimple as that! I have to admit, the setup is much easier with the Modern commanding approach.\nRefreshing the ribbon on form change At this point, you might be disappointed to see the button will still be displayed when the form state becomes unsaved—but there’s a good reason for that.\nNatively, the ribbon is only refreshed during the onLoad event of the form, causing all visibility rules of the ribbon to be evaluated at this time.\nSince the form’s unsaved status is set during the user session and after the initial load, it doesn’t really help in this case. We need to explicitly refresh the ribbon whenever form attributes change by invoking the following function.\nformContext.ui.refreshRibbon() 🔗ui.refreshRibbon (Client API reference) in model-driven apps - Power Apps | Microsoft Learn\nThe hard way to achieve this would be to manually add this function to the OnChange event of every field on the form, ensuring the ribbon refreshes when a value changes. But you can imagine waste of time for the initial setup and the nightmare it would be to maintain 🤢.\nInstead, I found this nifty solution provided by Andrew Butenko in the thread below.\n🔗https://community.dynamics.com/forums/thread/details/?threadid=2d8cfb18-13e4-403d-8e13-de5c2f27959c\nThe goal here is to add a function on the OnLoad of the form that will dynamically register an OnChange event on every attributes of the underlying record. 👉 This is a very cool pattern that can be applied to many other use cases.\nfunction onLoad(executionContext) { let formContext = executionContext.getFormContext(); formContext.data.entity.attributes.forEach(function(a){ a.addOnChange(function(){ formContext.ui.refreshRibbon(); }); }); } Last step is to configure the OnLoad event on the form to execute the function above and we are good to go.\nTesting the solution Now, as we can appreciate in the clip below, the custom buttons will automatically disappear whenever the form\u0026rsquo;s state is Unsaved and reappear upon saving the form.\nHope this helps 😎!\nLinks Use Power Fx with commands - Power Apps Use Power Fx to customize the command bar. learn.microsoft.com ","date":"2025-03-09T19:56:52Z","image":"/model-driven-app-trick-how-to-hide-a-ribbon-button-when-the-form-is-dirty/stormseeker-oXo6IvDnkqc-unsplash-1.jpg","permalink":"/model-driven-app-trick-how-to-hide-a-ribbon-button-when-the-form-is-dirty/","title":"Model-Driven App Trick : How to Hide a  Ribbon Button when the Form is Dirty"},{"content":"As a .NET developer, the yearly release cycle is always one of my most anticipated event. This years edition is no exception, as it brings .NET 9 to the forefront with its load of improvements. However, it also marks the end of support for .NET 6, meaning it\u0026rsquo;s time to think about upgrade and migration plan.\nOver time, I’ve developed and continue to maintain a several of Azure Functions projects built on . NET 6 using the In-Process model. With .NET 6 reaching its end of life and the In-Process model being slowly deprecated (End of life Nov 2026), I decided it was the perfect timing to upgrade my projects to a newer .NET version, but also to make the switch to the Isolated Worker model.\nDuring the process I encountered a nasty bug on Http-triggered functions, here\u0026rsquo;s how I uncovered and resolved the issue.\n🤒The symptoms I chose to upgrade my projects to .NET 8 Isolated worker mode. The migration path from In-Process to Isolated worker model is well documented ( see link below) and I was able to adjust the code and Azure infrastructure without too much problems.\n🔗 Migrate .NET function apps from t he in-process model to the isolated worker model | Microsoft Learn\nAs I began to test my new and improved functions, most of them worked on first attempt —Service Bus triggers, Timer triggers, Durable Functions all performed as expected. Unfortunately that was not the case for my HTTP-triggered functions.\nFor an unknown reason I kept receiving a 500 Internal server error with logs indicating some kind of timeout error. The same behavior was observed whether I ran the function locally or deployed in Azure.\nThe most frustrating part was that if I spun up a new project in Isolated Mode and created an HTTP-triggered function from scratch, it worked perfectly fine without any issues.\nAfter a couple of hours of going around in circles and loosing what\u0026rsquo;s left of my hair, I stumbled upon this comment in an issue on the Azure Functions GitHub repo. The moment I read it, I knew I had found the culprit.\n🔗 Migrating azure functions to .net8 isolated, function hangs when triggered · Issue #2425 · Azure/Azure-Functions\nIndeed, there were some commented lines in my host.json file 😳, remnants of a test I made long time ago.\n🧑‍⚕️The diagnostic Removing these commented lines and deploying the project fixed the issue instantly and the HTTP-triggered function started to work as intended.\nIt seems that even if comments are not supported in the JSON specification, the In-Process model used to ignore and skip these commented line in the host file. That doesn\u0026rsquo;t seem to be the case with the Isolated worker model.\nI later discovered several threads like the one below, where others have encountered the same issue. However, there doesn’t seem to be a fix on the horizon.\n🔗 Using comments in host.json fails silently for isolated worker using the ASP.NET integration · Issue #2855 · Azure/azure-functions-dotnet-worker\n💊The fix Since the compiler will not prevent the deployment of a function app project with a host.json with commented lines, this can lead to big problems.\nFor example, if a developer inadvertently commit a commented host file and deploys the function app, HTTP trigger issues will only be caught at runtime and might take a while to diagnose.\nSometimes, there might actually be a good reason for these commented lines. For instance, developers might want to test certain host configurations or toggle parameters on and off without losing track of their original settings.\nHere’s how I updated my project build configurations and release pipeline to ensure this never happens, whether running locally or deployed in Azure.\nThe goal is to remove the host.json file commented lines in the build output folder while allowing them in source control. Special mention to GitHub Copilot who took care of crafting the regex and Powershell scripts for me. Thank you buddy 😉!\nFor this to work locally, I added this PostBuild command in the projects .cdsproj file.\n\u0026lt;Target Name=\u0026#34;PostBuild\u0026#34; AfterTargets=\u0026#34;PostBuildEvent\u0026#34;\u0026gt; \u0026lt;Exec Command=\u0026#34;powershell -NoProfile -ExecutionPolicy Bypass -Command \u0026amp;quot;Get-ChildItem -Path \u0026#39;$(TargetDir)\u0026#39; -Recurse -Filter \u0026#39;host.json\u0026#39; | ForEach-Object { (Get-Content $_.FullName) | Where-Object { $_ -notmatch \u0026#39;^\\s*//\u0026#39;} | Set-Content $_.FullName }\u0026amp;quot;\u0026#34; /\u0026gt; \u0026lt;/Target\u0026gt; For it to work in my Azure Devops release pipeline, I had to run this powershell script before the build step of the pipeline\n- pwsh: | Get-ChildItem -Path \u0026#39;$(Build.SourcesDirectory)\u0026#39; -Recurse -Filter \u0026#39;host.json\u0026#39; | ForEach-Object { Write-Host \u0026#34;Processing file: $($_.FullName)\u0026#34; (Get-Content $_.FullName) | Where-Object { $_ -notmatch \u0026#39;^\\s*//\u0026#39; } | Set-Content $_.FullName } displayName: \u0026#39;Remove commented lines from host.json files\u0026#39; And that\u0026rsquo;s it, I don\u0026rsquo;t have to worry anymore about breaking my HTTP triggered Azure Functions because of invalid host files.\nHope this helps.\nLinks Migrate .NET function apps from the in-process model to the isolated worker model This article shows you how to migrate your existing .NET function apps running on the in-process model to the isolated worker model. learn.microsoft.com .NET 6 will reach End of Support on November 12, 2024 .NET Blog: .NET 6 will reach end of support on Nov 12, 2024. After that, Microsoft will no longer provide updates for .NET 6. Security fixes and technical support will no longer be available for .NET 6. You’ll need to update to .NET 8 before this date to stay supported. Commercial support for… www.elevenforum.com Migrating azure functions to .net8 isolated, function hangs when triggered · Issue #2425 · Azure/Azure-Functions I am migrating from Azure Functions .Net 6 app to .Net 8 isolated and I am testing a demo function called HttpTriggerCSharp by debugging it in Rider (MacOs). The breakpoints have a green tick and w… github.com Using comments in host.json fails silently for isolated worker using the ASP.NET integration · Issue #2855 · Azure/azure-functions-dotnet-worker When using comments in host.json the file is not loaded and no error is reported. All settings set in host.json are ignored and the default settings are applied. There is no log output related to t… github.com Why JSON doesn’t allow comments Comments are probably one of the most under-appreciated aspects of coding. When you’re typing at lightning speed while listening to The… medium.com ","date":"2024-12-16T21:01:31Z","image":"/azure-function-isolated-worker-avoid-comments-in-the-host-file/4uh70x.jpg","permalink":"/azure-function-isolated-worker-avoid-comments-in-the-host-file/","title":"Azure Function Isolated Worker : Avoid comments in the Host file"},{"content":"The ability to assign managed identities to Dataverse plug-ins was recently introduced in the Power Platform and was received with waves of likes and thumbs up from the Power Platform community.\nRightfully so, this powerful feature enables Dataverse plug-ins to securely connect with Azure resources without the hassle of managing credentials.\nHowever, due to technical constraints and limited documentation, setting up plug-in managed identities is not that straightforward and can prove to be a daunting process, even for seasoned Power Platform developers.\nOne aspect that I found unintuitive is the creation of managed identity records in Dataverse and their association to plug-in assemblies. This sparked the idea for my latest community tool the Plugin Identity Manager for the XrmToolBox.\nYou can use the tool to:\n🔧 Create, Update and Delete Managed identity records in Dataverse\n🔗 Link Managed Identity to plugin assemblies\n👀 Inspect existing Plugin/Identity configuration\nIn the following, I will show how to setup a managed identity for a Dataverse plug-in from scratch and use the Plugin Identity Manager tool for the final configuration step.\nImportant! at the time of writing, managed identities for Dataverse plug-ins is still in preview. Some features and implementation details might change in the future.\nManaged Identities for Dataverse Plugins In a nutshell, Azure Managed Identity enables secure, password-free access to Azure resources, simplifying both security and management in the application lifecycle. Any Azure resource that supports Azure Entra authentication can be accessed by a managed identity, opening up a wide range of scenarios.\nI highly recommend these resources that goes deeper on the matter🔗Power Platform’s protection — Managed Identity for Dataverse plug-ins by MVP Raphaël Pothin 🔗Developer introduction and guidelines - Managed identities for Azure resources | Microsoft Learn\nAs a proof of concept, I will demonstrate how to access a secret stored in an Azure Key Vault from within a Dataverse plug-in using a managed identity, removing the burden of credential management to the Azure resource.\nI\u0026rsquo;ll create a Custom API—mainly for easier testing—that takes the name of a Key Vault and the name of a secret in the Key Vault as input and return its value as output. I’ll also output the token for testing purposes. Screenshot from my Custom API Manager tool for XrmToolBox\nThe code looks like this and basically recreate the following Rest Api call to the key vault.\nGET {vaultBaseUrl}/secrets/{secret-name}/{secret-version}?api-version=7.4\nusing Microsoft.Xrm.Sdk; using System; using System.Collections.Generic; using System.Net.Http.Headers; using System.Net.Http; namespace Dataverse.ManagedIdentity.Plugin { public class GetSecretValue : IPlugin { public void Execute(IServiceProvider serviceProvider) { // Get Services. var pluginExecutionContext = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext)); var identityService = (IManagedIdentityService)serviceProvider.GetService(typeof(IManagedIdentityService)); var inputparameters = pluginExecutionContext.InputParameters; var outputparameters = pluginExecutionContext.OutputParameters; //INPUT of the Custom API var keyvaultname = (string)inputparameters[\u0026#34;KeyVaultName\u0026#34;]; var secretname = (string)inputparameters[\u0026#34;SecretName\u0026#34;]; // Get Token var scopes = new List\u0026lt;string\u0026gt; { \u0026#34;https://vault.azure.net/.default\u0026#34; }; var token = identityService.AcquireToken(scopes); outputparameters[\u0026#34;Token\u0026#34;] = token; outputparameters[\u0026#34;Message\u0026#34;] = string.Empty; var keyvaultsecretUrl = $\u0026#34;https://{keyvaultname}.vault.azure.net/secrets/{secretname}?api-version=7.4\u0026#34;; try { using (HttpClient client = new HttpClient()) { client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(\u0026#34;Bearer\u0026#34;, token); client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue(\u0026#34;application/json\u0026#34;)); var request = new HttpRequestMessage(HttpMethod.Get, new Uri(keyvaultsecretUrl)); var response = client.SendAsync(request).Result; string json = response.Content.ReadAsStringAsync().Result; var keyVaultResponse = System.Text.Json.JsonSerializer.Deserialize\u0026lt;KeyVaultResponse\u0026gt;(json); outputparameters[\u0026#34;SecretValue\u0026#34;] = keyVaultResponse.value; outputparameters[\u0026#34;Success\u0026#34;] = true; } } catch (Exception ex) { outputparameters[\u0026#34;Success\u0026#34;] = false; outputparameters[\u0026#34;Message\u0026#34;] = ex.Message; } } } } public class KeyVaultResponse { public string value { get; set; } public string id { get; set; } } All the magic lies in the AcquireToken method call of the IManagedIdentityService. Without proper configuration of the managed identity on both the Azure and Dataverse sides, accessing key vault secrets will be out of reach to the plug-in code.\nI will follow the official documentation and try to fill the gaps where needed.\n🔗Set up managed identity for Power Platform (preview) - Power Platform | Microsoft Learn\nStep #1 : Sign the plugin with a certificate One of the first step in the process is to sign the plugin assembly with a certificate (.pfx signing) . This is essential otherwise an error will be thrown while trying to associate a Dataverse managed identity record to the plugin assembly.\nDespite years of development on the platform, I never signed plug-in assemblies with a certificate (.pfx) and had always relied on the simpler strong name signing (.snk). As a result, this part proved to be a bit tedious for me as I am not a security expert.\nThe official doc is a bit scarce on this aspect but I followed the recipe described in this great post by Clive Oldridge. It shows how to create a self-signed certificate ( not recommended for production) that will be enough for our experimentations.\nI\u0026rsquo;m copying the powershell script here but go see the entire blog post for more context\n🔗 Set up managed identity for Power Platform Plugins - Clive Oldridge on Power Platform Blog\n$ku_codeSigning = \u0026#34;1.3.6.1.5.5.7.3.3\u0026#34;; $codeSignCert = New-SelfSignedCertificate ` -Type \u0026#34;CodeSigningCert\u0026#34; ` -KeyExportPolicy \u0026#34;Exportable\u0026#34; ` -Subject \u0026#34;ManagedIdentityPlugin\u0026#34; ` -KeyUsageProperty @(\u0026#34;Sign\u0026#34;) ` -KeyUsage @(\u0026#34;DigitalSignature\u0026#34;) ` -TextExtension @(\u0026#34;2.5.29.37={text}$($ku_codeSigning)\u0026#34;, \u0026#34;2.5.29.19={text}false\u0026#34;) ` -CertStoreLocation cert:\\CurrentUser\\My ` -KeyLength 2048 ` -NotAfter ([DateTime]::Now.AddDays(90)) ` -Provider \u0026#34;Microsoft Software Key Storage Provider\u0026#34;; Once created, you can inspect the certificate with certmgr. Grab the value of the thumbprint, it will be needed later.\nNow, with the certificate at hand the plug-in assembly can be signed using this command.\nsigntool sign /n {{CERTIFICATENAME}} /fd SHA256 {{ASSEMBLYNAME}}.dll Although I much prefer setting up a post-build command in Visual Studio to automatically sign the assembly upon every successful build of the plug-in project.\n\u0026#34;C:\\Program Files (x86)\\Windows Kits\\10\\bin\\10.0.22621.0\\x64\\signtool.exe\u0026#34; sign /n {{CERTIFICATENAME}} /fd SHA256 $(SolutionDir)bin\\$(Configuration)\\{{ASSEMBLYNAME}}.dll Once the plug-in assembly is signed, you can assess the presence of the signature by inspecting the file properties.\nThat’s one big step down! Now, let’s head over to the Azure setup.\nStep #2 : Configure the managed identity in Azure Two types of managed identities can be configured: a user-assigned managed identity or an application registered in Microsoft Entra ID.\nFor the current scenario, I will create a user-assigned managed identity, easily available to create from the Azure Portal.\nAssign the identity to a resource group and give it a name.\nOnce created, keep the Client ID at hand it will be needed later on.\nNext, grant the newly created identity access to the required Azure resources via the Azure role assignment tab. Here the Key Vault Secrets User RBAC role is given on the Key Vault we want to expose to the plug-in.\nNow on to the trickiest—and, in my opinion, under-documented—part: configuring federated credentials for managed identity.\nBefore starting the configuration have these info at hand\nDataverse Environment Id Thumbprint of the certificate Navigate to the Federated credentials tab and click on Add Credential\nSelect Other as Federated credential scenario\nAnd enter the following configurations.\nIssuer Url: Take the Dataverse Environment ID (GUID), remove the dashes, and format it by placing a period between the first 30 characters and the last 2 characters to construct the Issuer URL.\nhttps://{ENVID_FIRST30}.{ENVID_LAST2}.environment.api.powerplatform.com/sts\nex. https://3608895ef8844a53a065b306837e60.96.environment.api.powerplatform.com/sts\n2- Subject : Important! I went through some trial and error here, but this configuration finally worked for me. The thumbprint must be in uppercase, and the environment Id should be in the usual GUID format (lowercase with dashes)\ncomponent:pluginassembly,thumbprint:{THUMBPRINT_UPPERCASE},environment:{ENVID}\nex. component:pluginassembly,thumbprint:6C79AFBC726410ECB5A821F7C4663EC0299CD748,environment:3608895e-f884-4a53-a065-b306837e6096\nAudience : By default the audience is set to api://AzureADTokenExchange. I found out that the audience needed to be set in lowercase api://azureadtokenexchange otherwise errors where thrown\nHere is the error I got when using the default value, after I changed the audience to lowercase, it went through correctly.\nAn unexpected error occurred: Microsoft.Identity.Client.MsalServiceException: A configuration issue is preventing authentication - check the error message from the server for details. You can modify the configuration in the application registration portal. See https://aka.ms/msal-net-invalid-client for details. Original exception: AADSTS7002122: No matching federated identity record found for presented assertion audience \u0026rsquo; api://azureadtokenexchange\u0026rsquo;. The audience matches with case-insensitive comparison, but not with case-sensitive comparison. Please check your federated identity credential Subject, Audience and Issuer against the presented assertion. https://learn.microsoft.com/entra/workload-id/workload-identity-federation\nAnd now, the final piece of the puzzle—where I finally get to show off my tool! 😉\nStep #3 : Configure the managed identity in Dataverse Now that all is set in Azure, its time to register the managed identity in Dataverse and associate the record to the plugin assembly.\nSince there is no available UI for Managed Identity records in Dataverse, the official documentation instruct the user to make 2 platform WebApi requests.\nPOST https://\u0026laquo;orgURL\u0026raquo;/api/data/v9.0/managedidentities\n{ \u0026#34;applicationid\u0026#34;:\u0026#34;\u0026lt;\u0026lt;appId\u0026gt;\u0026gt;\u0026#34;, \u0026#34;managedidentityid\u0026#34;:\u0026#34;\u0026lt;\u0026lt;anyGuid\u0026gt;\u0026gt;\u0026#34;, \u0026#34;credentialsource\u0026#34;:2, \u0026#34;subjectscope\u0026#34;:1, \u0026#34;tenantid\u0026#34;:\u0026#34;\u0026lt;\u0026lt;tenantId\u0026gt;\u0026gt;\u0026#34; } PATCH https:// \u0026laquo;orgURL\u0026raquo;/api/data/v9.0/pluginassemblies(\u0026laquo;PluginAssemblyId\u0026raquo;)\n{ \u0026#34;managedidentityid@odata.bind\u0026#34;: \u0026#34;/managedidentities(\u0026lt;\u0026lt;ManagedIdentityGuid\u0026gt;\u0026gt;)\u0026#34; } While, there\u0026rsquo;s nothing wrong with making Web API calls if you\u0026rsquo;re comfortable with it, I think it falls short in terms of intuitive user experience. This is where the Plugin Identity Manager for the XrmToolBox comes in and brings value to the table.\nYou can download the tool from the Tool Library of the XrmToolBox\nSelect plugin assembly The first thing to do after firing up the tool is to choose your plug-in assembly. You have the choice to list all the plugins assembly installed in the environment of choose a given solution. You can also filter out managed or unmanaged assemblies.\nCreate and Assign a new Managed Identity Record Once the plug-in selected, you can create a new Managed Identity record to associate with the assembly by clicking Link to New Identity\nIn the creation screen you are invited to set these parameters :\nName : I have defaulted to \u0026rsquo; {Plugin Name} Identity\u0026rsquo; but you can enter what you want. The official docs doesn\u0026rsquo;t highlight the Name field in the Web API call example, but it’s good practice to assign a name to the record. This makes it easier to manage and include in a solution later on.\nApplicationId: This is the ClientId of of the managed identity created in Azure. TenantId: the GUID of the tenant where the Azure resource is located Credential Source : I am defaulting and forcing the \u0026rsquo; IsManaged (2)\u0026rsquo; value as the other available values seems to be reserved by Microsoft for internal scenarios. Drop me a line in the Github repo if you want me to open this. Subject Scope : I default to \u0026rsquo; Environment Scope (1)\u0026rsquo; but there are 2 other values. Global Scope or DevOnly Scope. Environment Scope limits the managed identity to the same tenant as the Dataverse environment. Global scope, on the other hand, would enable access to Azure resources located on another tenant. Note that I haven\u0026rsquo;t tested Global scope yet and am unsure if it\u0026rsquo;s available in the preview release of the feature.\nBy clicking on Create and Link, the managed identity record will be created and associated with the selected plug-in assembly.\nAt this point all the configuration is done and we can proceed to the testing phase. But here are some additional features of the tool.\nAssign to an existing Managed Identity Record If the desired Managed Identity record already exists, you also have the choice to Link to existing Identity\nThis will display a list of the Managed Identity records where credential source is \u0026rsquo; IsManaged (2)\u0026rsquo; allowing you to link them to the selected plug-in.\nUpdate/Delete a Managed Identity Record The tool allows modification of a Managed Identity record\u0026hellip;\n\u0026hellip; And deletion as well\nWithout further ado, let\u0026rsquo;s proceed to the testing phase.\nStep #4 : Test the plug-in Now comes the moment of truth—testing whether the plugin code can successfully access the Azure Key Vault secret.\nIn the Key Vault ( kv-isv-dev) that I’ve granted access to the managed identity, I have created a secret named MySecret.\nUsing the Custom API Tester Tool from Jonas Rapp, I can execute the plug-in code.\nWith the GetSecretValue Custom API ( described earlier) selected, simply provide the name of the Azure Key Vault, the name of the secret and Execute the API.\nIf all is well configured, the value of the secret is correctly retrieved by the plug-in code. All without any credentials, thanks to the managed identity and the federated credential.\nThat is all for now ;)\nTake Away Overall, managed identities for Dataverse plug-ins is a great new feature that deserves to be on Power Platform developers radar. But, you\u0026rsquo;ll have to admit that there is a certain complexity associated with the process. It’s important to weigh the pros and cons before pursuing this approach.\nI hope that some of you will find the Plugin Identity Manager tool useful to make the setup experience more enjoyable and coherent. Please submit any comments or ideas to improve the tool in the github repo\nThere’s much more to discuss on the subject, such as current limitations and ALM considerations, but that’s beyond the scope of this blog post. I will certainly continue my experimentations and share my findings.\nUntil then,\nLinks GitHub - drivardxrm/Driv.XTB.PluginIdentityManager: XrmToolBox Tool to help manage Managed Identity records in Dataverse XrmToolBox Tool to help manage Managed Identity records in Dataverse - drivardxrm/Driv.XTB.PluginIdentityManager github.com Power Platform managed identity overview (preview) - Power Platform Learn about managed identity for Power Platform and Dynamics 365 apps. learn.microsoft.com Set up managed identity for Power Platform (preview) - Power Platform Learn how to set up Power Platform managed identity. learn.microsoft.com Set up managed identity for Power Platform Plugins - Clive Oldridge on Power Platform Blog In the following blog, I’m going to guide you on the set up of managed identity for Power Platform. Once we have finished you should have everything you need to be able to create a plugin that can communicate with an azure resource. Why do we want to use manage identity? Managed identity allows your […] coldridge.azurewebsites.net Power Platform’s protection — Managed Identity for Dataverse plug-ins Once the network traffic is secured it is time to get out of the way identity credentials to integrate with Azure resources medium.com Use managed identities for Dataverse plug-ins Power Platform managed identities allow publishers of Dataverse plug-ins to securely connect to Azure resources without having to store or expose credentials. learn.microsoft.com Power Platform | Managed Identity – bearer token generation w/o Application Id and Secret Reference – [Note : This is in Preview] Power Platform managed identity allows Dataverse plug-ins to connect with Azure resources supporting managed identity without the need of credentials. … malvankaraniket.wordpress.com Image by freepik\n","date":"2024-11-03T19:41:42Z","image":"/how-to-secure-a-dataverse-plug-in-with-managed-identity-using-plugin-identity-manager-for-xrmtoolbox/3148275-min-scaled.jpg","permalink":"/how-to-secure-a-dataverse-plug-in-with-managed-identity-using-plugin-identity-manager-for-xrmtoolbox/","title":"How to Secure a Dataverse Plug-in with Managed Identity using Plugin Identity Manager for XrmToolBox"},{"content":"Although not officially released, there are strong signals that the support for Dark mode 🌚 is coming very soon to Power Platform Model-Driven apps.\nRecent investments made in the platform like the \u0026rsquo; New look\u0026rsquo; that leverages the Fluent 2 design system are paving the way to Dark Mode.\n🔗 Adapting PCF Controls for Model Driven apps New (Modern) Look\n🔗 Modern, refreshed look for model-driven apps - Power Apps | Microsoft Learn\nWhile we wait for an official Dark Mode toggle, thanks to Andrew Butenko ( \u0026hellip;whom I finally had the chance to meet at the last MVP Summit 😎🍺) we now have a way switch to dark mode by adding the following snippet to the URL of a Model-Driven app.\n\u0026amp;flags=themeOption%3Ddarkmode MDA dark theme in #Dynamics365 | Andrew Butenko posted on the topic | LinkedIn Did you know that a dark theme is available in #MDA? I did not. To check it out turn on \u0026#34;New Look\u0026#34; and add the e following text to the URL -… | 19 comments on LinkedIn www.linkedin.com The end result is pretty neat, despite some noticeable icons rendering issues, and I will probably use Dark Mode by default after official release.\nBut what about PCF Controls ? However, as a PCF control author, I\u0026rsquo;m always very eager each time that there is a new feature that affects the UI of the platform. It often means that I will have to go back to the drawing board and adapt my controls for the new kid in town.\nAnd as a matter of fact, that is exactly what happens with the Dark Mode switched on. You can see that the PCF controls are still rendering like they do in light mode \u0026hellip; How would they know.\nHere\u0026rsquo;s an example of my latest community PCF control, the FluentUI Month Picker\nHow to detect Dark mode at runtime ? Fortunately, it is quite trivial to detect if a PCF control should render in Dark mode or not.\nBy inspecting the context object received by the PCF control at runtime, we can see that context.fluentDesignLanguage.isDarkTheme property will give us the answer.\nAfter that its a matter of rendering the control with a Dark or Light theme depending on that value.\n🎯 Bonus point if you\u0026rsquo;ve already started to use FluentUI v9 to develop your controls. Since the theme is injected at the very root of the control in the FluentProvider, just provide webDarkTheme or webLightTheme accordingly and there is nothing else to do.\nNote that these are the exact same themes used by the platform so your controls have a better chance to blend perfectly with the rest of the form.\nMore on theming :🔗 Concepts / Developer / Theming - Page ⋅ Storybook (fluentui.dev)\nNow as expected, the control will render with the right theme depending on the users display preferences\u0026hellip; it\u0026rsquo;s that easy.\nUsing this technique we can future-proof PCF controls and make them Dark Mode aware ahead of time. Hope this helps!\nLinks FluentUI Month Picker A control to select a month and optionally outputs some information about the selected month (ex. month number, number of days in month). pcf.gallery Modern, refreshed look for model-driven apps - Power Apps Learn about the updated, user interface that makes model-driven apps easier to use. learn.microsoft.com Fluent UI React Fluent UI React Components is a set of UI components and utilities resulting from an effort to converge the set of React based component libraries in production today: @fluentui/react and @fluentui/react-northstar. react.fluentui.dev Image by Enrique from Pixabay\n","date":"2024-04-05T04:03:22Z","image":"/how-to-get-pcf-controls-ready-for-dark-mode-in-model-driven-apps/fantasy-4566021_1280.jpg","permalink":"/how-to-get-pcf-controls-ready-for-dark-mode-in-model-driven-apps/","title":"How to Get PCF Controls Ready for Dark Mode in Model-Driven Apps"},{"content":"As Microsoft pursues its One Dynamics, One Platform initiative, substantial investments are made to integrate the D365 Finance and Operations suite with the Power Platform and Dataverse.\nThese includes the ability to surface most F\u0026amp;O tables as virtual entities in Dataverse. Bringing full CRUD capabilities, but also opening up the whole Power Platform ecosystem to consume and act on F\u0026amp;O data. Think Power Automate, Model-driven and Canvas Apps, PCF Controls, Power Pages, etc.\nWhile experimenting with Finance and Operations virtual entities, I found gaps in the tooling and processes required to enable and manage them. This led to the inception of my latest tool for the XrmToolBox, the FinOps Virtual Entity Manager.\nHere are the main features that I\u0026rsquo;ll explain later on :\n- 📋List/Filter available Finance and Operations entities\n- 👁️Enable/Disable visibility of entities in Dataverse (Virtual entity enabled)\n- 🔁Enable/Disable change tracking of entities\n- 🔄Refresh entity metadata\n- 🤝Integrated with the Metadata Browser Companion from Tanguy Touzart to explore virtual entities attributes\nBut first, let\u0026rsquo;s put things in context.\nMy ode to XrmToolBox For most Power Platform developers, the XrmToolBox needs no introduction. But if you come from the F\u0026amp;O world you might not be familiar with this ecosystem and could be wondering what the fuss is all about.\nTo make a long story short, the XrmToolBox is a versatile and robust toolkit for Dynamics 365 and Power Platform professionals developed and maintained an by Tanguy Touzart.\nWith its user-friendly interface to organize environment connections and extensive range of powerful plugins developed by the community, the XrmToolBox helps users to streamline development, customization, administration and troubleshooting tasks within Power Platform environments.\nQuite frankly, I think I can count on my fingers the days that I haven\u0026rsquo;t opened the toolbox on my day to day activities. Some of these tools have literally saved my sanity more than once.\nAlso as a tool author myself, the platforms provides a level of reach and exposure that would be impossible to achieve independently, thanks to its widespread use.\nSo, wait no more and install the toolbox and be sure to download the FinOps Virtual Entity Manager (\u0026hellip;and my other tools at the same time\u0026hellip; shameless plug 😏 )\nBackground and Pre-requisites Even if they are often marketed together (under the Dynamics 365 umbrella), Finance and Operations and Power Platform / Dataverse are two entirely distinct product offerings. Each possesses its own unique architecture and serves vastly different purposes.\nFor the digital archeologists, Finance and Operations is derived from Dynamics AX whereas PP/Dataverse get its roots from Dynamics CRM and has dramatically evolved to the current PaaS (Platform as a service) that we know and love today.\nIn an effort to integrate and bring these 2 products together, the product team have made it quite easy to integrate a Finance and Operations environment to a PP/Dataverse environment through the Lifecycle Services portal. This setup goes beyond the scope of this blog post but you can find relevant info here.\n🔗 Enable Power Platform Integration - Finance \u0026amp; Operations | Dynamics 365 | Microsoft Learn\n🔗 One Dynamics One Platform - Dataverse C# Plugin for Dynamics 365 F\u0026amp;O — PowerAzure365\nOnce the integration completed you can appreciate a new Finance and Operations URL when navigating to the linked Dataverse environment from the Power Platform Admin Center (PPAC)\nThis is where the fun begins 😎.\nConnecting to the Tool I won\u0026rsquo;t go in details on how to setup connections for the XrmToolBox, it\u0026rsquo;s a vast topic, but here is an helpful link\n🔗 Connecting to an environment · XrmToolBox\nOnce connected to an FinOps/Dataverse linked environment, if you fire up the FinOps Virtual Entity Manager, you\u0026rsquo;ll be presented with the respective URLs of the Dataverse and the FinOps environments.\nBy clicking on the Load/refresh entities the list of Available Finance and Operations entities will be loaded on screen.\nIf you are interested on what is happening under the hood, I simply fetch the data from the mserp_financeandoperationsentity table that is itself a Virtual entity that is created part of the FinOps/Dataverse integration.\nAs you can see here, I\u0026rsquo;m querying the entity using SQL 4 CDS by Mark Carrington, another essential tool of the xrmTooolBox.\nNavigating through the entities There are about 3000 exposed entity coming from FinOps, so its important for the tool to be able to filter the tables to give a better user experience.\nThe tool, currently supports filter on the physical name, visible (virtual enabled) and change tracking enabled fields.\nAct on selected Finance and Operations entities By selecting a table from the list of available entities, this will populate the side-pane with the table info and give users the possibility to take action on certain parameters of the table.\n👁️Enable/Disable visibility (Virtual entity enabled) Enabling visibility of a F\u0026amp;O table will automatically expose that table as a Virtual entity in Dataverse. The new virtual entity will be prefixed with mserp_ in the environwement.\nIn the PowerApps maker portal you will see the table like this.\nFrom now on, the bar is open for that table on Dataverse side. you can for example :\nQuery the data from Dataverse like any other native tables Act on the data with Power Automate, Dataverse plugins, Custom APIs Create rich user interfaces with full CRUD capabilities like Model Driven apps, Canvas apps and Power Pages. Create relationships between native Dataverse tables and FinOps tables ( that one is pretty impressive) Note that the security/licensing context is not bypassed here, all consuming users need to be properly configured in Finance and Operations.\n🔁Enable/Disable change tracking of entities\nFor certain scenarios like Synapse link / Fabric integration of the tables data, its necessary to enable the change tracking at the virtual table level.\nUnfortunately the switch to enable change tracking is grayed out if you want to set it up at the table level in the maker portal.\nBy using the tool you can easily enable the change tracking of the FinOps virtual entity.\nThe virtual entity will then show up with the Track Changes switch enabled in the maker portal.\nAs mentioned by Nurlin Aberra in a recent post, if you run into errors while activating the change tracking property, you might want to check these requirements on the Finance and Operation side\nRow version change tracking for tables and data entities - Finance \u0026amp; Operations | Dynamics 365 | Microsoft Learn\n🔄Refresh entity metadata\nIf fields are added on an F\u0026amp;O tables afterward, you will want to update the metadata of the virtual entity, this is where you will use the Refresh Metadata switch on the entity\nI haven\u0026rsquo;t really tried it but, it speaks for itself.\nExplore Metadata This feature is among my top favorites in the tool, mostly because I only had to write one single line of code to integrate my tool with the awesome Metadata Browser Companion tool from Tanguy Touzart.\nThe end-result is quite slick IMHO as the user doesn\u0026rsquo;t even notices that there is a second tool involved. Kudos to Tanguy for making his tool extendable.\nAs you can see, clicking on the Explore with Metadata Browser opens the companion tool and we can drill-down on all the available metadata of the virtual entity including the newly created relationships demonstrated earlier\nTakeAway That\u0026rsquo;s it for now, I hope the tool will be helpful to some of you, as I really think it fills a gap. Please reach out if you have any comments or have any ideas for improvements, feedback is greatly appreciated ( link to the github repo below).\n🔗 drivardxrm/Driv.XTB.FinOpsVirtualEntityManager: XrmToolBox tool to manage Finance and Operations Dataverse Virtual Entities (github.com)\nSpeaking of the FinOps/Dataverse convergence, I see a lot of potential especially on the edges of the Finance and Operations ERP. Some scenarios like data entry, acting on business events and reporting might benefit from the Power Platform in the long run.\nAlso please note that I consider myself a total newbie on Finance and Operations, as I\u0026rsquo;ve only recently been exposed to it. Therefore, the views expressed in this post might be tainted by the Power Platform lens which is what I know best. I would love hear from Finance and Operations experts on that topic and understand what challenges they foresee with such architectural approaches.\nUntil then\u0026hellip;\nLinks GitHub - drivardxrm/Driv.XTB.FinOpsVirtualEntityManager: XrmToolBox tool to manage Finance and Operations Dataverse Virtual Entities XrmToolBox tool to manage Finance and Operations Dataverse Virtual Entities - drivardxrm/Driv.XTB.FinOpsVirtualEntityManager github.com Enable Power Platform Integration - Finance \u0026amp; Operations | Dynamics 365 This article explains how to enable the Microsoft Power Platform integration by using Microsoft Dynamics Lifecycle Services for finance and operations apps and Dataverse. learn.microsoft.com Virtual entities overview - Finance \u0026amp; Operations | Dynamics 365 This article provides general information about virtual entities for finance and operations apps. learn.microsoft.com Home · XrmToolBox XrmToolBox is a Windows application that connects to Microsoft Dataverse. Dynamics 365 Customer Engagement (CE) applications, like Dynamics 365 for Sales, Service or Talent also use Microsoft Dataverse as their foundational data service. XrmToolBox, provides tools to ease customization, configuration and operation tasks for anything built on Microsoft Dataverse, including Dynamics 365 CE (formerly CRM) and model-driven PowerApps. It is shipped with more than 30 tools to make administration, customization or configuration tasks easier and less time consuming. And more than 100 other tools are available in the Tool Library. www.xrmtoolbox.com Connecting to an environment · XrmToolBox XrmToolBox is able to connect to any kind of environment from Microsoft Dynamics CRM 2011 to Microsoft Dynamics 365 for Customer Engagement and Power Apps Common Data Service, using one of the available connection methods. www.xrmtoolbox.com SQL 4 CDS · XrmToolBox SQL 4 CDS allows you to use standard SQL syntax to query and manipulate your data and metadata in Dataverse / D365. www.xrmtoolbox.com Welcome to Metadata Browser companion Today, I’m releasing my first companion for XrmToolBox. What? You don’t know what a XrmToolBox companion is? It’s a compact tool designed to be used aside other tools in XrmToolBox. www.linkedin.com One Dynamics One Platform - Dataverse C# Plugin for Dynamics 365 F\u0026amp;O — PowerAzure365 An article part of the One Dynamics One Platform convergence : on the Dev side : How to deploy a Dataverse C# Plugin for a Virtual Table of Dynamics 365 Finance Operations. www.powerazure365.com Is it feasible to employ T-SQL for querying Dynamics 365 FO virtual entities and executing advanced queries? Could T-SQL queries be employed to access Dynamics 365 FO virtual entities? Although querying Dataverse tables is known, can Dynamics 365 FO virtual entities be queried would it be possible to perform joins across different Dynamics 365 FO virtual entities, along with aggregate functions ? Initially www.linkedin.com Image by PublicDomainPictures from Pixabay\n","date":"2024-02-25T14:52:19Z","image":"/finance-and-operations-virtual-entity-manager-for-xrmtoolbox/hands-20333_1280.jpg","permalink":"/finance-and-operations-virtual-entity-manager-for-xrmtoolbox/","title":"Finance and Operations Virtual Entity Manager for XrmToolBox"},{"content":"Recently, while developing a PCF control with the FluentUI React v9 library, I encountered a rather unusual and annoying runtime display bug. Its resolution ended up shedding light on an important concept that had previously escaped my attention and I thought it deserves its own blog post.\n🤒The symptoms The control I was developing is my latest community PCF control, the FluentUI Month Picker.\n🔗FluentUI Month Picker | PCF Gallery 🔗 GitHub repo : drivardxrm/FluentUI.MonthPicker.PCF\nGiven that FluentUI v9(@fluentui/react-components) is the main library used by the platform to render form elements when the New Look switch is activated\u0026hellip; see my previous blog post. I decided to use it in my project to replicate the look and feel of a native date picker.\nThe control functioned perfectly within the PCF test harness during development. However, upon deployment to a live Dataverse environment and integration into a form, inconsistencies surfaced in the display of the calendar pop-over.\nAs you can see in the image below, the styling of the calendar is off and the surface is transparent.\nMoreover, as soon as I selected a month in the calendar, the styling magically started to be applied correctly.\nThe cherry on top, this display issue seemed to happen only if my PCF control was configured on the first field of the form.\n🧑‍⚕️The diagnostic After struggling to find a solution and testing various approaches in vain, I decided to be pragmatic and look at the developer logs of the browser. Turns out that the answer was right there under my nose.\nI noticed this error message about conflicting DOM ids in the rendered page coming from the fluentui/react-provider library.\nInterestingly, the error message provides a link to the Advanced Configuration section of the FluentUI v9 documentation. This section explains the issue and offers a comprehensive solution.\n🔗Concepts / Developer / Advanced Configuration - Page ⋅ Storybook (fluentui.dev) 🔗feat: add IdPrefixProvider by layershifter · Pull Request #26496 · microsoft/fluentui (github.com)\n💊The fix One of the first thing to consider when working with FluentUI v9 is to wrap your application with a FluentProvider. This component is plays a crucial role in injecting both the theme and styles into the application.\nimport { Button, FluentProvider, webLightTheme } from \u0026#39;@fluentui/react-components\u0026#39; const SimpleApp= (): JSX.Element =\u0026gt; \u0026lt;FluentProvider theme={webLightTheme}\u0026gt; \u0026lt;Button appearance=\u0026#34;primary\u0026#34;\u0026gt;Hello FluentUI React v9\u0026lt;/Button\u0026gt; \u0026lt;/FluentProvider\u0026gt; export default SimpleApp See my previous blog post on PCF control development with FluentUI v9 for more context\n🔗 Develop PCF Controls with FluentUI React v9 - It Must Be Code!\nNow, Since FluentUI is also used natively by the PowerPlatform and that other PCF controls on the form might also bring their own flavor of the provider, chances are that we end up with multiple instances of FluentProvider with the same DOM id on the page at runtime. When this happens, it can cause interop problems, thus the display bug encountered earlier.\nTo mitigate this, we need to wrap the application with another component, IdPrefixProvider and provide an APPID. This ensures that the id of the rendered html element is unique by prefixing the standard id with the given APPID.\nimport { Button, FluentProvider, IdPrefixProvider, webLightTheme } from \u0026#39;@fluentui/react-components\u0026#39; const SimpleApp= (): JSX.Element =\u0026gt; \u0026lt;IdPrefixProvider value=\u0026#34;APPID-\u0026#34;\u0026gt; \u0026lt;FluentProvider theme={webLightTheme}\u0026gt; \u0026lt;Button appearance=\u0026#34;primary\u0026#34;\u0026gt;Hello FluentUI React v9\u0026lt;/Button\u0026gt; \u0026lt;/FluentProvider\u0026gt; \u0026lt;/IdPrefixProvider\u0026gt; export default SimpleApp Here is how I implemented the fix in my PCF control code. By adding a prefix that identifies the control \u0026rsquo; month-picker-\u0026rsquo; and an \u0026rsquo; instanceId\u0026rsquo; (randomly generated GUID), I can be sure that each possible instance of the control on a form will have a different prefix id.\nAs you can see in the image below, the FluentProvider root html element gets prefixed accordingly.\nAs soon as I deployed the version with the prefixed FluentProvider, collision errors were resolved and my PCF controls started to render flawlessly 💪.\nTakeaway Moving forward, I will always use the IdPrefixProvider in my PCF controls that uses FluentUI v9. This simple trick not only safeguards against DOM Id collisions but also enhances the overall robustness of PCF controls implementations.\nHope this helps,\nLinks Fluent UI React Fluent UI React Components is a set of UI components and utilities resulting from an effort to converge the set of React based component libraries in production today: @fluentui/react and @fluentui/react-northstar. react.fluentui.dev feat: add IdPrefixProvider by layershifter · Pull Request #26496 · microsoft/fluentui New Behavior This PR implements IdPrefixProvider for @fluentui/react-components. This feature allows to better control automatically generated IDs: /* All ids in a scope will start with “scope-” */… github.com Develop PCF Controls with FluentUI React v9 Explore FluentUI React v9 and the experience of developing Power Apps Component Framework controls with the new component library. itmustbecode.com FluentUI Month Picker A control to select a month and optionally outputs some information about the selected month (ex. month number, number of days in month). pcf.gallery GitHub - drivardxrm/FluentUI.MonthPicker.PCF: PCF Control that renders a Month picker over a Date column PCF Control that renders a Month picker over a Date column - GitHub - drivardxrm/FluentUI.MonthPicker.PCF: PCF Control that renders a Month picker over a Date column github.com Image by Marcel Langthim from Pixabay\n","date":"2024-01-16T02:24:28Z","image":"/pcf-controls-with-fluentui-v9-avoid-dom-id-collisions/crash-test-1620591_1280.jpg","permalink":"/pcf-controls-with-fluentui-v9-avoid-dom-id-collisions/","title":"PCF Controls with FluentUI v9 - Avoid DOM id collisions"},{"content":"If you\u0026rsquo;re a user of a Power Platform\u0026rsquo;s model-driven app, you\u0026rsquo;ve likely come across the \u0026rsquo; Try the new look\u0026rsquo; switch appearing on your app header.\nIndeed, toggling this switch will result in the platform adopting a modern Fluent Design System (a.k.a. Fluent 2) for rendering model-driven form elements such as fields and command bars.\nWhile this evolution is undoubtedly a positive and necessary step for the platform as a whole, it can present several challenges for PCF Control authors aiming to ensure their controls seamlessly blend with the out-of-the-box UI, delivering a polished user experience.\nIn this article, I will demonstrate a method to dynamically detect whether the user has activated the New Look feature within the PCF business logic and adapt the control\u0026rsquo;s rendering accordingly.\nUnder the hood of the New Look As said before, switching to new look will completely change the rendering of model driven app form and use a Modern Fluent design system. Under the hood, the main rendering library for form components changes from Fluent UI React 8 ( @fluentui/react) to FluentUI React 9 ( @fluentui/react-components).\nLink to Microsoft official announcement 🔗Modern, refreshed look for model-driven apps - Power Apps | Microsoft Learn\nAs an example, see below the difference observed for a Choice field (dropdown list). You can see that the difference is notable.\nAs of now, its every users decision if they want to use the new look or if they prefer to stay with the previous version by toggling the \u0026rsquo; Try the new look\u0026rsquo; switch on the header.\nHow does this impact PCF Controls PCF controls (PowerApps Component Framework) are customizable components that extends the functionality of Microsoft Power Platform and Model-Driven Apps by allowing developers to create and integrate custom UI elements and business logic.\nTo ensure a smooth user experience, it\u0026rsquo;s crucial to deliver controls that seamlessly integrate with the overall form. For this reason, making use the Fluent UI React 8 library was an obvious choice for PCF developers, given that it was the library used internally to render other form elements.\nHere are some of my community PCF Controls that are leveraging FluentUI React 8\n🔗Lookup Dropdown PCF | PCF Gallery\n🔗Country Picker | PCF Gallery\nNow, with the advent of the New Look, the situation has taken a different turn. I would encourage PCF developers to initiate the transition of their controls to Fluent UI React 9 as soon as they can.\nFurthermore, considering that end users have the flexibility to switch between the two rendering modes, it would be advantageous for PCF controls to transition contextually from a Fluent UI version 8 to version 9 implementation when necessary.\n💡Transitioning from Fluent UI version 8 to version 9 is not merely a straightforward update; it represents a complete architectural overhaul of the library. The development experience is completely different and I personally find FluentUI 9 to be much more enjoyable.\nYou can have a look at my previous blog post on the subject 🔗Develop PCF Controls with FluentUI REact 9\nLet\u0026rsquo;s see how we can detect the user look and feel selection inside a PCF control logic.\nIdentify the Look chosen by the user As a proof of concept, I developed an extremely basic PCF control, intentionally lacking any complex logic, that renders an input field. The objective is to identify the user\u0026rsquo;s choice (New Look or Old Look) and display an input field that seamlessly integrates with the overall form design.\nYou can find the source code on Github: 🔗drivardxrm/NewLookSwitchTest.PCF\nThrough examining the context object provided to the PCF control in both scenarios, one with the New Look feature enabled and the other without, we can see that the ( undocumented) \u0026rsquo; fluentDesignLanguage\u0026rsquo; property exclusively holds a value when the New Look feature is turned on.\nWith this information at hand, it\u0026rsquo;s simply a matter of offering two implementations of the control and rendering them accordingly based on the user\u0026rsquo;s choice.\nFeel free to review the source code for the individual implementations. However, as depicted in the images below, you can see that the rendering of the PCF control changes when the New Look feature is activated.\nAdditionally, both implementations integrate seamlessly with their respective Form design system.\nTakeAway All this is good for blog post material, but there are some things to take into considerations for developers who would go down that path.\nIntroducing dual implementations can entail additional complexity and potentially result in larger bundle size. Ultimately, it comes down to striking the appropriate balance between development cost, maintenance, and delivering an optimal user experience.\nAt least, its good to know that there is a way (even if unsupported) to detect the user look and feel selection at runtime and insure backward compatibility during the transition period.\nNow, If you\u0026rsquo;ll excuse me, I have a lot of work on my plate to migrate all my existing PCF control projects🥴.\nPhoto by Nadine Shaabana on Unsplash\nLinks Fluent 2 Design System Explore the next evolution of Microsoft’s design system, enabling more seamless collaboration and creativity than ever. Move fluidly from design to development, between apps, and across platforms. fluent2.microsoft.design Modern, refreshed look for model-driven apps - Power Apps Learn about the updated, user interface that makes model-driven apps easier to use. learn.microsoft.com Develop PCF Controls with FluentUI React v9 Explore FluentUI React v9 and the experience of developing Power Apps Component Framework controls with the new component library. itmustbecode.com Home - Fluent UI The official front-end framework for building experiences that fit seamlessly into Microsoft 365. developer.microsoft.com ","date":"2023-10-17T01:59:13Z","image":"/adapting-pcf-controls-for-model-driven-apps-new-modern-look/nadine-shaabana-UBvF7tGcLdg-unsplash-scaled.jpg","permalink":"/adapting-pcf-controls-for-model-driven-apps-new-modern-look/","title":"Adapting PCF Controls for Model Driven apps New (Modern) Look"},{"content":"The Power Apps grid control is a new and improved version for the data grid control for Power Platform model-driven applications. It introduces a modern data grid user experience and a range of noteworthy features, including the ability to perform inline editing and seamless infinite scrolling of the grid records, amongst others.\nSimply implement the Power Apps grid control component on your applications data grids (table views or form subgrids) to unlock up its capabilities.\nMoreover, as a developer, one of the most appealing aspects of the new grid control is the ability to customize the look and feel of the grid columns using specialized PCF (PowerApps Component Framework) controls known as Cell Renderers.\nAlthough, like my fellow MVP Diana Birkelback explained in her great post on the subject, the current architecture of cell renderers lacks the ability to inject parameters to the control ( like you can do with a normal PCF control) to make them more generic and reusable.\nIn this post I will show how I was able to attain a certain degree of genericity by making the cell renderer aware of their root table(entity) and how to obtain runtime information about lookup fields present in the underlying grid data.\nThe end-result can be appreciated in my latest community PCF project, the RecordImage Cell Renderer.\nThe control turns a plain out-of-the box grid like this one.\nInto a visually appealing grid as seen below.\nPlease check the source code for more in-depth info\n🔗drivardxrm/RecordImage.CellRenderer: Cell renderer for PowerApps Grid (github.com)\nWhat is the PowerApps Grid Control Before diving in the cell renderer specific stuff, I think that the PowerApps Grid control deserves a bit of attention as it will become the default experience for model-driven grids in the near future.\n\u0026quot; This control will eventually replace all read-only and editable grids in model-driven apps.\u0026quot;\n🔗 Power Apps grid control - Power Apps | Microsoft Learn\nofficial Microsoft documentation\nThe PowerApps Grid control acts as a one-stop shop where you can define the behavior and the look of your apps grids. The official documentation is a great resource to get a better understanding of all the features included with the control, but here are some of my favorites.\nSwitch from Read-Only to Editable grid Finish are the times when you needed to have a different controls for editable and for read-only grids. With this new control, simply configure the \u0026lsquo;Enable editing\u0026rsquo; parameter of the control at design time and it will be rendered accordingly.\nInfinite scrolling by default One aspect that always bugged me with classic data grids within modern-driven apps is the pagination system.\nEspecially for grids that contains a lot of data, navigating within the grid can quickly become a tedious task. Users find themselves constantly scrolling up and down, and if they can\u0026rsquo;t locate what they need, they\u0026rsquo;re forced to click through previous and next pages.\nThe PowerApps Grid control have infinite scrolling enabled by default, allowing seamless navigation of lengthy records lists without context switching.\nSimply toggle the \u0026rsquo; Enable Pagination\u0026rsquo; setting to \u0026lsquo;Yes\u0026rsquo; to revert to the classic rendering style.\nEnters the Cell Renderers From a developer perspective, the PowerApps Grid control truly shines by allowing the injection of a Customizer control (or cell renderer) on top of the grid. Just enter the name of the desired cell renderer in the \u0026rsquo; Customizer control\u0026rsquo; parameter. ( Format : {publisher prefix}_{namespace}.{control name})\nIt gives a way to customize the look and feel of specific cells in a grid without having to recreate your own data grid custom control from scratch. This approach allows you to piggyback on the out-of-the-box control and add your own customization on top of it, giving you the best of both worlds.\nHead to the official documentation to get you started on cell customizer development process.\n🔗Customize the editable grid control - Power Apps | Microsoft Learn 🔗Customized editable grid - Power Apps | Microsoft Learn\nAlso, don\u0026rsquo;t forget to get a look at these posts from Diana Birkelback\n🔗Power Apps Grid Control – First Glimpse to the Cell Renderer and Editors – Dianamics PCF Lady (wordpress.com) 🔗Fetch Related Records with Power Apps Grid Customizer Control – Dianamics PCF Lady (wordpress.com)\nI will not go in every details of the implementation of a cell customizer but here are the key points.\nIn the init method of the customizer PCF control, an EventName parameter will be received and will serve as a reference to the datagrid ( this is supplied at runtime by the platform, you don\u0026rsquo;t need to do anything). You then need to instantiate a PAOneGridCustomizer that will contain the business logic in the form of a cellRendererOverrides. Bind that customizer to the grid instance ( EventName) by invoking a fireEvent. The cellRendererOverrides implementation will contain code that will fire every time a cell of the grid is rendered. The goal here is to intercept the columns of interest and carry out the desired custom rendering.\nNote that every type of columns can have their own renderers so you need to define different overrides for each column types. Also, you have access to the column name so you can filter out the unwanted columns.\nHowever, as previously mentioned, despite Cell Renderers being constructed using the PCF control framework, a notable limitation is the inability to supply any runtime parameters to a specific instance of the control, as you would with a standard PCF control. This limitation presents challenges in creating generic cell renderers that are reusable across the system.\nLet\u0026rsquo;s explore ways to alleviate some of these challenges using my latest community PCF control.\nThe RecordImage Cell Renderer The story behind the RecordImage Cell renderer is to leverage the use of individual record image ( primary image) and showcase these images within data grids that surface these records.\nEnabling record images is a straightforward process that is often underestimated in model-driven application projects. It can introduce a layer of depth and visual appeal to your application.\nTo enable record image on any table, create an image column and configure the column as the Primary Image of the table.\nInside a data grid, link to records can come in two flavors, either by the primary name column or related data lookups columns contained in the view.\nUnder the hood of the cell customizer, whenever a cell of interest rendering is fired, a mini-React application ( RecordImageCellApp) will be returned to override the out-of-the-box rendering. To ensure accurate rendering of the image, the app relies on two crucial pieces of information passed as props (parameters).\nThe logical name of the table ( entityname) The ID of the individual record ( recordid) Here is how I was able to retrieve them.\nGet Entity Reference for Primary Name column Since the primary name column is of type \u0026rsquo; Text\u0026rsquo;, the first step is to determine if the cell that is being rendered is actually the PrimaryName column of the displayed view and skip the rendering for all other Text type columns. Fortunately the platforms gives us this information in the rendererParams object ( colDefs[columnIndex].isPrimary)\nKnowing that, it\u0026rsquo;s also easy to get the ID of the row\u0026rsquo;s record using the [ RECID] property of the rowData object.\nTo get the table name, it\u0026rsquo;s a bit more tricky. First, we need to determine what is the type of grid that is being rendered. The grid can either be rendered as a main entity view or as a subgrid in a form that shows related records.\nI found a way to get that information by inspecting the factory._customControlProperties.pageType that is buried inside the the context object of the PCF control. Note that the context object needs to be casted as an any because these properties are not exposed in the official type definition of the context.\n(context as any).factory._customControlProperties.pageType As seen below, the pageType value will be \u0026rsquo; EntityList\u0026rsquo; if the datagrid is rendered on a main entity view and \u0026rsquo; EditForm\u0026rsquo; when rendered as a subgrid on a form\nNow depending on the pageType value the name of the table can be infered accordingly.\nconst entityname = pageType == \u0026#39;EntityList\u0026#39; ? (pcfContextService.context as any).page.entityTypeName : (pcfContextService.context as any).factory._customControlProperties.descriptor.Parameters.TargetEntityType Main Entity view Subgrid on a form Get Entity Reference for Lookup columns The second technique I want to show is how to get the entity reference information about lookup columns referenced inside the grids underlying view.\nThe information about a particular lookup value (table name and id of the record) can be found in the rowData object received by the cell renderer rendererParams. The only challenge is that the property name inside the rowData object is dynamic and correspond to the name of the column inside the view.\nUsing the keyof typeof obj technique, we can get the lookup info (entity name and guid) by dynamically accessing the rowData object property that equals to the column name of the lookup. The code below speaks fort itself.\nMore onkeyof typeof obj here : 🔗Dynamically access an Object\u0026rsquo;s Property in TypeScript | bobbyhadz\n[\u0026#34;Lookup\u0026#34;]: (props: CellRendererProps, rendererParams: GetRendererParams) =\u0026gt; { const {columnIndex, colDefs, rowData } = rendererParams; const columnName = colDefs[columnIndex].name; type ObjectKey = keyof typeof rowData; const columnNameProperty = columnName as ObjectKey; const lookup = rowData?.[columnNameProperty] as any if(lookup == null){ return null } const lookupentity = lookup.etn const lookupid = lookup.id.guid The table name can be derived from the lookup.etn and the record id can be found in lookup.id.guid.\nGet the PrimaryImage column name from Metadata Having access to the table name either from the main table or from a a lookup, the next challenge is to get the name of the primary image column of these tables so we can retrieve the individual record images further on.\nTo achieve this, its a matter of making a metadata call on the table name using the getEntityMetadata function exposed by the ComponentFramework.Context object. Within the metadata call\u0026rsquo;s response, we can conveniently extract the value of the PrimaryImageAttribute, which holds the logical name of the primary image column.\nGet the record image Finally, to retrieve the image data, all is needed is to make a webAPI.retrieveRecord call to query the table (entityname) and get the primaryimage attribute of the current cell record (recordid)\nGiven that the content of the primaryimage field is stored in base64 within the Dataverse table, the function shown below will produce a string that is appropriately formatted and suitable for injection into an HTML \u0026lt;img\u0026gt; element\u0026rsquo;s src attribute. This string will be structured as follows: data:image/jpeg;base64,{primaryimage_data}.\nasync getRecordImage (entityname:string, recordid:string, primaryimage:string) : Promise\u0026lt;string\u0026gt; { let record = await this.context.webAPI.retrieveRecord(entityname,recordid,`?$select=${primaryimage}`) return record?.[primaryimage] ? `data:image/jpeg;base64,${record?.[primaryimage]}` : \u0026#39;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=\u0026#39; //1 px transparent https://png-pixel.com/ } In my implementation I have wrapped the result of the function in a custom hook, but you can see the resulting image data being injected in a FluentUI Image object src attribute.\nClickable link To preserve the standard functionality of Primary Name and lookup columns, it\u0026rsquo;s essential to wrap the text of the cell in a clickable link that redirects the user to the record expressed by the cell.\nThis can be achieve by using the ComponentFramework.Context n avigation.openForm function and binding the resulting promise to the OnClick event of a link tag. Here i\u0026rsquo;m using FluentUI Link object.\nasync openRecord (entityname:string, recordid:string):Promise\u0026lt;ComponentFramework.NavigationApi.OpenFormSuccessResponse\u0026gt; { return this.context.navigation.openForm( { entityName: entityname, entityId: recordid } ) } What about performance and caching? As you can imagine, having code that can run on any cell of a data grid needs to execute lightning fast.\nThat\u0026rsquo;s why for my implementation I opt-in for a PCF Virtual control. This flavor of PCF control uses the React and Fluent provided by the PowerApps runtime and are known to be smaller in size and execute faster than regular PCF control.\nSee official docs : 🔗React controls \u0026amp; platform libraries (Preview) - Power Apps | Microsoft Learn\nAdditionally, given that a substantial portion of the metadata and Dataverse WebApi calls might be the same across a grid rendering, it would be a counterproductive to re-query the same data over and over again.\nFor this, I\u0026rsquo;m using the awesome React Query package to graciously handle the asynchronous state management and caching of the app.\nLearning how to effectively use React Query is beyond the scope of this blog post and will probably be the subject of future writings. I highly recommend that Check the source code to get a grasp of its usage.\nTakeaway Exploring Cell Renderers for the PowerApps Grid control has been an enjoyable learning experience. They offer unprecedented ways to enhance the user experience of data grids.\nWhile it might take a bit of practice to master their implementation, the payoff is well worth it, as we have seen with the RecordImage Cell Renderer.\nI hope that the framework will evolve overtime to remove some of the current limitation and I can\u0026rsquo;t wait to see what kind of renderers will emerge from the community.\nHappy coding!\nLinks Power Apps grid control - Power Apps Learn about the Power Apps grid control for model-driven apps. learn.microsoft.com Customize the editable grid control - Power Apps Learn how you can customize the editable grid control. learn.microsoft.com React controls \u0026amp; platform libraries (Preview) - Power Apps You can achieve significant performance gains using React and platform libraries. When you use React and platform libraries, you are using the same infrastructure used by the Power Apps platform. This means you no longer have to package React and Fluent packages individually for each control. learn.microsoft.com Power Apps Grid Control – First Glimpse to the Cell Renderer and Editors We’ve saw the Power Apps grid control (Preview) in the latest Wave Announcements. Each time we hear about great improvements. In Release Wave 1/2022 we’ve got inline-editing and infinit… dianabirkelbach.wordpress.com Fetch Related Records with Power Apps Grid Customizer Control The Power Apps Grid customizer control is a preview feature I really look forward to. In the last two blogs I’ve already shown how to use it for: Host your own read-only or editable PCF insid… dianabirkelbach.wordpress.com Dynamically access an Object’s Property in TypeScript | bobbyhadz A step-by-step guide on how to dynamically access an object’s property in TypeScript. bobbyhadz.com TanStack Query | React Query, Solid Query, Svelte Query, Vue Query Powerful asynchronous state management, server-state utilities and data fetching for TS/JS, React, Solid, Svelte and Vue tanstack.com RecordImage Cell Renderer A control (generic Cell renderer) that works in conjunction with the Power Apps Grid Control. It renders each record’s primary name with its primary image, improving visual clarity and user experience. pcf.gallery GitHub - drivardxrm/RecordImage.CellRenderer: Cell renderer for PowerApps Grid Cell renderer for PowerApps Grid. Contribute to drivardxrm/RecordImage.CellRenderer development by creating an account on GitHub. github.com Photo by Fayette Reynolds M.S.\n","date":"2023-10-02T01:46:28Z","image":"/powerapps-grid-control-how-to-make-cell-renderers-more-generic/pexels-fayette-reynolds-ms-11198495-scaled.jpg","permalink":"/powerapps-grid-control-how-to-make-cell-renderers-more-generic/","title":"PowerApps Grid Control - How to make Cell Renderers more Generic"},{"content":"In a previous blog post, I described how to use the new modelbuilder command group of the Microsoft Power Platform CLI ( PAC CLI) to generate early-bound classes for Dataverse code customization projects.\nThis time we\u0026rsquo;ll take this a step further and explore how to automate the early-bound class creation process by invoking the PAC CLI modelbuilder within an Azure DevOps pipeline.\n🔗Link to previous post here : How to Generate Dataverse Early-Bound Classes with PAC CLI ModelBuilder\nWhen it comes to Dataverse code customizations, like server-side plugins, early-bound classes can play a vital role in the development process. These classes offer a strongly-typed representation of Dataverse entities that empower developers to ensure code reliability, leverage IntelliSense, and enhance overall productivity.\nAlthough I\u0026rsquo;ve previously demonstrated how to generate early-bound classes using PAC CLI modelbuilder command locally, there are several advantages to delegate this task to an Azure DevOps cloud-based build agent, such as :\nConsistency: Especially when several developers are working on the same project, producing the early-bound classes through an automated pipeline ensures that the process is always carried out in the same manner using a build agent regardless of the developer machine configuration. Security: In some scenarios, the developers might not have all the security clearance using their own credentials to access the needed metadata. By using Service Connections to Dataverse environments defined in Azure DevOps, only approved connections can be used and their usage can be monitored by internal IT departments to ensure compliance. Reusability: Once you have created an Azure DevOps pipeline to generate early-bound classes, you can reuse it for all your projects. This helps to maintain coherence in processes across multiple projects. Model generation from Azure DevOps Here is a high-level overview of the process that will be implemented:\nThe developer edits the builderSettings.json file on his computer and checks in the file to the Azure DevOps code repository. As seen in my previous post, this file acts as the blueprint of the process and contains the list of entities, messages and other parameters supplied to the modelbuilder. A pipeline is launched that connects to the source Dataverse environment and executes the PAC CLI modelbuilder command using the settings file as an input. The generated early-bound classes are commited to the repository The developer pulls the latest changes locally and uses the newly generated early-bound classes in the code project. Pre-Requisite To ensure the pipeline works correctly, the following requirements should be considered:\nService connection In order to establish a connection between the pipeline and a Dataverse environment, we need to create a Service connection within our Azure DevOps project.\nThe initial step involves setting up a (non-interactive) application user and assigning the necessary security role in the Dataverse environment. Follow the instructions outlined in the blog post below for a detailed walkthrough of the process.\nSetting up an Application User in Dynamics 365 | Magnetism Solutions | NZ (Auckland, Wellington, Christchurch and Dunedin)\nOnce the application user is correctly configured, head to your Azure DevOps project and go to Project Settings -\u0026gt; Service Connections -\u0026gt; Add New and choose Power Platform\nConfigure the service connection with the URL of the Dataverse environment and the credentials ( TenantId, ApplicationId and Client Secret) of the application user and give it a name.\nInstall Power Platform Build Tools The Power Platform Build Tools extension needs to be installed in the Azure DevOps environment. This extension contains the official Microsoft set of tasks for Power Platform ALM. It will be used to install the PAC CLI on the build agent. Power Platform Build Tools (2.0.18) - Visual Studio Marketplace Extension for Azure DevOps - Automate common build and deployment tasks related to Power Platform marketplace.visualstudio.com Learn more about this great extension here : Microsoft Power Platform Build Tools for Azure DevOps - Power Platform | Microsoft Learn\nSetup the code repository A code repository needs to be initiated in the Azure DevOps project.\nSince the main purpose of the pipeline is to generate early-bound classes files and check them back in the code repository, it\u0026rsquo;s necessary to give the build agent the contribute role on the repository. Otherwise permission errors will occur.\nIn order to give the appropriate rights, head to the Projects Settings of the Azure DevOps project and go to the Repositories section and select the Security tab. Under the User s section, choose the Build Service user and set the Contribute role to Allow.\nSetup the Azure Pipeline The pipeline itself is a declarative configuration file in YAML format that outlines the steps and tasks required to execute the process. In this example, I will maintain the pipeline file within the code repository of the project.\nWith this in place its easy to setup a pipeline using the Existing Azure Pipelines YAML file option\nWe end up with a pipeline that can be executed on demand.\nAzure Pipelines is a vast and complex subject, it is highly recommended to refer to the official documentation to gain a deeper understanding of its intricacies : Azure Pipelines documentation - Azure DevOps | Microsoft Learn\nI will cover every step of the pipeline in detail, but the final result looks like this. Feel free to grab this example as a starter and adapt it to your specific use-case.\n1- Parameters parameters: - name: serviceConnectionName type: string default: \u0026#39;{YOUR-SERVICECONNECTION-NAME}\u0026#39; - name: serviceConnectionUrl type: string default: \u0026#39;https://{YOURENV}.crm.dynamics.com/\u0026#39; - name: outdirectory type: string default: \u0026#39;{PATH-TO-OUTPUT-DIR}\u0026#39; - name: settingsTemplateFilePath type: string default: \u0026#39;{SETTINGS-PATH}/builderSettings.json\u0026#39; trigger: none pool: vmImage: windows-latest The pipeline expects 4 input parameters. I usually put some default values but these can be supplied at runtime if need be.\nserviceConnectionName : This is the name of the Service Connection to Dataverse that we set earlier serviceConnectionUrl : This is the main URL of the source Dataverse environment outdirectory : This is the path inside the code repository where the earlybound classes files will be created and commited settingsTemplateFilePath : This is the path to the json file that contains the modelbuilder parameters 2- Checkout - checkout: self fetchDepth: 1 persistCredentials: True displayName: \u0026#39;Checkout\u0026#39; This section of code checks out the code repository.\ncheckout: self This specifies that the pipeline should checkout the source code from the same repository that the pipeline is defined in. fetchDepth: 1 This tells the pipeline to fetch only the latest changeset from the repository. persistCredentials: True This ensures that the credentials used to trigger the pipeline are persisted and used for subsequent steps. 3- Install PowerPlatform Tools # Installs PowerPlatform Tools (including PAC CLI) - task: PowerPlatformToolInstaller@2 displayName: \u0026#39;Install Power Platform Build Tools\u0026#39; This task uses Power Platform Tool Installer task from the PowerPlatform Build Tools. It installs the PAC CLI on the build agent so it can be invoked in subsequent tasks.\nWhen the pipeline is run in debug mode (verbose) you\u0026rsquo;ll notice that the task sets a variable called POWERPLATFORMTOOLS_PACCLIPATH. This variable points to the folder in the build agent where the PowerPlatform Tools (including the PAC CLI) are downloaded. We\u0026rsquo;ll leverage this variable in subsequent steps to set the path to the PAC CLI executable.\nMore on all available PowerPlatform Build Tools tasks here\n👉 Build tool tasks - Power Platform | Microsoft Learn\n4- Set the path to the PAC CLI # Set PACEXEPATH variable : the path to the PAC CLI executable - pwsh: | $pacExePath = $env:POWERPLATFORMTOOLS_PACCLIPATH + \u0026#34;\\pac\\tools\\pac.exe\u0026#34; echo \u0026#34;##vso[task.setvariable variable=PACEXEPATH]$pacExePath\u0026#34; displayName: \u0026#39;Set Pac.Exe path\u0026#39; This step consist of an inline PowerShell script that sets the variable PACEXEPATH that contains the path to the PAC CLI executable.\n💡 Do you kow about the COE ALM Accelerator templates ?\nThis Github repository maintained by Microsoft is a real treasure trove that contains numerous pipeline scripts covering many different aspects of PowerPlatform ALM.\nThis is where I found out about the technique to get the PAC.EXE location.\nhttps://github.com/microsoft/coe-alm-accelerator-templates/blob/f37fb218f29ca1c96ad84f2e215bb30cd0b58d84/PowerShell/build-deploy-solution-functions.ps1#L19\nI highly recommend that you have a look at the repo (and why not give a star ⭐)\n5- Set Connection variables # Sets the Connection variables from the Service Connection passed in input parameter # Will set BuildTools.ApplicationId, BuildTools.ClientSecret, BuildTools.TenantId - task: PowerPlatformSetConnectionVariables@2 displayName: \u0026#39;Set Connection Variables - ${{parameters.serviceConnectionName}}\u0026#39; name: ConnectionVariables inputs: authenticationType: PowerPlatformSPN PowerPlatformSPN: \u0026#39;${{parameters.serviceConnectionName}}\u0026#39; This is a very handy task from the Power Platform Build Tools. It takes the name of the service connection to Dataverse (created earlier) and extracts important connection values (AppId, ClientSecret, TenantId) in secret variables accessible to other tasks of the pipeline.\n6- Connect to Source Dataverse environment # PAC Auth - Connects to the Power Platform environment - pwsh: | $pacCommand = \u0026#34;auth create --url ${{parameters.serviceConnectionUrl}} --applicationId $(ConnectionVariables.BuildTools.ApplicationId) --clientSecret $(ConnectionVariables.BuildTools.ClientSecret) --tenant $(ConnectionVariables.BuildTools.TenantId)\u0026#34; Write-Host \u0026#34;Pac command - $(PACEXEPATH) $pacCommand\u0026#34; Invoke-Expression -Command \u0026#34;$(PACEXEPATH) $pacCommand\u0026#34; displayName: \u0026#39;PAC Auth\u0026#39; In this inline Powershell script, we make a first call to the PAC CLI to establish a connection to the source Dataverse environment from which we want to create the early bound classes. A pac auth command is built using the connection variables and run using the Pac.exe.\nLink to pac auth command documentation\n7- Execute PAC Modelbuilder # PAC Model Builder - Delete content of outputfolder and Execute mopdelbuilder statement - pwsh: | Get-ChildItem -Path ${{parameters.outdirectory}} -Include *.* -File -Recurse | foreach { $_.Delete()} write-host \u0026#34;Content of ${{parameters.outdirectory}} Deleted..\u0026#34; -BackgroundColor Green -ForegroundColor Black $pacCommand = \u0026#34;modelbuilder build --outdirectory ${{parameters.outdirectory}} --settingsTemplateFile ${{parameters.settingsTemplateFilePath}}\u0026#34; Write-Host \u0026#34;Pac command - $(PACEXEPATH) $pacCommand\u0026#34; Invoke-Expression -Command \u0026#34;$(PACEXEPATH) $pacCommand\u0026#34; displayName: \u0026#39;PAC Modelbuilder\u0026#39; And for the main event of the pipeline, we start by clearing the content of the outdirectory. After that, a pac modelbuilder command is invoked using the builderSettings.json as template and the generated files are created in the outdirectory folder.\n8- Commit to repository # Commit changes - script: | echo on git config --global user.email \u0026#34;$(Build.RequestedForEmail)\u0026#34; git config --global user.name \u0026#34;$(Build.RequestedFor)\u0026#34; git fetch set branch=$(Build.SourceBranch) set branch=%branch:refs/heads/=% echo source branch is %branch% git checkout %branch% git status git add --all git status git commit --no-edit --message \u0026#34;Early-bound classes generation v$(Build.BuildNumber)\u0026#34; git -c http.extraheader=\u0026#34;AUTHORIZATION: bearer $(System.AccessToken)\u0026#34; push origin $(Build.SourceBranch) displayName: \u0026#39;Commit Changes\u0026#39; The final step contains a script used to commit the changes made by the pipeline job back to the source code repository.\nAnd that is all there is! Simply pull the latest change from the repo on your local development machine and start building great solutions.\nRinse and repeat the process anytime you need to add new tables or when there are metadata changes on the source environment to keep the classes clean.\nTakeaway With this pipeline in place, we now have a steady and reliable work horse that generates the projects early-bound classes on demand using a cloud-based build agent. This ensures that anyone working on the project can easily initiate the models creation process in a consistent and repeatable manner.\nI recently started to implement this approach in my professional and personal projects and I really like it so far.\nFurthermore, while the pipeline shown leverages the PAC CLI modelbuilder command, the same method can be used to execute any other PAC CLI command from Azure DevOps pipelines.\nHappy coding!\nPhoto by 夜 咔罗 on Unsplash\n","date":"2023-06-04T19:44:35Z","image":"/calling-pac-cli-modelbuilder-from-an-azure-devops-pipeline/karosu-RIQdGGU2US0-unsplash.jpg","permalink":"/calling-pac-cli-modelbuilder-from-an-azure-devops-pipeline/","title":"Calling PAC CLI ModelBuilder from an Azure DevOps Pipeline"},{"content":"As a Power Platform developer, I have always been a strong advocate for the use of early-bound classes in customization projects that targets Dataverse tables and actions. Early-bound classes not only increase code readability and maintainability, they also significantly reduce the risk of errors. I think that being proficient and fast in generating early-bound classes is a must-have skill for any developers who works with the platform.\nRecently, the Microsoft Power Platform CLI ( PAC CLI) introduced the new modelbuilder command group that enables early bound classes generation directly from the CLI. Traditionally the generation of early-bound classes was primarily accomplished through a specialized tool called CrmSvcUtil. Yet, integrating these capabilities into a more versatile and widespread tool like PAC CLI is a logical step forward that will undoubtedly improve user adoption in the long run.\nThis post takes a closer look at the PAC CLI modelbuilder, delving into its inner workings and examining some of the key command group switches and their impact on the resulting classes. Additionally, we\u0026rsquo;ll explore how to effectively generate these classes on the fly within a Dataverse plugin project.\nBut first, let\u0026rsquo;s recap on the early-bound classes concept.\nEarly bound classes In Dataverse, early-bound classes are used to provide a strongly-typed representation of the Dataverse tables (entities), columns (attributes) and choices (optionsets) in .NET languages, such as C# and VB.NET.\nTypically, a code generation tool establishes a connection to the target Dataverse organization and inspects the metadata to create a collection of classes that represents each entity and its attributes as a corresponding property within that class.\nBy using early-bound classes, developers can write code that references Dataverse entities and their attributes using strongly-typed objects, rather than using string literals ( a.k.a. magic strings). This makes the code more readable, maintainable, and less error-prone.\nFurthermore, early-bound classes provide compile-time type checking, which helps to detect errors early in the development process, rather than catching them at runtime. They also provide intellisense, making it easier for developers to discover and use available entities and attributes.\nAs an example, the following screenshots compares early-bound vs late-bound coding style. You can appreciate the difference in style and readibility. I personally find the late-bound notation hard to understand.\nPAC CLI modelbuilder That being said, let\u0026rsquo;s explore the new modelbuilder command group of the PAC CLI to produce these early-bound classes.\nPre-requisites There are some prerequisite to use the PAC CLI, the first one is to have it installed on your computer. You can find the official docs here, but the easiest way is to install it through the Power Platform Tools Visual Studio Code extension. This will install the CLI globally on your machine and you\u0026rsquo;ll be able to use it from any command prompts.\nNow, before generating the classes, it is necessary to connect to an actual Dataverse environment. There are several methods to create connections using the CLI but for the simplicity of the post, we will use this type of command :\npac auth create \u0026ndash;url https://{yourenv}.crm.dynamics.com \u0026ndash;name {yourenv-friendly-name}\nIssuing this command will pop-up an account sign-in screen where you can enter your credentials and connect to the desired environment\nOnce authenticated, the connection will be created and selected as the active connection.\nFor more in-depth information on creating and managing Dataverse connections with the CLI, check out this helpful blog post.\nPower Platform CLI: Installing, Connecting, and Selecting an Organization – Nicolas Nowinski (nicknow.net)\nSimple modelbuilder command Now that we are connected to a Dataverse environment, we can issue modelbuilder commands to generate early-bound classes. Please refer to the official documentation of the PAC CLI below for the most up to date information.\nMicrosoft Power Platform CLI modelbuilder command group - Power Platform | Microsoft Learn\nIn its simplest form you can issue a command like this one.\npac modelbuilder build \u0026ndash;outdirectory Models \u0026ndash;serviceContextName XrmContext \u0026ndash;namespace ModelBuilderTest\nHere\u0026rsquo;s a brief explanation of the parameters and switches.\n--outdirectory This is the directory where the early-bound classes will be created. the directory can be a full path (ex. C://MyOutputPath) or a relative path to the folder where the command is executed.\n--serviceContextName This is the desired name of the generated ServiceContext class. It creates a class in the output directory that extends the OrganizationServiceContext from the SDK and provides Queryable collections for every tables (entities) present in the model, thus enabling the usage of LINQ queries over the Dataverse table data. I personnaly use the name \u0026lsquo;XrmContext\u0026rsquo;.\nWith a servicecontext instantiated you can now produce powerful and easy to understand queries on the business model.\nMore on OrganizationserviceContext here OrganizationServiceContext Class (Microsoft.Xrm.Sdk.Client) | Microsoft Learn\n--namespace This is the desired namespace that the code generation tool use for every generated files\nRunning the command will generate a bunch of files in the folder specified in the \u0026ndash;outdirectory parameter. The Entities folder will contain one file for each tables detected and the OptionSets folder will contain enums representing the global choices (optionsets)\nThe main problem with this pac modelbuilder statement is that it generates huge amount of files (1 file for every tables in the environment) weighing around 25 MB and it took about 2 minutes to completes. In a real life project you should only generate the early-bound classes for the tables that are needed in the business logic of your project.\nLet\u0026rsquo;s see how to optimize the ouput files using other available switches.\nOptimized modelbuilder command There are numerous other switches and parameters available in the modelbuilder command group that will have an effect on the gerated code and files produced, here are the most notable.\n--entitynamesfilter When working with early-bound classes in a customization project, chances are that you\u0026rsquo;ll only need to target a small subset of tables to perform your business logic. The entitynamesfilter parameter in allows the user to provide a semicolon-separated list of table names to filter the exported table classes accordingly.\nFor example, if you only want to use Accounts and Contacts use the following :\n\u0026ndash;entitynamesfilter \u0026ldquo;account;contact\u0026rdquo;\n--generateActions When included, this switch will include early-bound classes for Actions and CustomApis. Actions classes exposes robust and easy to use wrappers around actions/customapi request and response calls.\nSee how easy it is to consume a custom api with early-bound classes with the example shown below. I\u0026rsquo;m using the GetEnvironmentVariable that is part of my generic Custom API collection project.\n--messagenamesfilter This is used to filter the generated messages/actions classes. Same idea as the entitynamesfilter, you can provide a list of Actions/CustomAPI separated with a semicolon\n🐛There is currently slight bug with this feature, to correctly filter the desired actions you need to add a wildcard \u0026lsquo;*\u0026rsquo; at the end of each actions/customapi present in the filter list. I have opened an issue on the CLI github repo and hopefully it will be resolved soon.\npac modelbuilder - generateActions and messagenamesfilter inconsistencies · Issue #495 · microsoft/powerplatform-vscode (github.com)\n--emitfieldsclasses Adding this switch to your model generation command will generate constants out of the fields name of each table in your model.\nAs seen below in the generated account.cs file, this will add a static class called Fields inside the Account class that lists all the fields of the account table as string constants.\nThose constants are then easilly acessible troughout the codebase. This feature is particularly useful in reducing the use of magic strings when you need to fall back to late-bound style for any reason. As demonstrated in the example below.\nAs far as I know, this is a unique feature of the PAC CLI modelbuilder and is not possible when using the (older) crmsvcutil tool. Thus, I highly recommend incorporating this switch for model generation.\n--generateGlobalOptionSets If you include this switch, this will emit classes for all the global optionsets(choices) present in the environment. If you omit the switch, only the global optionset used in the entities produces by the model will be generated. So as a rule of thumb I don\u0026rsquo;t use it.\n--suppressGeneratedCodeAttribute This switch will remove a bit of noise in the output files by removing unecesary and redundant lines of code. If you are a neat freak, you\u0026rsquo;ll definitely want to use it.\n--suppressINotifyPattern By default all properties will expose a INotify pattern that can be used in your code. Issuing that switch will remove the pattern implementation and delete 2 lines of code per properties. I personally never used this pattern in my projects so I\u0026rsquo;m using the switch.\n--writesettingsTemplateFile Using this switch will produce a builderSettings.json file in the output directory.\nThe builderSettings.json file will contain a representation of all the parameters and switches used in the issued pac modelbuilder command. As we will see in the next section, this file can be put in source control and reused on demand.\nMy final optimized statement will look something like this\npac modelbuilder build --outdirectory Models --serviceContextName XrmContext --namespace ModelBuilderTest --emitfieldsclasses --entitynamesfilter \u0026#34;account;contact\u0026#34; --generateActions --messagenamesfilter \u0026#34;driv_GetEnvironmentVariable*\u0026#34; --suppressGeneratedCodeAttribute --suppressINotifyPattern --writesettingsTemplateFile Having limited the number of tables and actions only to what\u0026rsquo;s needed, the whole operation is completed in a couple of seconds and the Models folder weighs around 300 kb, that is much better.\nAll this is great, but not very practical in a real-life project. I want to be able to regenerate the classes on-demand as my project grows in complexity and I don\u0026rsquo;t want to have to remember this big command. Most of all I want to store the configuration in source control where it can be reused by other team members.\nLet\u0026rsquo;s push this a bit further and simplify our lives with the use of a template file.\nGenerate classes from a template file As seen in the previous example, the --writesettingsTemplateFile switch will produce a builderSettings.json that can be used as template to feed into the PAC CLI. In fact, once you have a template file, you dont even need to issue commands that contains all these switches and parameter. You can grab this one as an example to build upon.\nInstead we will use the settingsTemplateFile parameter to supply the settings to the command.\n--settingsTemplateFile This parameter expects the name of the file that contains the parameters and switches. If the file is not located in the directory from where you are issuing the command, put the full path.\nWith this, the command to issue is way more simple, as you only need to provide the output directory and the template file. This file can be stored in source control and can evolve throughout the project\u0026rsquo;s lifecycle.\npac modelbuilder build --outdirectory Models --settingsTemplateFile builderSettings.json With all the necessary components in place, we can now easily generate the early-bound classes on demand as your model and business logic evolves.\nAn example is shown below, with a Dataverse plugin project containing a builderSettings.json file and an earlybound.bat file that runs the PAC CLI command at the project root. Simply executing the .bat file allows for quick and efficient generation of the classes.\nLimitations Here are some limitations I came upon during my experimentation.\nModels folder not cleared The model folder is not cleared between each modelbuilder invocation. Meaning that if you remove a table from your desired early-bound classes, the file that was created from an earlier call would not be deleted. This could potentialy cause noise and unwanted behavior.\nThere\u0026rsquo;s an issue on the PAC CLI repo regarding this : [Feature request] Add clobber option to pac modulebuilder build · Issue #365 · microsoft/powerplatform-vscode (github.com)\nTherefore I advise to find a way to clear the folder before generating the classes.\nLots of files to include in the .csproj I really like that the generated model files are well separated in folders and having one file per artifact (tables, choices, messages) as it\u0026rsquo;s easy to understand and visualize the outputs. But one of the drawback is when used in a C# class library project, everytime a new file appears in the models folder, it must be manually included in the project.\nYou can mitigate this by modifying the .csproj file so that any new files (or deleted filed) that appears in the models folder gets picked and included in the project automatically. By including the following lines :\n\u0026lt;Compile Include=\u0026#34;Models\\*.cs\u0026#34; /\u0026gt; \u0026lt;Compile Include=\u0026#34;Models\\Entities\\*.cs\u0026#34; /\u0026gt; \u0026lt;Compile Include=\u0026#34;Models\\OptionSets\\*.cs\u0026#34; /\u0026gt; \u0026lt;Compile Include=\u0026#34;Models\\Messages\\*.cs\u0026#34; /\u0026gt; I had some issues with this technique as sometimes, I had to shut down and restart the project to get the files included or the include statements gets re-written for no reason.\nFor that reason I would like to have the possibility to emit the generated models in 1 single file that would be included in the project. I know its a bit of an anti-pattern but this was possible with the CrmSvcUtil tool.\nEarly Bound Generator V2 All the examples shown up to here were done using the PAC CLI directly, but you might want to have a look at the Early Bound Generator V2 for XrmToolBox by Daryl Labar. The tool leverages the PAC CLI modelbuilder and adds a lot of extra features including mitigation for the limitations listed above.\nEarly Bound Generator · XrmToolBoxEarly Bound Generator · XrmToolBoxEarly Bound Generator · XrmToolBox\nEarly Bound Generator V2 (linnzawwin.blogspot.com)\nTakeaway That\u0026rsquo;s it for now, It was a lot to cover.\nI hope this post has shed light on the benefits of using the PAC CLI to generate early-bound classes for your Dataverse projects.\nPhoto by Pierre Bamin on Unsplash\n","date":"2023-04-12T03:37:47Z","image":"/how-to-generate-dataverse-early-bound-classes-with-pac-cli-modelbuilder/pierre-bamin-18T72jBinvI-unsplash.jpg","permalink":"/how-to-generate-dataverse-early-bound-classes-with-pac-cli-modelbuilder/","title":"How to Generate Dataverse Early-Bound Classes with PAC CLI ModelBuilder"},{"content":"Whenever a new version of C# is released I\u0026rsquo;m always eager to explore the new features of the language. However, as a Power Platform developer, it can be frustrating knowing that they can\u0026rsquo;t be used to develop Dataverse plugins, which constitutes a significant part of my daily work.\nAs a matter of fact, due to a dependency on the Microsoft CRM SDK, Dataverse plugins are confined to use an older version of the .NET framework (4.6.2) which natively supports C#7.3, while the latest version is C# 11.\nWell, those days are over! In this post we\u0026rsquo;ll see how to take Dataverse plugin development to the next level and unlock the latest C# features with the help of the nifty PolySharp library created by Sergio Pedri from Microsoft.\nPolySharp to the rescue The motivation behind PolySharp is to adress this very issue. It allows developers to enable the latest version of C# compiler while targeting older versions of the .NET framework which would normally be incompatible.\nIt does it\u0026rsquo;s magic by filling the gaps that makes the compiler complain when using modern syntax. Using source generators, PolySharp detects the missing types required for the features that are not implemented in the (older) target framework and inject the appropriate polyfills.\nFun fact, the library is already being used internally at Microsoft with positive impact, which gives me confidence on its future.\nConfigure your project to use PolySharp Let\u0026rsquo;s start from the ground up and see how easy it is to configure a Dataverse Plugin project that target C#11 and leverages PolySharp.\nTo follow along, you can find the sample project I used for the blog post in this github repo.\n(Pre-requisite) Enable PackageReference mode To be compatible with PolySharp it\u0026rsquo;s mandatory to set the Package Management mode of the project to PackageReference. Ensure that your Visual Studio settings is correctly set here.\nTools-\u0026gt; NuGet Package Manager -\u0026gt; Package Manager Settings\nIf you start from a project is already in packages.config mode, you can easily migrate. See the official documentation here\n1- Create a Dataverse plugin project To begin we need to a class library project that targets the .NET Framework 4.6.2. Easiest way is to fire up Visual Studio and and create a new project using the Class Library (.NET Framework) template.\n2- Install Dependencies Now, install the required nuget packages, at the minimum install these 2 packages.\nMicrosoft.CrmSdk.CoreAssemblies PolySharp At this point, the PolySharp source generator should be visible in the Analyzers node of the projects References section. We are almost there \u0026hellip;\n3- Bump the Language version in the csproj file Now, to ensure that the project is compiled using the latest version of C#, navigate to the project\u0026rsquo;s csproj file and insert the following line of code within the first PropertyGroup node.\n\u0026lt;LangVersion\u0026gt;11.0\u0026lt;/LangVersion\u0026gt; That\u0026rsquo;s all there is in terms of configuration. From now on, since the project compiles C#11, the latest C# syntax can be used and Intellisense will pick up as well. Thanks to the PolySharp source generator the gaps left by the older framework will be patched with the appropriate polyfills\u0026hellip; it\u0026rsquo;s a pure gem 💎.\nDataverse Plugin Using C#11 To illustrate this in the context of a Dataverse plugin (link to the repo), I will implement a Dataverse Custom API to play RockPaperScissor (✊🖐️✌️) using some of the latest C# features. don\u0026rsquo;t take this too seriously there\u0026rsquo;s better ways to code this , I just want to showcase the new syntax.\nThe Custom API takes the name of the player and the hand (rock, paper or scissor) as input and send back the result of a game against the computer. The Custom API will execute the plugin Dataverse.Polysharp.Plugin.RockPaperScissor from the project (see code below)\nScreenshot taken from my Custom API Manager tool for XrmToolbox. Shameless plug 🔌\nBy looking at the plugin code, you can spot at least 5 usages of modern C# syntax that are natively unavailable to .NET Framework 4.6.2, yet everything compiles flawlessly.\nGlobal usings : it really helps to de-clutter the top of each files File-scoped namespace : reduces the nesting of the file and give back some real estate Record: usage of the new record struct with init-only properties Raw string litterals : makes it easier to deal with multiline strings that contains brackets and quotes. Very useful to write json strings Pattern matching and modern switch statement Once the assembly is compiled and deployed to the Dataverse environment, the RockPaperScissor custom API can be invoked and the business logic is executed.\nTo test the API, I\u0026rsquo;m using the Custom API Tester XrmToolbox tool from Jonas Rapp\nHow cool is that! We just executed a C#11-enabled Dataverse Plugin🤯\nTakeAway For me, this is a real game changer and I can\u0026rsquo;t wait to step out of the dark ages and test PolySharp on my real Dataverse plugin codebases. I see a lot of potential not only for plugins but also for XrmToolbox tool authoring.\nDont forget to star⭐ the PolySharp project on Github if you like it!\nI also recommend this video by Nick Chapsas that test drives the library. watch?v=RgKa-tjnUMA www.youtube.com Links GitHub - Sergio0694/PolySharp: PolySharp provides generated, source-only polyfills for C# language features, to easily use all runtime-agnostic features downlevel. Add a reference, set your C# version to latest and have fun! 🚀 PolySharp provides generated, source-only polyfills for C# language features, to easily use all runtime-agnostic features downlevel. Add a reference, set your C# version to latest and have fun! 🚀 -... github.com GitHub - drivardxrm/Dataverse.Polysharp.Plugin: Testing the Poly# library with on a Dataverse plugin project Testing the Poly# library with on a Dataverse plugin project - GitHub - drivardxrm/Dataverse.Polysharp.Plugin: Testing the Poly# library with on a Dataverse plugin project github.com Migrating from packages.config to PackageReference formats Details on how to migrate a project from the packages.config management format to PackageReference as supported by NuGet 4.0\u0026#43; and VS2017 and .NET Core 2.0 learn.microsoft.com Custom API Manager for XrmToolBox Like most Power Platform developers, I am a heavy user of the XrmToolBox. This is the story of creating a tool to contribute to the community. itmustbecode.com Custom API Tester · XrmToolBox Browse Custom APIs, enter input parameters, execute the action, investigate output parameters. www.xrmtoolbox.com Image by PDPics from Pixabay\n","date":"2023-01-20T03:30:30Z","image":"/dataverse-plugins-unlock-the-latest-c-features-with-polysharp/padlock-g12d30703f_640.jpg","permalink":"/dataverse-plugins-unlock-the-latest-c-features-with-polysharp/","title":"Dataverse Plugins : Unlock the latest C# features with PolySharp"},{"content":"I was working on a new PCF control project and I encountered an unexpected error when attempting to build the project, even though no custom code had been added yet. (Cannot find module ajv/dist/compile/codegen)\nFor reference, I\u0026rsquo;m using the latest version ( at the time of writing) of the Microsoft Power Platform CLI ( 1.21.4+g4869036) and here are the steps to reproduce :\nExecute the init method of the pac cli. This will scaffold a new PCF control projects with all the basic dependencies. Execute npm install to download the dependencies Try to build the project : npm run build ❌Fails with error : Cannot find module \u0026ldquo;ajv/dist/compile/codegen\u0026rdquo; pac pcf init -ns \u0026lt;Namespace\u0026gt; -n \u0026lt;ProjectName\u0026gt; -t field npm install npm run build The error message is quite straitforward and points toward a node module that cannot be found : ajv/dist/compile/codegen . Upon checking the node_modules directory, even if the ajv module seems present, the compile/codegen part is nowhere to be found.\nI came across a similar issue ( yet unrelated to PCF control development) on Stack Overflow. Based on the accepted answer, I just added a reference to the ajv package in the dev dependencies of the PCF project.\nnpm install --save-dev ajv As you can see the missing module can now be found in the node_modules directory.\nAnd the project compiles flawlessly.\nHopefully this issue will be resolved quickly in future updates to the Microsoft Power Platform CLI. In the meantime, it is good to know that there is a workaround for it.\nHope this helps.\n","date":"2023-01-03T18:09:56Z","image":"/pcf-control-compile-error-cannot-find-module-ajv-dist-compile-codegen/error3.png","permalink":"/pcf-control-compile-error-cannot-find-module-ajv-dist-compile-codegen/","title":"PCF Control compile error : Cannot find module 'ajv/dist/compile/codegen'"},{"content":"Dataverse Custom APIs are a powerful extension model of the PowerPlatform. However, at the time of writing, there are no direct method to execute a Custom API inside the PowerApps Canvas App model.\nIn this post I will show how to call any Custom API from a Canvas App with the use of a generic Power Automate Flow and the new ParseJSON functionality.\nUPDATE 17-FEB-2023\nDataverse Custom APIs can now be called directly from PowerFx in Canvas Apps and Custom Pages. ( still in experimental phase)\nCall Dataverse actions directly in Power Fx | Microsoft Power Apps\nCustom APIs in context First off, I have to admit that I am die-hard fan of Dataverse Custom APIs since their introduction. The main reason is that it gives developers a way to use the same endpoint that the platform uses for the core functionalities (CRUD on the data tables etc..) and extend it with tailor-made messages that encapsulates server-side business logic over REST API requests.\nAs a result, the Custom APIs are agnostic to the caller and the same logic can be consumed from different sources like Dataverse plugins, Power Automate flows, model driven forms javascript, PCF controls, external programs etc\u0026hellip;\nSadly, one of the blind spot is the direct use of Custom APIs within a Canvas Apps (or from the new Custom Pages) model. Let\u0026rsquo;s see how we can overcome this limitation in an indirect manner.\nLearn more about Dataverse Custom APIs here: 👉Create and use Custom APIs (Microsoft Dataverse) - Power Apps | Microsoft Learn\nDon\u0026rsquo;t forget to use my Custom API Manager tool for XrmToolBox for great authoring experience : 👉Dataverse Custom API Manager · XrmToolBox\nPrerequisites Follow these steps to setup the stage.\nEnable ParseJson The technique that I will show uses the Canvas Apps ParseJSON function that is still in preview, so the activation of the feature in the settings of the canvas app (or custom page) is required.\nsee the official documentation on the feature here 👉ParseJSON function in Power Apps (experimental) - Power Platform | Microsoft Learn\nInstall the PowerApps.Action.Runner solution (optional) You can follow along and create your own Power Automate flows. But I have created a solution that contains the 2 Power Automate Flows shown later on.\nPowerApps:BoundActionRunner PowerApps:UnboundActionRunner Here\u0026rsquo;s the link to the github repo for download : 👉drivardxrm/PowerApps.Action.Runner: Generic Power Automate Flows to run Dataverse Custom APIs an Actions in Canvas Apps (github.com)\nSurface the Flows in the Canvas Apps Once the Power Automate Flows are installed, they need to be added to the Canvas App being edited by enabling them in the PowerAutomate pane of the Canvas App editor.\nMore on using PowerAutomate flows in a Canvas Apps 👉Use Power Automate pane - Power Apps | Microsoft Learn\nHave some Custom APIs at hand You can use any Custom API from your environment, but for the purpose of the demo, I will showcase 2 Custom APIs that can be found in my generic Dataverse Custom API collection.\nHere\u0026rsquo;s the link to the github repo for download : 👉drivardxrm/Dataverse-CustomApis: Collection of Dataverse Custom Apis (github.com)\nFor the Unbound Custom API example, I will use driv_GetTableInfo. This API takes for input a Dataverse table name (LogicalName) and return a collection of valuable information (metadata) on the table.\nFor the Bound Custom API example, I will show a Custom API bound to the systemuser table driv_GetUserTimezone. This API retrieves the Timezone of a given user from the user personal settings. It can be useful for datetime calculations.\nCalling an unbound Custom API Let\u0026rsquo;s start by presenting a Power Automate flow that can be used to call any unbound Custom APIs, PowerApps:UnboundActionRunner.\nIn fact the flow is quite simple and is merely a wrapper around the Custom API call. It consists of 3 parts, the trigger, the action and the response.\nThe Trigger The flow is of type Instant/PowerApps and this type of trigger is what enables the PowerAutomate flow to be surfaced in the Canvas Apps editor as we seen before.\nThe configuration of the trigger defines 2 input parameters that will be supplied by the calling Canvas App\nActionName : this expects the unique name of the Custom API InputJson : this expects a string in JSON format that contains the request parameters (inputs) one wishes to pass to the Custom API. The Action The action uses the Perform an unbound action that is part of the Power Automate Dataverse connector.\nThe Action Name selector exposes a list of all existing Custom API (and legacy Custom Actions) available in the environment, but in our case we\u0026rsquo;ll just select Enter custom value and affect the ActionName value defined earlier in the trigger.\nNow, since the ActionName is dynamic and will only be resolved at runtime, the Power Automate engine cannot determine the individual input parameters so it shows an input field called Action Parameters that expects a JSON construct representing the input parameters of the API.\nFor example to call the GetTableInfo API on the account Table, the Action Parameters would look something like this\n{ \u0026#39;LogicalName\u0026#39; : \u0026#39;account\u0026#39; } The idea here is to set the Action parameters field with the InputJson received from the trigger. However, it\u0026rsquo;s really important here to convert the InputJson text value using the json() function otherwise an error will be thrown at runtime.\nThe Response To pass the Custom API results back to the calling Canvas Apps, the flow makes use of the Respond to PowerAppp or flow action. Here, Simply set the value of OutputJson property to the response of the Custom API call made earlier.\noutputs(\u0026#39;Perform_an_unbound_action\u0026#39;)?[\u0026#39;body\u0026#39;] Calling the flow from a Canvas App Now to the main event, let\u0026rsquo;s connect the dots and use the Flow inside a Canvas App (or Custom Page) to execute a Custom API.\nThe app shown takes a table name as input and at the click of the button, the PowerApps:UnboundActionRunner is used to execute the GetTableInfo Custom Api and output some metadata information on the form.\nThe OnSelect action of the button is used to set the value of the variable TableInfoResults. The value is the OutputJson resulting from the execution of PowerApps:UnboundActionRunner where the ActionNameand InputJson of the Custom API are supplied. So on every click to the button the flow is executed, the Custom API is called and the expression is re-evaluated based on the value of the textbox.\nSet(TableInfoResults, \u0026#39;PowerApps:UnboundActionRunner\u0026#39;.Run( \u0026#34;driv_GetTableInfo\u0026#34;, \u0026#34;{\u0026#39;LogicalName\u0026#39; : \u0026#39;\u0026#34; \u0026amp; txtInputTable.Value \u0026amp; \u0026#34;\u0026#39;}\u0026#34; ).outputjson) The new ParseJSON() function is applied on the TableInfoResults variable to display the API results on the form. This will deserialize de output of the API response and expose its properties. Here, it\u0026rsquo;s important to cast the desired property to its correct object type (string = Text, number = Value etc..). (See the ParseJSON official docs)\nAs you can see below, the Custom API is being executed on each click of the button and the results are parsed and displayed on the form.\nCalling a bound Custom API To call a bound Custom API we will use the PowerApps:BoundActionRunner from my solution. The idea is the same as the unbound api version so I will not repeat everything.\nThe main differences are at the trigger level as more input parameters are expected.\nTableCollectionName: Collection Name of the Table (normaly the plural name) RecordId: uniqueidentifier (GUID) of the bound record ActionName : this expects the unique name of the Custom API InputJson : this expects a string in JSON format that contains the request parameters (inputs) one wishes to pass to the Custom API. There\u0026rsquo;s also a minor difference in the way that the Action Name needs to be set on the Perform bound action step ( Microsoft.Dynamics.CRM.{ActionName}).\nCalling the flow from a Canvas App For this demo, the button click will call the GetTimezoneInfo Custom API using the current user as the bound record.\nAgain, a variable is set (UserTimezoneResults) with the OutputJson received from the PowerApps:BoundActionRunner flow. The\nSet(UserTimezoneResults, (\u0026#39;PowerApps:BoundActionRunner\u0026#39;.Run( \u0026#34;systemusers\u0026#34;, First(Filter(Users,\u0026#39;PrimaryEmail\u0026#39;=User().Email)).User, \u0026#34;driv_GetUserTimezone\u0026#34;, \u0026#34;\u0026#34;) .outputjson)) The same principle as earlier is applied to Parse the response of the flow and display the results on the form.\nAs you can appreciate, whenever the button is clicked the Custom API will be executed accordingly.\nTakeaway As cool as this is, I have to admit that I hope that this solution will have a short lifespan. It would be great if Custom APIs could be surfaced and executed directly inside Canvas Apps and Custom Pages.\nIn my opinion, the fact that we have to delegate the Custom API call to a PowerAutomate wrapper adds an unnecessary layer of complexity that can affect performance and maintainability.\nAlso, an important point to consider is the concurency on the flow and the API call limit. Since the flows are using a common connection to the Dataverse environment, this means that the same connection will be used for each execution. So if you have several apps used by hundreds of users all using the same flows and connections, you might run into problems down the road.\nBut hey, on the bright side of things let\u0026rsquo;s celebrate that with this solution Custom APIs can be unleashed in the realm of Canvas Apps. I see a lot of use cases for this.\nLinks ParseJSON function in Power Apps (experimental) - Power Platform Reference information including syntax and examples for the ParseJSON function in Power Apps. learn.microsoft.com Dataverse Custom API Manager · XrmToolBox Management tool that provides 360° View of Dataverse Custom APIs. Provides CRUD operations on Custom API, Request Parameters (Inputs) and Response Properties (Outputs). www.xrmtoolbox.com GitHub - drivardxrm/Dataverse-CustomApis: Collection of Dataverse Custom Apis Collection of Dataverse Custom Apis. Contribute to drivardxrm/Dataverse-CustomApis development by creating an account on GitHub. github.com GitHub - drivardxrm/PowerApps.Action.Runner: Generic Power Automate Flows to run Dataverse Custom APIs an Actions in Canvas Apps Generic Power Automate Flows to run Dataverse Custom APIs an Actions in Canvas Apps - GitHub - drivardxrm/PowerApps.Action.Runner: Generic Power Automate Flows to run Dataverse Custom APIs an Actio... github.com Photo by Pavan Trikutam on Unsplash\n","date":"2022-10-31T04:01:32Z","image":"/how-to-call-a-dataverse-custom-api-from-a-canvas-app/pavan-trikutam-71CjSSB83Wo-unsplash-scaled.jpg","permalink":"/how-to-call-a-dataverse-custom-api-from-a-canvas-app/","title":"How to Call a Dataverse Custom API from a Canvas App"},{"content":"While I was starting a new PowerApps Component Framework ( PCF) project, I stumbled upon the latest release notes of the framework\u0026rsquo;s main package ( pcf-scripts v1.18.4). I was stoked 🤩 to see that they improved the performance of the bundling process by switching from babel-loader to esbuild-loader.\nLet\u0026rsquo;s take this opportunity to nerd-out on the bundling process of a PCF control and see if this change really measures up ⌚.\nPCF control Bundling As a quick recap, it\u0026rsquo;s important to know that the PCF control framework uses webpack to create the bundle ( bundle.js), which is nothing more than the deployable artifact produced from the source code files and other dependencies (i.e. referenced packages, images etc.).\nI have blogged in the past on webpack and the PCF control framework 👉PCF controls – Custom Webpack configurations\n👉PCF Controls – Useful Webpack Plugins\nSince the advent of the PCF controls a couple of years ago, the frameworks webpack configuration was using babel-loader and ts-loader webpack plugins as javascript and typescript file bundlers.\nThe webpack configuration can be found in the node_modules\\pcf-scripts\\webpackConfig.js file of the project. Here i\u0026rsquo;m showing an older version of the file (v1.16.6).\nEnters Esbuild As their official tagline says, Esbuild is an extremely fast javascript bundler. It\u0026rsquo;s a next-gen bundler written in Go language with performance in mind. It can be used as a replacement for webpack and the numbers they show on performance gain compared to old-school bundlers are astonishing\u0026hellip; we are talking about 10 to 100 fold.\nHere are some interesting reads on the subject 👉esbuild - An extremely fast JavaScript bundler\n👉privatenumber/esbuild-loader: ⚡️ Speed up your Webpack build with esbuild (github.com)\n👉webpack or esbuild: Why not both? - LogRocket Blog\nOn the other hand, if you still want to use webpack, you can make use of the esbuild-loader plugin for webpack. This let\u0026rsquo;s you take advantage of the speed of esbuild inside a webpack build process.\nThat\u0026rsquo;s exactly what they did with the latest version of the pcf-scripts package (v1.18.4). If we look at the new and improved webpackConfig.js file, we can see that the javascript and typescript bundling as been delegated to esbuild-loader as well as the minification of the bundle.\nMeasuring up To measure up the build time, I\u0026rsquo;m making use of a webpack plugin called Speed Measure Plugin, this will gives nice looking output and statistics on the build process. see my previous blog post to see how to configure this.\nI will use one of my community PCF project, LookupDropdown.PCF, to do the test.\nLet\u0026rsquo;s start with the old version of pcf-scripts (v1.16.6). We can see that the build time is in the 10 seconds range with the babel-loader steps sucking up most of the build time.\nNow by simply changing the pcf-scripts package to the latest version (1.18.4) and rebuilding the project. Tada\u0026hellip;we can appreciate a significative drop in the build time with the esbuild-loader steps taking no more than 2 seconds. That\u0026rsquo;s a 125% build time improvement\u0026hellip; Fantastic!.\nTakeaway From now on, I will make sure to use the latest pcf-scripts version in my future PCF control projects and upgrade my older ones.\nKudos 👏 to the Microsoft Product team for keeping the PCF framework up to date with this kind of investment. Reducing the build time have a direct positive impact on the development experience.\nAs a side note..🤔I\u0026rsquo;m very curious about the 2nd statement in the release notes about objectType and propertyDependencies. As I can\u0026rsquo;t find any official documentation on that feature yet\u0026hellip; lets keep that for a future blog post.\nLinks pcf-scripts This package contains a module for building PowerApps Component Framework (PCF) controls. See project homepage how to install.. Latest version: 1.18.4, last published: 22 days ago. Start using pcf-scripts in your project by running `npm i pcf-scripts`. There are no other projects in the npm registry… www.npmjs.com GitHub - privatenumber/esbuild-loader: ⚡️ Speed up your Webpack build with esbuild ⚡️ Speed up your Webpack build with esbuild. Contribute to privatenumber/esbuild-loader development by creating an account on GitHub. github.com Babel · The compiler for next generation JavaScript The compiler for next generation JavaScript babeljs.io PCF controls - Custom Webpack configurations Provide your own custom Webpack configurations to a Power Apps Component Framework control. itmustbecode.com PCF Controls - Useful Webpack Plugins Enhance the PCF control development experience with the use of Webpack plugins. itmustbecode.com What is esbuild? Table of contents JavaScript’s dirty little secret ES Modules Introducing esbuild Bundling Plugins... dev.to webpack or esbuild: Why not both? - LogRocket Blog esbuild makes builds faster, but if you’re invested in webpack, esbuild-loader enables you to use esbuild alongside webpack. blog.logrocket.com Photo by Tim Trad on Unsplash\n","date":"2022-10-10T13:45:03Z","image":"/the-pcf-control-framework-chooses-esbuild-loader-for-faster-build-time/tim-trad-Ur5VN_92g-k-unsplash-scaled.jpg","permalink":"/the-pcf-control-framework-chooses-esbuild-loader-for-faster-build-time/","title":"The PCF Control Framework chooses Esbuild-Loader for Faster Build Time"},{"content":"This is the second part of a series on Storybook for PowerApps Component Framework ( PCF) controls, where I take one of my community PCF control hosted on Github (CountryPicker.PCF) and implement a Storybook from scratch.\nWhile the first post, revolved around the setup and authoring process of the Storybook, this one focuses on the publishing steps required to make Storybook static site publicly available from GitHub Pages.\nWe\u0026rsquo;ll start by uploading the Storybook site manually. And then, with the help of a GitHub action, we will implement a release pipeline that publishes the site on every commit to the code repository.\nWhy GitHub Pages ? In essence, Storybook is an open source framework used to develop, test and document UI components in isolation. It creates beautiful static websites out of the stories (use cases) that can be shared amongst team members or publicly.\nGitHub Pages is a 💸 free static site web hosting service that can serve sites directly from a GitHub repository. Moreover, since the PCF project used is already hosted on GitHub, It makes a lot of sense to host the Storybook site using the GitHub Pages service.\nWhen published GitHub Pages sites can be reached following this convention :\nhttps://{your_github_handle}.github.io/{repository_name} You can access the GitHub Pages configurations by navigating to the Settings -\u0026gt; Pages Tab of any GitHub repository.\nThe subject is vast and goes far beyond the scope of this post. If you want to dig deeper into GitHub pages, here are some good reads :\n👉About GitHub Pages - GitHub Docs\n👉Collection: GitHub Pages examples\nPublish Storybook to GitHub Pages manually To better understand the process, let\u0026rsquo;s build and deploy our site to GitHub Pages manually at first. We will continue where we left in part 1.\nI\u0026rsquo;m following the steps described in this blog post : 👉How to Deploy Storybook to GitHub Pages | by Armin Yazdani | The Startup | Medium\nLet\u0026rsquo;s start by installing the gh-pages npm package to the project.\nnpm install gh-pages --save-dev Then add the following line in the scripts section of the package.json file.\n\u0026#34;deploy-storybook\u0026#34;: \u0026#34;gh-pages -d storybook-static\u0026#34; This script will execute the gh-pages deploy command with the content of Storybook default output folder ( storybook-static).\nTo ensure that we have the latest version at hand, the first step is to compile the Storybook by running the build-storybook command. Since we are using the default configurations, this will produce the output of the static website in the \u0026rsquo; storybook-static\u0026rsquo; folder.\nNow we can run the deploy-storybook script that was added earlier.\nThe first time that the deploy-storybook script is executed, it automatically creates a \u0026rsquo; gh-pages\u0026rsquo; branch in the code repository (\u0026hellip; this will be useful later). After that it copies and commit the content of the local storybook-static folder into it.\nUpon any commit to the gh-pages branch, an internal GitHub action \u0026rsquo; pages-build-deployment\u0026rsquo; will kick, that will deploy the content of the branch to GitHub Pages.\nOnce the pages-build-deployment action is completed, you\u0026rsquo;ll be able to appreciate your Storybook static website at the repository\u0026rsquo;s own GitHub Pages address : https://{your_github_handle}.github.io/{repository_name}\nThat\u0026rsquo;s a good start, but it\u0026rsquo;s far from ideal since most of the steps were done manually and the content of the site came from a local folder.\nPublish Storybook to GitHub Pages Automatically Let\u0026rsquo;s push this a little further and automate the process so that a fresh version of the Storybook website gets published on every commit to the underlying GitHub repository.\nI\u0026rsquo;m basically following the steps from this blog post, so credit goes to the author 👉https://budiirawan.com/how-to-publish-storybook-github-pages/\nBecause of the manual publish done earlier our code repository already contains a gh-pages branch so the only remaining step is to create a GitHub action folder in the project .github/workflows/ and create an action file storybook.yml.\nThe script uses the following (widely used) community GitHub action 👉 https://github.com/JamesIves/github-pages-deploy-action\nOnce commited in the repo, the action will trigger on every commit to the main branch. It\u0026rsquo;s basically doing the same thing explained earlier in the manual steps but inside a build agent instead of locally on your computer.\nrun build-storybook-\u0026gt; will generate the Storybook static website in the storybook-static folder. github-pages-deploy-action -\u0026gt; will publish the content of the storybook-static folder in the gh-pages branch. Upon commit to the gh-pages branch, the pages-build-deployment action will be triggered and the site will be published. Thats all there is, you now have a fully automated release pipeline for your PCF control Storybook site. You won\u0026rsquo;t have to do anything and your Storybook website will be refreshed upon any change the source code.\nThis makes GitHub Pages the perfect vehicule to host Storybook sites and broadcast community PCF controls usage and documentation to potential users.\nThe final Storybook can be found here : 👉https://drivardxrm.github.io/CountryPicker.PCF/\nLinks Storybook for PCF Controls - Part 1 : Set the Story Straight Learn how to implement and publish a Storybook for a Power Apps Component Framework project. itmustbecode.com What is GitHub Pages? GitHub Pages lets you turn GitHub repositories into websites that showcase your portfolio, your projects, their documentation, or anything else you want to s... youtu.be How to Deploy Storybook to GitHub Pages I used Storybook to document my React components and host it on GitHub Pages to make it accessible for other members of the team… medium.com How to publish Storybook to Github Pages In this post, I’m going to share about how to deploy Storybook to Gihub pages via Github Actions. budiirawan.com GitHub - JamesIves/github-pages-deploy-action: Automatically deploy your project to GitHub Pages using GitHub Actions. This action can be configured to push your production-ready code into any branch you’d like. Automatically deploy your project to GitHub Pages using GitHub Actions. This action can be configured to push your production-ready code into any branch you\u0026#39;d like. - GitHub - JamesIves/github-... github.com gh-pages Publish to a gh-pages branch on GitHub (or any other branch on any other remote). Latest version: 4.0.0, last published: 5 months ago. Start using gh-pages in your project by running `npm i gh-pages`. There are 940 other projects in the npm registry using gh-pages. www.npmjs.com Image by Mahesh Patel from Pixabay\n","date":"2022-09-29T00:16:42Z","image":"/storybook-for-pcf-controls-part-2-publish-to-github-pages/announcement-g26ae1b59d_640.jpg","permalink":"/storybook-for-pcf-controls-part-2-publish-to-github-pages/","title":"Storybook for PCF Controls - Part 2 : Publish to GitHub Pages"},{"content":"In the frontend development world, Storybook as emerged as the industry standard to showcase and test UI components.\nIn this series of posts I will show how easy (and rewarding) it is to implement and publish a Storybook for a PowerApps Component Framework (PCF) project. That way users can have a direct and interactive access to the control without having to install anything on their side.\nPart 1, will focus on setting up Storybook and write the stories in the context of a PCF control project. Part 2, will demontrate how to publish the Storybook to Github Pages on every commit using GitHub Actions. What is Storybook In essence, Storybook is a framework that helps web developers express and test frontend workflows. It can be used for building, documenting, and testing UI components in isolation.\nStories are files that wraps up a specific component and supply a set of props and mock data. It provides a way to see different variations of a component and assess its rendering and behavior without the need to spinup the whole application.\nWhen built, Storybook generate a beautiful static website out of the stories files that can be published and shared amongst team members (or publicly).\nThe ecosystem is highly extendable and the stories can also be reused with other popular tools like Jest and Playwright just to name a few.\nHere\u0026rsquo;s a very good synthesis on the matter 👉Why Storybook in 2022?\nYou can appreciate a Storybook generated site with the FluentUI React V9 official docs from Microsoft 👉https://react.fluentui.dev/\nIs Storybook is a good fit for PCF controls ? By design, PCF Controls are frontend components for Microsoft PowerPlatform that can be configured on a Dataverse Field or Dataset to change the platform out-of the box rendering.\nBy leveraging the PCF framework, developers can use modern frontend stack and libraries (React, Vue etc..) to build rich user experiences. The ultimate goal is to have controls that can be packaged, deployed in any Dataverse environment and used without any coding skills by the form configurators (Makers).\nWith this in mind, especially if you develop community PCF controls, a Storybook is a great way to provide a sneak peek of your controls to end users that might not be pro coders. Potential users can then have a good idea of the look and feel a PCF control before installing it on their environments.\nI have already published a couple Storybook for some of my community controls, have a look here:\nFluentUI Badge Storybook FluentUI Slider Storybook LIMITATIONS\nDepending on how you designed your PCF Control, It might prove a bit difficult to implement your stories.\nIf the component you want to test has dependencies on the Datavese WebAPI or the ComponentFramework.Context objects, you will have to mock these objects in your stories because Storybook knows nothing about Dataverse and is not connected to a particular environment.\nFor those reasons, I recommend to remove any dependencies (if possible) on the PCF framework objects and use a flat interface for the component properties as we will see in the next section.\nUse Case : Country Picker PCF To better illustrate the setup process of a Storybook for a PCF control project, I will take one of my community project, the CountryPicker PCF, and guide you through the Storybook creation and publishing steps.\nThe main component of the PCF project is a React Component called CountryPickerApp and this will be the component being rendered by our Storybook..\nIt accepts the following IViewModel interface as props. The interface is quite flat and the properties are derived from the ComponentFramework.Context parameters defined in the ControlManifest. There is also a callback function that notifies back to the form when a user selects a new country from the dropdown.\nAs seen in the index.ts screenshot, the viewmodel is completely decoupled from any PCF framework dependencies and the CountryPickerApp component will be easilly portable to Storybook.\nSetup Storybook for a PCF project In doubt or in case of roadblock, follow the official documentation, its quite straightforward. Install Storybook\nAs a first step, install Storybook to your project. Assuming that you are using Visual Studio Code, open a terminal and run the following command at the at the root of the project\n# Add Storybook: npx storybook init A lot of things will happen here, new dependencies and scripts(in greenbelow) are added to the package.json file. Most important, the installer detected that my PCF control is a React project and added the right extension package ( @storybook/react)\nNotice also new folders that contains Storybook configuration files and boilerplate stories to get you up and running.\nBefore going any further, we can check that the Storybook can be built by running this command\nnpm run storybook Alternatively, you can also run the start-storybook command from the NPM Scripts section in VS Code.\nThis will build a static website out of the content of the stories directory and serve the pages locally, it gives a good idea of what can be achieved.\nStorytelling Now here\u0026rsquo;s the real deal, it\u0026rsquo;s time to author our own Storybook content and tell the story of the PCF control project.\nA good pattern is to have an Introduction page that summarize what the PCF control does and several stories (chapters) that represent specific use cases of the control. Of course you are not limited to that and you can build pretty much what you want here, be creative.\nI\u0026rsquo;ll start by setting up the Intro page by opening the Introduction.stories.mdx file in the stories folder ( added as a boilerplate during initial install).\nBy tweaking the existing template and editing the files markdown and html, I\u0026rsquo;ll add some info on the control features and provide links to the Github Repo and the PCF Gallery link, here\u0026rsquo;s what it looks like. (see code in the repo for reference)\nNow its time to add the actual stories. The subject is very vast so I strongly recommend that you read to the official documentation to learn the best practices and to get a grasp of all the possibilities of the Storybook framework.\n👉 How to write stories (storybook.js.org)\nStorybook stories are defined using the Component Story Format (CSF) which is an open standard not limited to Storybook.\nStories can be edited in different formats (js | ts | jsx | tsx | mdx) but for simplicity I will use tsx for this blog post.\nThe main part of a story file is called the default export, it describes the metadata about the component being storied. This is complemented by one or several named exports that represents the different flavors of the component being rendered (ex. different set of props)\nAs seen in the code below, the stories being defined by the default export will do the following.\n1️⃣Render instances of CountryPickerApp(the main entry point of the PCF control). 2️⃣Decorate each stories with additional html for styling. 3️⃣Set some default arguments (props) for the control. // CountryPicker.Demo.stories.tsx // .. imports removed for clarity export default { title: \u0026#39;Country Picker/Demo\u0026#39;, component: CountryPickerApp, decorators: [ (Story) =\u0026gt; ( \u0026lt;div style={{ margin: \u0026#39;3em\u0026#39; , maxWidth:\u0026#39;350px\u0026#39;}}\u0026gt; {Story()} \u0026lt;/div\u0026gt; ) ], args:{ countrycode: \u0026#39;\u0026#39;, language : \u0026#39;en\u0026#39;, displayinfo: true } } as ComponentMeta\u0026lt;typeof CountryPickerApp\u0026gt;; In my story file, I want to display several flavors of the same components representing different uses cases. In order to have clean code, I will define a template that can be reused by all the stories.\nAlso, to help us down the road, I will add another package to the project. @storybook/client-api\nnpm install --save-dev @storybook/client-api This package exposes a React hook called useArgs that i\u0026rsquo;m using to dynamically update the story args at runtime when a user selects a country from the dropdown. You can get more context from this blog post :\nChanging args values / state in Storybook (without useState hook) + ReactJS | by Nadine Thery | urbanData Analytics | Medium\nThe template looks something like this :\nconst Template: ComponentStory\u0026lt;typeof CountryPickerApp\u0026gt; = (args) =\u0026gt; { const [, updateArgs] = useArgs(); args.onChange = (countrycode:string, countryname:string) =\u0026gt; { console.log(`PCF NotifyOutputChanged =\u0026gt; ${countrycode}:${countryname}`) updateArgs({countrycode: countrycode}) } return \u0026lt;CountryPickerApp {...args} /\u0026gt;; } With a template in place, its now super easy to define the named exports that represents different stories (use cases) of the component. By binding the named export to the template, and supplying to each story a different variation of the arguments. ( the final file can be found here)\nexport const Default = Template.bind({}); export const Promoted = Template.bind({}); Promoted.args = { promoted : [\u0026#39;CAN\u0026#39;,\u0026#39;USA\u0026#39;,\u0026#39;MEX\u0026#39;] } export const Limited = Template.bind({}); Limited.args = { limit : [\u0026#39;CAN\u0026#39;,\u0026#39;USA\u0026#39;,\u0026#39;MEX\u0026#39;] } export const Disabled = Template.bind({}); Disabled.args = { countrycode : \u0026#34;CAN\u0026#34;, readonly : true } export const Masked = Template.bind({}); Masked.args = { countrycode : \u0026#34;CAN\u0026#34;, masked : true } When the Storyboook is running, you can see that the countrycode argument is being updated dynamically when the user is changing the selected country.\nAt the end, my stories folder contains only 3 files. I\u0026rsquo;m defining another story to display the different languages but the concept is the same (see the code in the repo for reference).\nWhen built, these 3 files will generate a full-fledge, visually attractive and interactive website.\nAll the different stories are hierarchically displayed on the left side. Each story renders its own instance of the CountryPicker component with different permutations. Most important, the user can test the components and change the input parameters as he wish. In my opinion, this is pure gold and adds a lot of value for the end users as well as for developers.\nYou can browse the CountryPicker PCF Storybook here https://drivardxrm.github.io/CountryPicker.PCF\nWe\u0026rsquo;ll take a break for now and in the next post, I will show how to publish and host the Storybook to GitHub pages for everyone to enjoy.\nStay tuned!\nLinks Storybook: UI component explorer for frontend developers Storybook is an open source tool for building UI components and pages in isolation. It streamlines UI development, testing, and documentation. storybook.js.org Why Storybook in 2022? What’s all the fuss about Storybook storybook.js.org Country Picker A control that renders a Text field as a Combobox displaying country names and flags. Country information comes from the public API https://restcountries.eu. pcf.gallery Changing args values / state in Storybook (without useState hook) A quick glance at how to change your stories args values within Storybook and ReactJs. To be combined with Storybook Controls. medium.com Image by Gerhard from Pixabay\n","date":"2022-09-12T01:43:09Z","image":"/storybook-for-pcf-controls-part-1-set-the-story-straight/book-ga3d7b30ed_640.jpg","permalink":"/storybook-for-pcf-controls-part-1-set-the-story-straight/","title":"Storybook for PCF Controls - Part 1 : Set the Story Straight"},{"content":"Microsoft recently unveiled the first stable version of FluentUI React v9( @fluentui/react-components). This new edition of FluentUI is the result of joint efforts from the Office and Teams product teams to streamline their respective React front-end libraries into one component framework.\nTo celebrate this 🎉, I have released 2 community PowerApps Control Framework ( PCF) Controls that targets this new library.\nIn this post I will reflect on my experience authoring PCF controls with this new set of components and highlight the main differences with prior versions.\nBut first, here are the links to my new PCF controls. Download them from their respective github repo or play with them in their associated Storybooks.\nFluentUI Badge PCF FluentUI Badge | PCF Gallery drivardxrm/FluentUI.Badge.PCF (github.com) Introduction - Page ⋅ Storybook (drivardxrm.github.io) FluentUI v9 as a very decent badge system, and this PCF control is merely a ( configurable) wrapper around the out-of-the-box badge control exposed by the library.\nThe control can be installed on almost every type of Dataverse field. UX-wise, it\u0026rsquo;s a good way to put emphasis on your forms read-only data.\nIf you are into badges, I also have developped another cool PCF control that renders Shield.Io badges. Have a look here :\nPCF control - Generate Shields.IO Badges in the PowerPlatform - It Must Be Code!\nFluentUI Slider PCF FluentUI Slider | PCF Gallery drivardxrm/FluentUI.Slider.PCF (github.com) Introduction - Page ⋅ Storybook (drivardxrm.github.io) This control is a bit more complicated than the first one and includes more components like Badges and a Tooltip that follows the handle to provide more context to the user. Use this one to infuse some joy over your forms numerical fields.\nWhy FluentUI is a good match for PCF controls ? Considering that React and FluentUI ( version 8) are the main librairies used by PowerApps runtime to render Model-Driven Forms, it\u0026rsquo;s a natural choice (at least for me) to leverage the same stack for PCF control development.\nBy doing so, while you might have some styling to do, you ensure that the control will blend nicely with the existing form thus providing a better UX.\nWhat as changed in FluentUI v9 Even though they share the same branding, FluentUI React v9 ( @fluentui/react-components) is not an upgrade ⛔ from v8 ( @fluentui/react) but a completely different library with a new architecture. In fact as stated in the official doc :\nFluent UI React Components is a set of UI components and utilities resulting from an effort to converge the set of React based component libraries in production today: @fluentui/react and @fluentui/react-northstar.\n🔖 Bookmark the link to the official docs, this is where you\u0026rsquo;ll find up to date information on the library controls, code examples and upgrade path from previous versions.\nAs you would expect, FluentUI React v9 offers a rich set of form controls like Input, Button, Checkbox and so on. Keep in mind that some of them are still in preview (ex. Dropdown) (see 🛣️ roadmap here)\nAt this point in time not all the controls from v8 have a v9 counterpart, but on the bright side, there are some controls that are unique to v9 like the Badge component that I used in my 2 PCF controls.\nThe most notable differences from FluentUI v8 revolves around these aspects that will be discussed later on.\n🎨 Theming ✨ Styling 🖥️ Rendering 🏃🏽 Performance Getting started First, let\u0026rsquo;s see how to setup a PCF project to use the library.\nHere, I assume that you already have installed React on your PCF project and that all the plumbing is done in the index.ts file to render the control as a React App.\nSimply, npm install the FluentUI React v9 library ( @fluentui/react-components) in your project.\nnpm install @fluentui/react-components Now wrap your React component/app with a and provide a theme as a prop. As you can see in the folowing example that renders a very simple FluentUI Button.\nimport { Button, FluentProvider, webLightTheme } from \u0026#39;@fluentui/react-components\u0026#39; const SimpleApp= (): JSX.Element =\u0026gt; \u0026lt;FluentProvider theme={webLightTheme}\u0026gt; \u0026lt;Button appearance=\u0026#34;primary\u0026#34;\u0026gt;Hello FluentUI React v9\u0026lt;/Button\u0026gt; \u0026lt;/FluentProvider\u0026gt; export default SimpleApp 🎨 Themes One of the main difference between FluentUI React V9 and v8 is the ability to provide (inject) a theme to a component. A theme is basically a set of common tokens that can be assigned as CSS properties. Each theme having its own definition of a specific token.\nOffial docs : Concepts / Developer / Theming - Page ⋅ Storybook (fluentui.dev)\nAs we saw earlier, a theme is injected through the element. The Fluent UI v9 components will natively adapt to the provided theme and any exposed tokens of the theme can also be used to further customize the styling of the app.\nThere are 5 out of the box themes :\nWeb Light Web Dark Teams Light Teams Dark Teams High Contrast See the all the color definitions and token list here : Theme / Color - Page ⋅ Storybook (fluentui.dev)\nIn the controls that I published, I included a Theme parameter so that a theme can be supplied by the end-user to alter the look and feel of the PCF controls.\nAs you can see here, the same control will render differently depending on the applied theme.\nYou can also create (or extend) your own theme, have a look at this artice Quick branded light and dark modes with Fluent UI React v9 - DEV Community\n✨ Styling In terms of styling, FluentUI React v9 is built on top of Griffel, a new open source CSS-in-JS engine from Microsoft. You can find a lot of good information on in the docs here.\nIn a very simplistic example, here is how to use Griffel to style a component:\nDefine your classes using the makeStyles Griffel function ( needs to be defined outside of the element) Reference the resulting hook inside your component. Any exposed class can now be injected in the components via the className attribute import { makeStyles, tokens, Button, FluentProvider, webLightTheme } from \u0026#34;@fluentui/react-components\u0026#34;; const useStyles = makeStyles({ myclassname: { backgroundColor: tokens.colorPaletteRedBackground3 } }); const SimpleStyleApp = (): JSX.Element =\u0026gt; { const classes = useStyles(); return ( \u0026lt;FluentProvider theme={webLightTheme}\u0026gt; \u0026lt;Button className={classes.myclassname}\u0026gt;Hello FluentUI React v9\u0026lt;/Button\u0026gt; \u0026lt;/FluentProvider\u0026gt; ); }; export default SimpleStyleApp; One of the component that I used a lot from FluentUI v8 is the Stack component. The stack components lets you easilly position your elements in an horizontal or vertical manner. In fact its syntactic sugar that wraps your element in CSS Flexbox layout.\nUnfortunaletly there are no direct alternative for Stacks and StackItems in v9 but there is a nice section in the docs on how to upgrade components from v8 to v9. There, you\u0026rsquo;ll find how to use FluentUI v9 CSS-in-JS to achieve the same results as the v8 Stacks and StackItems.\nI have used a slightly modified version of the upgrade path in the FluentUI Slider control and I was able to stack my elements nicely. Here is a simplified version that renders horizontal (row) and vertical (column) stack.\n🖥️ Rendering Another big architectural change in FluentUI v9 is the use of Slots. By definition slots are parts of a given component where you can inject anoter react element.\nThis is a real game changer compared to v8 where you often have to inject complex rendering callback function to alter the look and feel of a component.\nHeres a good post that explains how to work with FluentUI v9 Slots Using Slots with Fluent UI React v9 - DEV Community\nHere is a very good example that shows the simplicity(and power) of working with slots. We see that the content attribute of a Tooltip component can accept not only a simple text attribute but any other complex components (JSX.Element) like a Badgeor an Avatar.\nimport { Tooltip, Badge, Button, Avatar, FluentProvider, webLightTheme } from \u0026#39;@fluentui/react-components\u0026#39; const SimpleSlotApp = (): JSX.Element =\u0026gt; \u0026lt;FluentProvider theme={webLightTheme}\u0026gt; \u0026lt;Tooltip content=\u0026#39;simple text injected\u0026#39; relationship=\u0026#39;label\u0026#39;\u0026gt; \u0026lt;Button\u0026gt; Hover me (simple text) \u0026lt;/Button\u0026gt; \u0026lt;/Tooltip\u0026gt; \u0026lt;Tooltip content={\u0026lt;Badge\u0026gt;Badge injected\u0026lt;/Badge\u0026gt;} relationship=\u0026#39;label\u0026#39;\u0026gt; \u0026lt;Button\u0026gt; Hover me (badge) \u0026lt;/Button\u0026gt; \u0026lt;/Tooltip\u0026gt; \u0026lt;Tooltip content={\u0026lt;Avatar name=\u0026#34;David Rivard\u0026#34; image={{ src: \u0026#39;https://avatars.githubusercontent.com/u/38399134?s=400\u0026amp;v=4\u0026#39; }} /\u0026gt;} relationship=\u0026#39;label\u0026#39;\u0026gt; \u0026lt;Button\u0026gt; Hover me (Avatar) \u0026lt;/Button\u0026gt; \u0026lt;/Tooltip\u0026gt; \u0026lt;/FluentProvider\u0026gt; export default SimpleBadgeApp I have used this technique in the FluentUI.Slider.PCF to render a badge inside the Tooltip, look at the source code for reference.\n🏃🏽 Performance One of the claim made by the FluentUI v9 team is they refactored, slimmed down components and optimize the dependencies. This should produce lightweight and performant components.\nIn the context of a PCF control project, I already blogged on a problem I had building my project with FluentUI v9, so please have a look and be sure to configure your tsconfig.json file correctly, to optimize the final bundle size.\nPCF Controls - Tree-Shaking For Better Bundle Size - It Must Be Code!\nIn terms of bundle size, I think it kind of delivers. The the FluentUI Badge and Slider PCF components are below the bar of 90kb for the deployable managed solution. (Manifest + bundle + image)\nTakeaway Overall, my experience with FluentUI v9 is very positive. I really like some of the new features especialy the slots system that removes some complexity I have experienced in the past using controls from v8.\nI like the theming capabilities as it brings consistency to the look and feel. And, since Teams is becoming the Hub for a lot of applications, having a way to design components with the official Teams colors is a big plus.\nWill I still use FluentUI v8 ? probably if I need to render text flields or dropdowns in a Model-driven app, only because v8 is the current library used by the product.\nBut who knows 🤷 maybe FluentUI React v9 will become the next PowerApps runtime library. So I think that learning how to tackle with it is a good time investment for PCF developers.\nLinks GitHub - microsoft/fluentui: Fluent UI web represents a collection of utilities, React components, and web components for building web applications. Fluent UI web represents a collection of utilities, React components, and web components for building web applications. - GitHub - microsoft/fluentui: Fluent UI web represents a collection of utili... github.com Fluent UI React Fluent UI React Components is a set of UI components and utilities resulting from an effort to converge the set of React based component libraries in production today: @fluentui/react and @fluentui/react-northstar. react.fluentui.dev What’s new with Fluent UI React v9? After nearly two years in development, we are proud to announce the release of Fluent UI React v9 to... dev.to Using Slots with Fluent UI React v9 Fluent UI React v9 components have customizable parts called “slots.” An example of this is the icon... dev.to Quick branded light and dark modes with Fluent UI React v9 When building Teams Apps, Office Add-ins, or any kind of Microsoft 365 integration there’s always a... dev.to Photo by Adrian Curiel on Unsplash\n","date":"2022-08-26T04:50:52Z","image":"/develop-pcf-controls-with-fluentui-react-v9/adrian-curiel-PwQHfxo3Q2Y-unsplash-1-scaled.jpg","permalink":"/develop-pcf-controls-with-fluentui-react-v9/","title":"Develop PCF Controls with FluentUI React v9"},{"content":"Building modern front-end controls and application requires great care to keep the size of the assets as low as possible. The development of PowerApps Control Framework (PCF) controls doesn\u0026rsquo;t fall short from this rule.\nIn this post I will show how to optimize the tree-shaking process and reduce thebundle size of PCF controls with simple adjustments to module resolution of the Typescript configuration file.\nHow I got there After seeing this tweet from Scott Durow that announced the release of FluentUI React v9 , I felt the urge and I immediately started a new PCF control project that targets this new library.\nhttps://twitter.com/ScottDurow/status/1548085913946714112\nFluentUI v9 offers a nice badge system and I decided to develop a FluentUI Badge PCF control ( available soon in your favorite PCF Gallery 😎).\nOverall, it\u0026rsquo;s a very simple control so everything went smooth. I was able to build my project locally and test the control in the test harness. The problem came when I had to package my solution and deploy it to a Dataverse environment.\nWhen I tried to compile a production build and package a solution using the usual command.\ndotnet build -c release I got a dreaded\u0026rsquo; unexpected error\u0026rsquo; with no particular explanation. What immediately caught my attention was the reported size of the bundle.js file that was said to be 12 Mb (Way too big for the small control I am building)\nThen I decided to kick a development build of the control wich I knew was working and inspect the output folder. Turns out that the bundle size of my control was about 18 Mb, so something was definitely wrong here.\n🌴Tree-Shaking to the rescue Tree-shaking is a process that removes unnescessary and unreachable code from imported libaries in order to keep the bundle size as low as possible. Literally, it\u0026rsquo;s like shaking your project, which has a tree-like structure, to remove the dead leaves.\nFor example in my project, I have the following imports from the FluentUI library\nimport { Badge, FluentProvider, makeStyles, webLightTheme } from \u0026#39;@fluentui/react-components\u0026#39; As a result, I should expect that only the code from these assets to be included in the production bundle and not the whole library \u0026hellip; hence the 18 Mb we saw earlier.\nTo implement proper tree-shaking in a PCF control project, you can refer to Microsoft official best practices documentation. It shows how to fine-tune the module resolution of the Typescript configuration file ( tsconfig.json) to optimize the bundle size.\nI modified the tsconfig.json file of my project by adding these 2 lines.\n{ \u0026#34;extends\u0026#34;: \u0026#34;./node_modules/pcf-scripts/tsconfig_base.json\u0026#34;, \u0026#34;compilerOptions\u0026#34;: { \u0026#34;typeRoots\u0026#34;: [\u0026#34;node_modules/@types\u0026#34;], \u0026#34;module\u0026#34;: \u0026#34;es2015\u0026#34;, \u0026#34;moduleResolution\u0026#34;: \u0026#34;node\u0026#34; } } And to my surprise, the development build immediately went down from 18 Mb to 1.3 Mb.\nNote : the Microsoft documentation states that these configuration should only affect release/production builds, but It seems in that particular case that it also affects development build\nMoreover, I was now able to trigger a production build with no error and package my solution. The production bundle size went down to 211 Kb and the final compressed solution to 71 Kb. Now you are talking !\nAfter witnessing that kind of improvement, I decided to revisit some of my existing community PCF controls and recompile them with module resolution configurations to see the effect on bundle size.\nWith a percent reduction of the deployable solution of more than 50% for most of the controls, let\u0026rsquo;s say that I\u0026rsquo;m very happy with the results 🎉.\nRating.PCF : 304 kb ➡️ 95 kb ( -69%) IconTwoOption.PCF : 290 kb ➡️ 93 kb ( -68%) IconOptionSet.PCF : 295 kb ➡️ 129 kb ( -56%) TimePicker.PCF : 407 kb ➡️ 183 kb ( -55%) CountryPicker.PCF : 386 kb ➡️ 178 kb ( -54%) ShieldsIO.Badge.PCF : 64 kb ➡️ 53 kb ( -16%) DateTwoOption.PCF : 110 kb ➡️ 99 kb ( -10%) Take Away With such a clear effect on the bundle size, I will not forget to add the module resolution lines in the typescript configuration of my future PCF control projects.\nIf you want to deep-dive on tree-shaking and module resolution, here are some interesting reads.\nTree-Shaking: A Reference Guide — Smashing Magazine Reduce JavaScript payloads with tree shaking (web.dev) TypeScript: TSConfig Reference - Docs on every TSConfig option (typescriptlang.org) TypeScript: Documentation - Module Resolution (typescriptlang.org) And remember \u0026hellip; Size does matter!\nPhoto by Eva Bronzini - Pexels\n","date":"2022-07-25T02:29:08Z","image":"/pcf-controls-tree-shaking-for-better-bundle-size/pexels-eva-bronzini-5949339-1.jpg","permalink":"/pcf-controls-tree-shaking-for-better-bundle-size/","title":"PCF Controls - Tree-Shaking For Better Bundle Size"},{"content":"In this episode of the Visual Studio Talk Show, I had the great pleasure to talk (In French) with Microsoft MVP\u0026rsquo;s Mario Cardinal and Guy Barette.\nWe talked about the PowerPlatform in general and mostly about my open source PCF control projects.\nVisual Studio Talk Show: 0266 – David Rivard – PowerApps Control Framework (PCF) Nous discutons avec David Rivard de PowerApps Control Framework (PCF), un cadre de programmation logiciel permettant de créer des composantes UI pour l’outil Power Apps. Power Apps permet l’écriture d’applications commerciales sans être un programmeur professionnel car il nécessite très peu de code… visualstudiotalkshow.libsyn.com ","date":"2022-04-08T03:47:38Z","permalink":"/visual-studio-talk-show/","title":"Visual Studio Talk Show"},{"content":"One of the thing I like the most about PCF controls for the PowerPlatform is the ability to change the normal behavior and rendering of forms attributes to add a new twist to the user experience.\nWith that in mind, for my latest communityPCF control, ShieldsIO.Badge.PCF, I wanted to bring the ability to render custom (and awesome ) Shields.IO badges to the PowerPlatform.\nUsing badges in Model-driven or Canvas Apps forms is a great way to provide concise, actionable and visually appealing controls to end users.\nFor example, these out-of-the-box Model-driven forms fields :\nCan be turned into these slick looking badges :\nWhat is Shields.IO But, before we dive into the PCF control implementation, let\u0026rsquo;s introduce the Shields.IO service.\nEven if you are not familiar with Shields.IO badges, chances are that you\u0026rsquo;ve already seen them (virally) poping here and there while browsing your favorite platforms. The service is very popular especialy to display status badges.\nYou can see some good example in the read.me of the Shields.IO project github repo.\n💸 If you like Shields.IO , please consider donating here : shields.io - Open Collective 💸\nThe concept behind Shields.IO is to render dynamic badges(images) that are expressed with URLs that contains the needed metadata.\nbadgeurl = https://img.shields.io/{badge-metadata} So, when an URL is defined as the source of an html image tag , the image is dynamically fetched and served from the shields.io service when requested.\nThis makes the Shields.IO badges very useful to display dynamic data that changes over time like build status, download count, social media followers\u0026hellip; you name it.\nPredefined badges There are a ton of predefined badges model for different popular services like github, nuget, twitter just to name a few. (Check the official shields.io site for more examples)\nAs can be seen in this screenshot of one of my github repo . These nuget badges Urls will render the download count and the current version badges of my package.\nhttps://img.shields.io/nuget/dt/XTB.CustomApiManager https://img.shields.io/nuget/v/XTB.CustomApiManager Or this one that will render a follow link to my Twitter acount with my follower count.\nhttps://img.shields.io/twitter/follow/david_rivard?style=social Custom badges Most importantly, one of the great feature of Shields.IO is the custom badges system that uses a generic notation that looks like this :\nhttps://img.shields.io/badge/\u0026lt;LABEL\u0026gt;-\u0026lt;MESSAGE\u0026gt;-\u0026lt;COLOR\u0026gt; Hence, using this URL :\nhttps://img.shields.io/badge/shields.io-rocks!-orange Will render a badge that looks like this :\nIn addition, there are also a bunch of other switches that can be added as querystrings to provide additional features like styling, logos and much more.\nIt is this custom badge system that is leveraged in my new PCF control to render badges inside the PowerPlatform.\nShields.IO Badge PCF control To try out the PCF control, wait no more and download the latest version of the ShieldsIO.Bagde.PCF from this github repo (or find it exposed on the great PCF gallery) and install the solution in your Dataverse environment.\nNote : My examples are focused on Model-Driven apps, but the ShieldsIO.Badge PCF control also works in Canvas Apps and PowerApps Portals.\nUnfortunaltely at the time of writing, you still need to use the classic form editor to configure a PCF Control on a form.\nNow, navigate to any compatible field of a form, open the property editor and choose the ShieldsIO Badge from the Control Tab.\nThe selected field will be bound to the Message parameter. Values supplied in the other parameters will also have an effect on the final rendering of the badge (styling color etc\u0026hellip;).\nControl Parameters Message : Main Message of the badge, can be bound to any available field type Show Label: Display a label on the left side of the badge (true / false) Custom Label: (Optional) Custom label text, if blank the display name of the field will be shown Color : (Optional) Color of the Message 🎨 Label Color : (Optional) Color of the Label 🎨 Style: Style of the Badge (plastic / flat /flat-squared / for-the-badge / social) Logo: (Optional) Logo. see https://simpleicons.org/ for available logos Logo Color : (Optional) Color of the Logo 🎨 Url: (Optional) Redirect to this URL on click of the badge 🎨 for color paramaters : hex, rgb, rgba, hsl, hsla and css named colors supported\nBind your badges to (almost) any field on your form I have made the control as generic as possible and it\u0026rsquo;s compatible with all the field types currently supported by the PCF framework. (see official doc here for a list of supported types)\nAs can be seen below, in badges generated from more complex field types.\nLookup field\nCurrency field\nChoice field\nStyle your badges like a Boss When setting up a badge, you can supply a Style parameter. The parameter offers 5 different styles to choose from :\nAs you can see, the same badge will render differently depending on the chosen style.\nBadges look better with a logo Don\u0026rsquo;t be shy to include logos in your badges when applicable, a visual cue is always appreciated by users.\nTo include a logo, just set the Logo parameter of the PCF control. Shields.io can natively render any icons exposed by the simpleicons service.\nHere are some examples that I have used in my demos :\nlogo value****badgemicrosoftteamsvisalinkedin\nAdd some magic with calculated fields A good way to provide dynamic data to the badges is to use calculated fields as data sources.\nTake this example where the color of a Percent field is calculated based on the percent value (red, yellow, green).\nSee the results when the calculated field is passed as the Color parameter of a badge.\nMake your badges clickable A great way to add usability to the badges is to make them actionable by supplying a redirect link in the Url parameter.\nAs you can see below, It\u0026rsquo;s quite easy to render clickable badges that redirects to a contact social media landing pages.\nTakeaway With some imagination, I think that the use of the ShieldsIO badge PCF control can really add some depth to the forms and provide a rich UX.\nI\u0026rsquo;m really curious to see the kind of use cases and cool badges some of you will come up with.\nHave fun!\nLinks Shields.io: Quality metadata badges for open source projects We serve fast and scalable informational images as badges for GitHub, Travis CI, Jenkins, WordPress and many more services. Use them to track the state of your projects, or for promotional purposes. shields.io shields.io - Open Collective Concise, consistent, and legible badges… in a readme near you. opencollective.com GitHub - drivardxrm/ShieldsIO.Badge.PCF: PCF control to render Shields.io badges PCF control to render Shields.io badges. Contribute to drivardxrm/ShieldsIO.Badge.PCF development by creating an account on GitHub. github.com ShieldsIO Badge A Control to render Shields.IO badges from Dataverse data Can be bound to most of the available fields type Provide a redirect URL to make badges clickable pcf.gallery ","date":"2022-04-07T02:49:10Z","image":"/pcf-control-generate-shields-io-badges-in-the-powerplatform/repository-open-graph-template.png","permalink":"/pcf-control-generate-shields-io-badges-in-the-powerplatform/","title":"PCF control - Generate Shields.IO Badges in the PowerPlatform"},{"content":"In the latest release of the LookupDropdown PCF control for Dataverse, I have added a new feature that adds support for related record filtering, hence the ability to filter the values of a dropdown in real-time based on the value of another lookup field. When rendered, this can produce nice cascading effect as seen below.\nIn this post I will show how to configure the PCF control for this scenario and dissert on what\u0026rsquo;s happening under the hood to make the magic happen.\nTo get more context on the control, have a look at my initial post on the LookupDropdown PCF and be sure to install the latest version ( v1.0.0.3) to leverage this new feature.\n🚨 UPDATE 2022-03-10 : please use v1.0.0.4 or above of the control, a bug 🐛 was found for the filtering in v1.0.03\nBetter UX with a Lookup Dropdown PCF Control https://github.com/drivardxrm/LookupDropdown.PCF/releases/latest Lookup Dropdown PCF | PCF Gallery Use case To illustrate the feature, let\u0026rsquo;s pretend that we run a SpaceFlight scheduling service 🚀. As seen below, we have a data model that consists of Space Agencies and their corresponding fleet of Space Ships.\nNow in our SpaceFlight scheduling form, we want to exposes 2 lookups and we want to filter the values exposed in the SpaceShip lookup depending on the selected Agency.\nStep #1 : Configure Record Filtering At this point, I assume that you have already setup the Lookup Dropdown PCF control on the 2 lookup fields as described in my initial post. The next steps are only required when you want to implement dependent lookup filtering on top of that.\nThe platform natively exposesmechanism to provide additional filtering options on a lookup field. Therefore, the PCF control will make use this information at run-time to implement proper filtering.\nYou will need to open your form in classic mode as the Modern form editor doesn\u0026rsquo;t expose Record filtering yet. Now click on the Lookup field that you want to filter, in our case the SpaceShip field.\nIn the Display tab of the lookup field properties, go to the Related Records Filtering section. Enable the \u0026rsquo; Only show records where\u0026rsquo; checkbox and select the appropriate filters, Space Agency in our case.\nUsing the normal lookup ( without any PCF control), this would render something like this on the form, showing that the filters are well configured.\nStep #2 : Configure the PCF Control There\u0026rsquo;s new optional parameter defined in the LookupDropdown PCF manifest called \u0026rsquo; Dependent Lookup Field\u0026rsquo; that needs to be configured. The parameter expects a reference to a Lookup.Simple field.\nJust go to the Controls tab of the field properties, select the Dependent Lookup Field and from the list select the same lookup attribute that is part of the Related Records Filtering that was set in step #1. ( here the space agency field)\nWith a Dependent Lookup Field being configured, the control is able to resolve the Id (guid) of the dependent attribute at runtime. Most importantly, it also ensures that the instance of the PCF control gets notified 📣 whenever the dependent value gets updated. This makes certain that the filtered list gets updated as well.\nThats all there is, the SpaceShip dropdown will now expose the fleet of the selected agency and the values will automatically be updated when needed, as seen below.\nUnder the hood For developers, I think its interesting to show how the different pieces are used inside the code. Please refer to the code repo to get the latest implementation.\nI gave a good explanation in my first post on the way the control generates the query needed to render the control properly. Heres a recap :\nGet the default view id using the getViewId() method exposed by the lookupfield parameter Get the default view fetchxml by retrieving the record from the savedquery table Modify the fetch xml by adding the fields needed by the control (ex. entity image) Execute the modified fetchxml to retrieve the values needed by the control instance Without dependent lookup filtering, the query the SpaceShip lookup in the example would look something like this\n\u0026lt;fetch version=\u0026#34;1.0\u0026#34; mapping=\u0026#34;logical\u0026#34;\u0026gt; \u0026lt;entity name=\u0026#34;driv_spaceship\u0026#34;\u0026gt; \u0026lt;filter type=\u0026#34;and\u0026#34;\u0026gt; \u0026lt;condition attribute=\u0026#34;statecode\u0026#34; operator=\u0026#34;eq\u0026#34; value=\u0026#34;0\u0026#34;/\u0026gt; \u0026lt;/filter\u0026gt; \u0026lt;attribute name=\u0026#34;driv_spaceshipid\u0026#34;/\u0026gt; \u0026lt;attribute name=\u0026#34;driv_name\u0026#34;/\u0026gt; \u0026lt;attribute name=\u0026#34;driv_image\u0026#34;/\u0026gt; \u0026lt;/entity\u0026gt; \u0026lt;/fetch\u0026gt; Now, when dependent lookup filtering is enabled on the control, we need to add a link-entity node to the fetchxml and refetch the data everytime the valueof the dependent changes. In green you see the dynamic values that we can get using info from the configuration steps explained earlier.\n\u0026lt;fetch version=\u0026#34;1.0\u0026#34; mapping=\u0026#34;logical\u0026#34;\u0026gt; \u0026lt;entity name=\u0026#34;driv_spaceship\u0026#34;\u0026gt; \u0026lt;filter type=\u0026#34;and\u0026#34;\u0026gt; \u0026lt;condition attribute=\u0026#34;statecode\u0026#34; operator=\u0026#34;eq\u0026#34; value=\u0026#34;0\u0026#34;/\u0026gt; \u0026lt;/filter\u0026gt; \u0026lt;attribute name=\u0026#34;driv_spaceshipid\u0026#34;/\u0026gt; \u0026lt;attribute name=\u0026#34;driv_name\u0026#34;/\u0026gt; \u0026lt;attribute name=\u0026#34;driv_image\u0026#34;/\u0026gt; \u0026lt;link-entity name=\u0026#34;driv_spaceagency\u0026#34; from=\u0026#34;driv_spaceagencyid\u0026#34; to=\u0026#34;driv_spaceagency\u0026#34; alias=\u0026#34;dependent\u0026#34;\u0026gt; \u0026lt;filter type=\u0026#34;and\u0026#34;\u0026gt; \u0026lt;condition attribute=\u0026#34;driv_spaceagencyid\u0026#34; operator=\u0026#34;eq\u0026#34; uitype=\u0026#34;driv_spaceagency\u0026#34; value=\u0026#34;9ad553fc-a75f-ec11-8f8e-000d3a84327b\u0026#34; /\u0026gt; \u0026lt;/filter\u0026gt; \u0026lt;/link-entity\u0026gt; \u0026lt;/entity\u0026gt; \u0026lt;/fetch\u0026gt; The values needed to build the link-entity node can be obtained by extracting the dependentAttributeName and dependentAttributeType attributes of the bound lookupfield properties. These values will be filled accordingly as a result of Step#1.\n👉For a deep-dive the properties exposed by a lookup field have a look at this great post by Diana Birkelbach\nLookup PCF – let’s dive deeper – Dianamics PCF Lady (wordpress.com)\nAs for the ID (guid) of the dependent lookup, it can be found by looking at the dependentlookupfield properties. This value is defined as a result of Step#2.\nTakeaway I think that the Related Record filtering adds nice touch to the LookupDropdown PCF control. It certainly enables more use case to be ported and rendered by the control while providing a great user experience.\nIf you find any issues or have any comments/ideas for the controls please drop me a line in the discussion section of the repo.\nImage by jimmysobandith from Pixabay\n","date":"2022-02-09T02:37:48Z","image":"/related-record-filtering-with-the-lookup-dropdown-pcf/cars-g66f4a8d9d_1280_2.jpg","permalink":"/related-record-filtering-with-the-lookup-dropdown-pcf/","title":"Related Record Filtering with the Lookup Dropdown PCF"},{"content":"Environment variables in Dataverse are a powerful vehicule to develop portable customizations between different environment. Recently, a new Secret Data Type was introduced that enables the use of secrets stored in Azure Key Vaults 🔐 .\nThe integration between Dataverse and Azure Key Vault was long-awaited and I am really happy to see it materialize. It brings new kind of use cases and an additional security layer to protect sensitive information needed in platform customizations.\nIn this post, I will share my findings setting up the key vaults. And, while most of the documentation and videos out there are showing how to consume secret environment variables in PowerAutomate Flows, I will focus on their usage inside Dataverse Plugin code.\nAzure Key Vault setup The first step is to setup an Azure Key Vault to hold the secrets and give Dataverse environments the right to read the secrets stored in the vault.\nThe official documentation gives really good instructions on how to configure your key vaults so I will not repeat everything here. The main steps are :\nEnable Microsoft.PowerPlatform as a resource provider in your Azure subscription Create a Key Vault Give proper security role to the Dataverse application There are 2 permission model available in a Key Vault\nVault access policy Azure role-based access control (RBAC) The official documentation assumes that the permission model of the Key Vault is \u0026rsquo; Vault access policy\u0026rsquo; follow the instructions if that is your case.\nIf you use Role-based access control ( RBAC), you need to grant the Key Vault Secrets User role to the Dataverse application. Here\u0026rsquo;s how to do it in the Azure portal :\nHead to the Access control (IAM) blade and add a Role Assignment, and select Key Vault Secrets User.\nYou will be prompted to select the members. Type Dataverse in the search box and the Dataverse application service principal will be proposed. Select the Dataverse application and save.\nIn the Access control (IAM), you can now assess that the Dataverse application as proper access to ther Key Vault.\n🔔 Be aware that once you granted the read secrets permissions to the Dataverse application on a given Key Vault, all the Dataverse environments in your tenant are entitled to read secrets from this vault.\nSo as a best practice, its a good idea to have dedicated Key Vaults for Dataverse secrets usage only and don\u0026rsquo;t mix up secrets from other systems.\nIt\u0026rsquo;s also recommended to have seperate key vaults for all your different environments (ex. DEV, QA, PROD)\nCreate a Secret in the Key Vault For our example, we will create a secret with the following properties.\nName : TopSecret Value : \u0026lsquo;🔐 For Your Eyes 👀 Only 🔐\u0026rsquo; Given that your user has admin rights on the key vault secrets, head to the Secrets blade of the Key Vault and select Generate/Import.\nNotice that you can even set an an activation and/or expiration date. That\u0026rsquo;s a feature that is not possible using a normal Environment variable. This could be quite useful in certain scenarios.\nCreate a Secret Environment Variable We\u0026rsquo;re almost there. Now we need to create an Environment Variable of type Secret in Dataverse that will reference the secret that we just created in the key vault.\nSwitch to the PowerApps Maker portal and open a solution. Here, I created a solution called \u0026lsquo;KeyVault Test\u0026rsquo; and added an Environment Variable from the \u0026rsquo; New\u0026rsquo; option in the top menu.\nNote : The user who creates the environment variable must have read permission on the specific key vault. This provides an additional layer of security\nBe sure to choose the \u0026rsquo; Secret\u0026rsquo; data type and \u0026lsquo;Azure Key Vault\u0026rsquo; as the Secret Store. Then click on New Azure Key Vault secret reference where you\u0026rsquo;ll be asked to enter the info needed to resolve your key.\nAzure subscription Id Resource Group Name Azure Key Vault Name Secret Name : we will use \u0026lsquo;TopSecret\u0026rsquo; wich is the name of the secret defined earlier Once saved, the Environment Variable will only hold the reference to the secret in the key vault without storing its value inside your Dataverse environment. Think of it as a pointer.\nThe reference to the key vault secret will be stored in the EnvironmentVariableValue table using this form :\n/subscriptions/{subscriptionid}/resourceGroups/{resourcegroupname}/providers/Microsoft.KeyVault/vaults/{keyvaultname}/secrets/{secretname} Retrieve the Secret Value In order to retrieve the Environment variable secret value, the platform exposes an unbound Custom Api called RetrieveEnvironmentVariableSecretValue that can be called at runtime inside customizations.\nOne of the easiest way to test this API is to fire-up the XrmToolBox and open the Custom API Tester tool by Jonas Rapp.\nSelect the RetrieveEnvironmentVariableSecretValue custom API and set the name of the variable to fetch as the EnvironmentVariableName input. Execute the API and the secret value will be received in the EnvironmentVariableSecretValue output, as seen in the image below.\nSince the Custom API is adressable, it\u0026rsquo;s also possible to make a direct call to the Dataverse web API to retrieve the secret value.\nPOST =\u0026gt; https://{{baseurl}}/api/data/v9.2/RetrieveEnvironmentVariableSecretValue BODY : { \u0026#34;EnvironmentVariableName\u0026#34; : \u0026#34;{VariableName}\u0026#34; } Using Secrets in Plugin code Awesome, now let see how we can leverage the usage of a Secret Environment Variable in a Dataverse Plugin.\nIt\u0026rsquo;s only a matter of making a call to the RetrieveEnvironmentVariableSecretValue API inside the code of the plugin.\nHere\u0026rsquo;s an example using Late Bound coding style. You need to create an OrganizationRequest object and set the EnvironmentVariableName parameter. Upon execution of the request, the secret value will be found in the EnvironmentVariableSecretValue Results collection of the response.\nI personally prefer the Early Bound coding style for my plugin development. Early bound classes can be generated not only for Tables (Entities) but also for Custom Actions/API.\nMy weapon of choice for early bound classes generation is the spkl Task Runner by Scott Durow. Just add RetrieveEnvironmentVariableSecretValue in the \u0026quot; actions\u0026quot; section of the spkl.json configuration file.\nThis will produce specialized RetrieveEnvironmentVariableSecretValueRequest and RetrieveEnvironmentVariableSecretValueResponse that can be used instead of the generic OrganizationRequest used in the late bound example. Difference here is that there are no magic strings only concrete objects with properly typed properties.\nNow, when deployed and registered on Create of a contact record, eighter of the plugins showed above will produce the following. I\u0026rsquo;m just throwing an error with the secret value.\nI used the technique showed above to enhance my own Dataverse-CustomApis collection community project. GitHub - drivardxrm/Dataverse-CustomApis: Collection of Dataverse Custom Apis Collection of Dataverse Custom Apis. Contribute to drivardxrm/Dataverse-CustomApis development by creating an account on GitHub. github.com In this project I expose a Custom API called GetEnvironmentVariable. This API takes the name of an environmenmt variable as an Input and returns a bunch of information on the variable. Most importantly, it casts the value accordingly depending on the type (String, Boolean, Number and now \u0026hellip; 🎉 Secret).\nAs you can see below, when the GetEnvironmentVariable API is called with a variable Key of type Secret. The secret value is resolved in the ValueSecret output property.\nInstall the latest release of the solution if you want to try it.\nTakeaway I\u0026rsquo;m thrilled by the addition of the Secret data type for Dataverse Environment Variables and I see a lot of potential use cases in my current projects.\nThere are a lot of benefits to store secrets in Key vaults instead of Dataverse tables. Think about logging, monitoring, key rotation just to name a few.\nHere are some other great resources and use cases on the subject :\nEnvironment Variable Secrets - YouTube Access Azure Key Vault Secrets using Environment Variables. #CitizenCan E15 | 365.Training - YouTube Photo by George Becker from Pexels\n","date":"2022-01-25T05:21:28Z","image":"/azure-key-vault-secrets-in-dataverse/pexels-george-becker-333837.jpg","permalink":"/azure-key-vault-secrets-in-dataverse/","title":"Azure Key Vault Secrets in Dataverse"},{"content":"One of the most anticipated feature of the PowerApps Control Framework (PCF) last year was the Lookup datatype support. Hence the ability to bind a PCF control to a Lookup field in a Dataverse Model-Driven form to customize it\u0026rsquo;s behavior.\nThe feature was released last summer (see official post) and the first idea that came to my mind was to create a PCF control that renders a lookup field as a dropdown list instead of the of the out-of-the-box lookup selector.\nI also wanted to add some cool features like :\nDisplay the record image 📷 Customize the record display text Use the default view defined on the form to filter and order the dropdown values The lookup datatype being a totally different beast than simple data types ( like text or numbers), It proved to be trickier than I thought to develop a robust control and I got stuck for awhile. But, I took advantage of the holidays to put the finishing touches and I\u0026rsquo;m quite happy with the end result.\nThe control will turn the lookup selector\u0026hellip;\noob lookup selector into a dropdown list\u0026hellip;\nLookupDropdown PCF I will show how to setup the control and hightlight some of my findings in this post but you can download it straight up from my GitHub repo or find it exposed in the PCF Gallery .\n🚨 UPDATE 2022-01-20 : please use v1.0.0.2 or above of the control, a bug 🐛 was found in earlier versions\nAlso, If you want to dig deeper on the Lookup field functionality for the PCF Framework, I highly recommend the blog posts and videos from Diana Birkelbach and Andrew Butenko .\nA first look to the Lookup PCF – Dianamics PCF Lady (wordpress.com) Lookup PCF – let’s dive deeper – Dianamics PCF Lady (wordpress.com) You asked, I built - Showing lookup field as an Optionset using PCF - YouTube Use Case for a Lookup Dropdown Whenever you want to display a list of values to users, the recommended and easiest way is definitely to create a Choice column (optionset) in your table, define the values and expose them on the form. But, for many reasons, the use of an optionset is not always the best solution.\nSometimes, a selected value comes with additional data that shapes the underlying business logic. For example, each payment method in the example above could come with its own % fee and some calculation might depend on it. So by using a Payment Method table instead of a choice column, this is very easy to model and consume in your application logic.\nAlso, super-users of your application might want more control over the values of a selection displayed on a form (add, modify or delete) without having to ask the development team to push a new version of the app in production. Again, this is easily achievable using a table.\nThat being said, a lookup column displayed as a dropdown can provide a more intuitive and fluid UX than the lookup selector, especialy when there are few and consistent choices in the list.\nHow to Set-up the control After you install the LookupDropdown.PCF solution in your Dataverse environment, you will be able to bind the PCF control to any Lookup field exposed on a form.\nFirst, open your form in classic mode. Unfortunately (at the time of writing) PCF controls configuration are still not possible using the \u0026lsquo;modern\u0026rsquo; form editor 🤷‍♂️ .\nNow, when you configure a Lookup field, select the appropriate default view in the Display section. This view will be used by the PCF control to filter and order the values shown in the dropdown list.\nThen, head to the Controls section and select the LookupDropdown control\nAnd add the desired configurations\nLookup Field : name of the bound lookup field ( will be populated automatically) Custom Text : (optional) put column names between curly braces. leave blank to use the \u0026lsquo;Primary Name\u0026rsquo; column. more on this later Custom Select Text : (optional) custom text for select text (empty), default = \u0026lsquo;Select\u0026rsquo; Show Record Image : select \u0026rsquo;true\u0026rsquo; to show record images beside the display text Show Open Record Button : select \u0026rsquo;true\u0026rsquo; to show a button that will open the selected record Edit form Thats all there is! You now have a way to render lookup fields as dropdown lists as seen in action below.\nNow, let\u0026rsquo;s look more closely to some features of the control.\n1️⃣ Show Record image 📷 Without a doubt, my favorite feature ✨ is the ability to show the record image ( Primary Image field) beside the record display text. I think that when used correctly, it adds meaning to the UI and provides a pleasant experience to end users. Here\u0026rsquo;s how to setup your tables to take advantage of it.\nWhile some common tables like Account and Contact have a Primary Image column enabled by default, it\u0026rsquo;s quite easy to define on any table. Just create a column of type Image and check the Primary Image box.\nOnce defined, the Primary Image attribute of a table is discoverable using a metadata query. This is used under the hood by the control to access image data.\nTo set an image on a specific record, open it in edit mode and click on the upper left corner of the form. This will open a dialog where you can upload the record specific image.\nOnce saved, the image data ( in base 64 format) can be retrieved from a web api call. This data will be used by the control when the \u0026rsquo; Show Image\u0026rsquo; property is set to true to display record images.\nWith the image data in base 64, you can create an adressable url that can be used within the PCF control code using this notation : url = \u0026lsquo;data:image/jpeg;base64,{base64image}\u0026rsquo;. For example in a FluentUI ImageIcon. ( see the code repo for the real implementation)\n2️⃣ Customize display text Another nice feature of the control is the ability to customize the display text of each record.\nBy default, the Primary Name column will be shown but this can be extended by suppling a value in the Custom Text property of the PCF control.\nProvide the desired field(s) logical name(s) between curly braces {} and the record specific value will be replaced at run time. Any text that is not between culy braces will stand as a placeholder.\nPiggy-backing on the previous example, setting a custom text like this :\n{driv_name} (fee: {driv_fee}%)\nWill render the dropdown with these custom text values.\nThis can prove quite useful, especialy when the Primary Name column is not what you want to show up to users.\n3️⃣ Fetch Default view records One of the major roadblock I encountered was to find a way to dynamically fetch the records using the default view that is configured natively on the Lookup field properties of the form where the PCF control is used.\nThis ensures that the values of the dropdown list are filtered and ordered as intended by the developer of the application.\nAfter numerous design tentatives and headaches, I finally found a solution that fitted my need.\nRetrieve the fetchxml of the default view There is a property of a lookup field parameter in the ComponentFramework.Context called getViewId, this will give the GUID of the default view\nUsing the viewid, its now easy to retrieve the view fetchxml using a retrieveRecord from the savedquery table. Note that I also convert the fetchxml string to a Xml Document object using a DOMParser for further usage.\nNote. this code as been altered for simplicity, look at the code repo for the real implementation\nManipulate the fetchxml Now that we have the default view fetchxml, the goal is to modify the xml to include the fields (attributes) needed for the rendering of the dropdown list.\nFor example, we will want to add the Primary Image and other attributes required by the Custom Text property.\nExecute a WebApi request with the altered fetchxml We now have everything in hand to make a RetrieveMultiple web api call on the main table using the modified fetchxml.\nthis.context.webAPI.retrieveMultipleRecords(this.lookupentityname, `?fetchXml=${fetchxmlstring}`) A getLookupRecords method could look something like this\nTakeaway The addition of the Lookup datatype support in the PCF framework brings up a lot of new possibilities and I really learned a lot while developing the Lookup Dropdown control.\nI think that the control fills a gap and I will certainly use it in my current projects to enhance the user experience. I\u0026rsquo;m curious to see how it will be used by others and dont hesitate to drop me a line in the project discussion if you have any comments, issues or improvement ideas.\nLinks Lookup Dropdown PCF A control that renders a Lookup field as a Dropdown Honours the filtering and ordering of the default view selected on the field properties of the form Optional: Show record image (Primary Image) Optional: Customize record display text. Default = Primary Name column pcf.gallery GitHub - drivardxrm/LookupDropdown.PCF: PCF Control that renders a lookup field as a dropdown PCF Control that renders a lookup field as a dropdown - GitHub - drivardxrm/LookupDropdown.PCF: PCF Control that renders a lookup field as a dropdown github.com A first look to the Lookup PCF According to the docs, we can start using the PCF Lookup.Simple. But there is a small bundling issue. After fixing that, the customizing possibilities lets me dream about amazing features. Dream wi… dianabirkelbach.wordpress.com Lookup PCF – let’s dive deeper Lookup PCF …the second.. this time for real! I had a look how a Lookup PCF works, what I can do with it and what not, how to detect the settings made by the maker, and more…. Even if th… dianabirkelbach.wordpress.com Photo by Daniel Kux from Pexels\n","date":"2022-01-06T02:35:50Z","image":"/better-ux-with-a-lookup-dropdown-pcf-control/pexels-daniel-kux-932320-1.jpg","permalink":"/better-ux-with-a-lookup-dropdown-pcf-control/","title":"Better UX with a Lookup Dropdown PCF Control"},{"content":"In my last post I explained how to enable custom webpack configurations in a PowerApps Control Framework project. I also showed how to generate the source-map file of the generated PCF bundle.\nPCF controls – Custom Webpack configurations\nTo continue on this track and push things a little further, I want to explore how to enhance the PCF development experience with the use of webpack plugins that can be referenced in the custom configuration file.\nAltough there are tons of webpack plugins available (see links at the bottom) I will focus on 4 plugins that will help :\n⌚ Measure up the build time 👁️ Get insight on the bundle composition and size 🏃‍♂️ Build your project faster 🧹 Cleanup the stage between each build. What are Webpack Plugins Before we dive deeper on the matter, remember that webpack is the bundler that is used by the PCF framework to create the deployable artifacts (bundle.js) out of the source code and other dependencies like referenced npm packages.\nSee the source image By definition, a webpack plugin is a piece of code that as access and can interact with the whole webpack compilation events and objects.\nAs stated in the official Webpack documention, Plugins are the backbone of webpack and most of webpack itself is architectured around plugins.\nWebpack Plugin in a PCF project To make use of webpack plugins in a PCF project, just import and reference them in a custom configuration file webpack.config.js (see my previous post for more context)\nAt this point, I assume that you have enabled the pcfAllowCustomWebpack feature flag by adding a featureconfig.json file at the root of your projet\nTo add plugins to your configuration, just add a \u0026rsquo; plugin\u0026rsquo; node inside the module.exports of the webpack.config.js at the root of the project. This is where the plugins code will be added in the next sections\nAt build time, this file gets merged with the out of the box webpack configuration of the PCF framework (located at node_modules\\pcf-scripts\\webpackConfig.js)\n⌚ Speed Measure Webpack Plugin https://github.com/stephencookdev/speed-measure-webpack-plugin\nThe first plugin I want to show is Speed Measure Webpack Plugin. By enabling this plugin, you\u0026rsquo;ll be able to get valuable insight on the time it takes for every step of the build process to complete. This will help later on to demonstrate the usage of other plugins.\nInstall the npm package and add the following code to the webpack.config.js file\nnpm install --save-dev speed-measure-webpack-plugin Notice that this plugin is a bit different from the others as you don\u0026rsquo;t put the code inside the plugin node but instead you are wrapping all the content of the module.exports with the plugin instance ( smp.wrap())\nNow when you build the project, there will be a new section in the output log where you can see the statistics of each loaders and plugin involved in the bundling of your component. Pretty slick 🤓 eh.\n👁️ Webpack Vizualizer https://github.com/chrisbateman/webpack-visualizer The Webpack Visualizer plugin can help get a clear picture of the bundle composition.\nThis plugin will generate a webpage out of the statistics gathered by the webpack compilation process. You\u0026rsquo;ll be able to see all the packages referenced in the project and their respective size. This can be very useful to assess if a specific library is bloating the bundle or to spot duplicated libraries.\nJust install the npm package and add the following code to the webpack.config.js file\nnpm install --save-dev webpack-visualizer-plugin When the project is built, notice a new file called stats.html in the build folder.\nOpen the file and a nice interactive chart that expresses the packages sizes contained in the bundle will be shown. For example, here FluentUI accounts for 49% of my control composition.\nAs a side note, you might want to comment out this plugin code before building your deployable solution as it will put the stats.html file in your solution .zip file ( more on that later). You can also change the output folder in the options of the plugin, just look at the documentation.\nThere are other very intersting plugins for bundle statistics and visualization like webpack-bundle-analyzer I encourage you to have look and find the one that best suits your needs.\n🏃‍♂️ Hard Source Webpack Plugin https://github.com/mzgoddard/hard-source-webpack-plugin This one is very interesting as it will cache some info about the build process and significally speedup the build time.\nAgain, install the npm package and insert the plugin code in your webpack.config.js file\nnpm install --save-dev hard-source-webpack-plugin Here\u0026rsquo;s where it gets interesting. Once this plugin is enabled, the first time you build the project you will see no difference in build time, but some of the heavy lifting stuff will be cached on disk.\nIf you look at the output below, you see that a cache is being created. ( We can see the SMP plugin shown earlier in action that measures the processing time of the hard source plugin)\nNow if you rebuild the project without doing any changes you\u0026rsquo;ll see that the build time dropped drastically because the data on cache was used.\nI know this doesn\u0026rsquo;t prove nothing since there where no changes to the source code, so here I made changes to 3 typescript files in the project and rebuilt. here\u0026rsquo;s the results\nYou can appreciate that the build time is now more than half of the initial build time (3.76 sec vs 8.86). I agree that this can be insignificant for small projects, but it can be really useful for big PCF projects.\n🧹 Clean Webpack Plugin https://github.com/johnagan/clean-webpack-plugin Last but not the least, Clean Weppack Plugin will help to clean up the output folder at every succesful build.\nBy default, the out folder doesn\u0026rsquo;t get sweeped between each build, so if like me you experiment a lot with plugins and source-map files, you can end up with unwanted files in the output directory.\nNow even if for instance, you comment out the lines in your webpack configuration that generates extra files (ex. source-map, stats.html), you can see below that the build started at 10:32 PM only overwrited the files generated by the current build and left the 3 unwanted files in the directory.\nEven worse 😒, these unwanted files will be included in the generated solution packages and deployed into your Dataverse Environments, as you can see in the extracted zip file below\nTo rectify this situation, just install the npm package and insert the plugin code in your webpack.config.js file\nnpm install --save-dev clean-webpack-plugin From now on the build folder will be wiped-out at evey build. As you can see below, the next build of the same project using CleanWebpackPlugin will yield only the desired files in the output directory.\nConclusion If we mix all these together, my custom webpack configuration would look something like this. It\u0026rsquo;s very easy to comment lines as needed when functionalities are not needed (ex. source-map and Visualizer)\nHopefully this will give you some ideas on how to improve your PCF development experience. Above all, I really feel like I have just scratch the surface here.\nHere\u0026rsquo;s some interesting ressources to find more plugins and use cases.\nhttps://webpack.js.org/plugins/ https://awesomeopensource.com/projects/webpack-plugin ","date":"2021-11-16T04:58:31Z","image":"/pcf-controls-useful-webpack-plugins/AdobeStock_245503753.jpeg","permalink":"/pcf-controls-useful-webpack-plugins/","title":"PCF Controls - Useful Webpack Plugins"},{"content":"When developing Power Platform PCF controls, at build-time, Webpack is invoked to bundle the code and dependencies into deployable assets.\nWhile the out-of-the-box configurations are suitable for most of the basic PCF control needs, sometimes, you need to throw your own custom instructions in the game. This is what we are going to cover in this post.\nWebpack and PCF I will not spend too much time on the fundamentals of Webpack, there are tons of great blog post that deep-dives on the matter. But I think its important to understand what Webpack is and how it works in PCF control development.\nWebpack is essentially a module bundler that will take all your code and dependencies (typescript files, npm packages, images, css, ressources, \u0026hellip;) and bundle them in static assets. In PCF terms this is the process that produces the deployable bits out of your source code.\nThe PCF npm package ( pcf-scripts) provides an out of the box Webpack configuration that you can find here in your project ( node_modules\\pcf-scripts\\webpackConfig.js ). Whenever you build your project, take a look at the out/ folder. You can appreciate that all your code and assets are bundled up in a single bundle.js file.\nNow, let\u0026rsquo;s see how we can add our own configurations and instruction to spice things up a little bit.\nUse Case : Generate source map file There are many reasons why you would want to mingle with the Webpack configuration. But for simplicity, let\u0026rsquo;s use a very easy ( yet very usefull) example which is to generate a source map file that will greatly help the debugging of your your PCF controls.\n🗺️ Source maps enables you to debug in your actual typescript files rather than the generated javascript.\n👉 see this excellent post from Ivan Ficko for more context on source maps : Debugging PCF in Typescript - Dynamics Ninja\nOne of the step requires to modify the default webpack config of your control and add one line of code (see line 47 below). As stated earlier the out-of-the-box configurations are buried deep in the node_modules folder ( node_modules\\pcf-scripts\\webpackConfig.js)\nThe problem with this approach is that you should never ( in theory) modify any files directly in the node_modules directory as you will loose your edits if you restore the npm packages. Also, keep in mind that the node_modules folder isn\u0026rsquo;t normaly archived in source control, so any modification you make to a file will be lost when cloning the repo .\nTurns out that there is a much cleaner (and ALM friendly) way to customize the webpack configurations and this is what I will document in this post.\n1️⃣ Setting the stage I want to point out a file that is located in the node_modules/pcf-scripts folder alled constants.js\nNotice these 2 constants as their values will be helpful later on\nFEATURE_CONFIG_FILE_NAME = \u0026lsquo;featureconfig.json\u0026rsquo; WEBPACK_CUSTOMIZATION_FILE_NAME = \u0026lsquo;webpack.config.js\u0026rsquo; 2️⃣ Activate pcfAllowCustomWebpack feature The next step is to activate a feature flag on your PCF control project. Once again we need to navigate in the node_modules/pcf-script folder and find a file called featureflags.json. There, you can locate the pcfAllowCustomWebpack switch and assess that it is turned off.\nYou could turn on the feature right here in this file and re-build, but that is exactly what we are trying to avoid. Remember that the goal 🎯 of our operation is to leave anything under the node_modules folder untouched.\nThis is where the FEATURE_CONFIG_FILE_NAME (featureconfig.json) value we saw in the constants.js file will come in handy.\nWhat this says is that you can override the default featureflags of your PCF control project, by supplying your own in a file called featureconfig.json at the root of your project. In this file, simply provide the list of feature flags that you want to override. In our case, the pcfAllowCustomWebpack flag is turned on ✅.\nThats it, from now on you will be able to provide custom Webpack configurations to change the bundling behavior of your PCF control.\n3️⃣ Custom Webpack configurations Now that the pcfAllowCustomWebpack is activated, you need to provide the additional custom configurations that will be used by Webpack to bundle the control.\nThis time, we will make use of the WEBPACK_CUSTOMIZATION_FILE_NAME( webpack.config.js) constant retrieved earlier. This tells us to create a file named webpack.config.js in the project root where we can put any custom webpack instruction that we want to be executed on top of the out-of-the box instructions.\nIn our case, to generate the source-map file, its super simple, just add one line of code inside the exports of the file. The instruction will be merged with the OOB configuration at build-time.\n4️⃣ Build your project One last thing, as stated in Ivan\u0026rsquo;s post, don\u0026rsquo;t forget to add the sourceMap property in the compilerOptions of the tsconfig.json\nAnd now, whenever the project is built, you can see that the custom configurations are executed and that the source map file bundle.js.map is present in the /out folder.\nYou just have succesfully injected and executed a custom webpack configuration on a PCF control project 🎉.\nConclusion Just to recap. It is quite straitforward to add your own custom webpack configuration to a PCF control project in a consise and ALM friendly way.\nAdd a featureconfig.json file at the root of your project\nEnable the pcfAllowCustomWebpack feature flag\nAdd a webpack.config.js file at the root of your project\nAdd your custom Webpack configurations that will be merged with the OOB, like this example\nI showed a very simple example for the sake of the blog post but this opens the door to a lot of interesting stuff, I\u0026rsquo;m curious to see what other people will come up with.\nPhoto by Karolina Grabowska from Pexels\n","date":"2021-10-20T02:06:29Z","image":"/pcf-controls-custom-webpack-configurations/pexels-karolina-grabowska-4498124.jpg","permalink":"/pcf-controls-custom-webpack-configurations/","title":"PCF controls - Custom Webpack configurations"},{"content":"In-App notifications for Model-Driven apps ( still in preview at the time of writing) exposes a central notification hub in Power Platform model-driven apps and the notifications model provides a fantastic vehicle to deliver contextual and user-specific information.\nIn this blog post, I will continue my exploration of In-App notifications and show how we can spice things up a little bit and create visually rich and appealing 💎 notifications by embedding images inside the content.\nYou can refer to my 2 earlier posts for more context.\nEnable Model-Driven In-App Notifications with Power Automate Send Model-Driven In-App Notifications with Power Automate The use case To get a supply of stunning images ✨ there are no better use case than to display the famous NASA\u0026rsquo;s Astronomy Picture of the day (APOD) inside our notifications.\nAlso, while the Microsoft official documentation examples are using Dataverse Web API calls to create the notifications, I will use Power Automate to show how easy it is to create awesome notifications in a low-code manner.\nThe end result looks like this and contains the following.\nA custom Icon A clickable image in the body An Action at the bottom rendered as a clickable image Display images in notifications Before we go too far in the final solution, let\u0026rsquo;s try to understand the different parts of a notification and how they are rendered.\nThe main parts of a notification are :\nThe Microsoft official documentation shows how to inject rich content like hyperlinks by using the \u0026rsquo; data\u0026rsquo; field of the notification record. If you look closely at the example below, you will notice that it uses Markdown notation to render the hyperlinks. This is where it gets interesting.\nMarkdown links and image syntax While the documentation only shows how to render hyperlinks inside notifications, the markdown notation also offers methods to render images and clickable images as well.\nref : https://guides.github.com/features/mastering-markdown/ Hyperlink [Link Text](Url) Image ![Alt text](ImageUrl) Clickable image [![Alt text](ImageUrl)](Url) That way if you render a notification with this \u0026rsquo; Data\u0026rsquo; field\nYour notification will look like this\nLimitation The major limitation I faced with embedding images using Markdown notation is that it seems impossible to resize the image.\nMeaning that when the image you want to display is greater than 250 px in width the image will not render inside the available space and will be cropped 😡. Diana Birkelback came to the same conclusion in her blog post on in-app notifications.\nOvercome Image sizing limitation By doing some research I found a nifty solution using a service called FileStack that makes it possible to resize an image on-the-fly by using URL parameters.\nHow to Automatically Resize, Fit, and Align Any Image Using Only URL Parameters | Filestack Blog See how to automatically resize, fit, and align any image stored on an object store like AWS s3, Azure Blog Storage, or Google Cloud storage. blog.filestack.com That way once you have the URL of a large image that you want to display inside a notification, for example\nhttps://apod.nasa.gov/apod/image/2109/SunSpotHill_Coy_960.jpg\nYou can resize the image to a 250 px width in real-time using a simple URL.\nhttps://cdn.filestackcontent.com/****\u0026lt;API_KEY\u0026gt;/ resize=width:250/https://apod.nasa.gov/apod/image/2109/SunSpotHill_Coy_960.jpg\nVoilà! Now when embedded in a notification, the image is not overflowing anymore. 👌\nTo get access to Filestack you need to sign-up for an account. There is a free tier that gives you a 1000 transformations per month and its not that expensive if you really need to beef up the API calls. There is also a ton of other services available, I encourage you to have a look, it\u0026rsquo;s awesome.\nFilestack - The Best File Uploader \u0026amp; Upload API How to Automatically Resize, Fit, and Align Any Image Using Only URL Parameters | Filestack Blog NASA Picture of the Day notification Flow Now that we have all the parts needed, let\u0026rsquo;s build a Power Automate Flow that will create a new notification with the NASA Picture of the Day everyday at midnight. The outline of the Flow looks like this.\nand here are some of the important parts explained.\n1️⃣ Trigger - Everyday at Midnight The trigger of the flow is a simple recurrence trigger set at midnight everyday\n2️⃣ Get NASA Picture of the Day To be able to call the Picture of the day service, you will need to get an API key from the NASA website. Its totally free and there are plenty of other amazing API. Get yours now!\nI will show you 2 methods query the NASA APOD API.\nHTTP Call - The HARD way With the API Key you can now query the picture of the day API at this address:\nhttps://api.nasa.gov/planetary/apod?api_key={YOUR_APIKEY} To call this endpoint in Power Automate you can use an HTTP action\nHere is an example of the result\nYou would then need to add a Parse JSON step to extract the values from the response and use them in your Flow. Not super complicated but there is a better way.\nCustom connector - The EASY way To make it easier and more portable, I created a NASA APOD Custom connector that you can install in your environments. Follow the instructions from the Custom Connector Gallery or on the GitHub repo for installation and usage.\nNASA Pic of the day Custom connector that retrieves images URL and associated metadata from the famous NASA - Astronomy Picture of the Day (APOD). Free API key required @ https://api.nasa.gov/ 🚀🌌 www.connector.gallery GitHub - drivardxrm/NASA_APOD.Custom_Connector: NASA Astronomy Picture of the Day - PowerPlatform Custom Connector NASA Astronomy Picture of the Day - PowerPlatform Custom Connector - GitHub - drivardxrm/NASA_APOD.Custom_Connector: NASA Astronomy Picture of the Day - PowerPlatform Custom Connector github.com Once installed you can Insert a Get NASA Picture of the Day action in your Flow.\nThe first time you will have to create a connection and enter your API key. Note that this method is much more convenient and secure than the HTTP call since the API Key is stored in the connection and is not revealed.\nnasa_apod_create2 You can optionally enter a date or leave it blank to retrieve today\u0026rsquo;s image\nimage No need to parse the JSON response here, all the output parameters are ready to use by the downstream steps of the Flow.\n3️⃣ Conditional stuff There are 2 types of resource that can be retrieved from the API ( image and video), so depending on the \u0026rsquo; media_type\u0026rsquo; value of the response I set some variables for the Image Url and the Action to display at the bottom of the notification\nNotice the markdown image notation in the \u0026rsquo; title\u0026rsquo; pf the srtAction variable, this is how we can render an image instead of plain text in the actions section at the bottom of the notification.\n4️⃣ Resize the image This is where we use the Filestack magic 🧙 described earlier and set the URL to resize our image to 250 px wide.\n5️⃣ Create Notification record We now have all the pieces to build the notification. So we can drop an Add a new Row action from the Dataverse connector.\nChoose the Notifications table ( appnotification) and set the appropriate fields.\nSet the IconType to Custom inject a JSON contruct in the Data field that contains iconUrl, body and actions nodes. Don\u0026rsquo;t forget to pass the resized image URL in the markdown. Here is an example of the final JSON injected in the Data field:\nAnd that\u0026rsquo;s all there is! Turn on the Flow and from now on you will receive stunning and inspirational images on a daily basis. What a great way to start your day 😎.\nHere are some example:\nConclusion I am really happy with the outcome of this (space) exploration, I think it clearly shows the potential for creating visually attractive in-app notifications that end-users will crave for.\nAlso, I really had a blast 🚀 showcasing the NASA Astronomy Picture of the Day and developing the custom connector. To be frank Business apps are fine, but nothing beats Science 🤓.\n","date":"2021-09-23T03:38:29Z","image":"/embed-images-in-model-driven-in-app-notifications/maligne_lake.jpg","permalink":"/embed-images-in-model-driven-in-app-notifications/","title":"Embed Images in Model-Driven In-App Notifications"},{"content":"I n-App notifications for PowerPlatform Model-Driven apps are now available in preview. The feature provides a central notification hub in the app and the notifications provides a fantastic vehicle to deliver contextual and user-specific information to end users.\nWhile my last post showed how to enable notifications in model-driven apps, let\u0026rsquo;s see what the real deal is and start creating simple notifications.\nAs a use case, we will create a Power Automate flow that will notify users whenever a new article is posted on the official PowerApps blog (https://powerapps.microsoft.com/en-us/blog). Something like this.\nThe official documentation only shows examples using JavaScript and Dataverse Web API calls to create notifications. It\u0026rsquo;s good for developers but it might be a bit cryptic for other app makers. That\u0026rsquo;s why I want to use Power Automate to illustrate how easy it is for anyone to start using in-app notifications.\nPowerApps Blog Notification Flow Trigger - RSS feed As a trigger for the Flow, we will use the RSS connector \u0026rsquo; When a feed item is published'.\nSet the URL to the Blog\u0026rsquo;s RSS feed (https://powerapps.microsoft.com/en-us/blog/feed/) and the trigger property to PublishDate. This ensures that our Flow will trigger every time a new article is published on the site\nHere\u0026rsquo;s an example of the output of the RSS feed. Notice that for each item that are published we can extract the URL and the title. These values will be used later on.\nCreate Notification Record To create a notification, we simply need to Add a new row in the Notifications Table ( appnotification) using the Dataverse Connector.\nJust select Notifications in Table name and fill in the required fields to build the notification.\nThere is a couple of thing to notice here\n1️⃣ Inject the Feed title from the RSS trigger in the Body of the record\n2️⃣ In the Data field, a JSON construct is used to add an Action at the bottom of the notification. This is where the Primary feed link received from the RSS trigger will be injected. ( For more example of what you can do with the Data field, see the official doc)\n{ \u0026#34;actions\u0026#34;: [ { \u0026#34;title\u0026#34;: \u0026#34;View Post\u0026#34;, \u0026#34;data\u0026#34;: { \u0026#34;url\u0026#34;: \u0026#34;{{Primary feed link}}\u0026#34; } } ] } 3️⃣ Set the Owner of the notification.\n/systemusers({{GUID of USER}}) The Ownership of a notification record is the main driver of the in-app notification model. The owner of a notification is the user that will see and act upon the notification.\nFor this example I\u0026rsquo;m sending the notification to myself. However, in a real-life scenario you probably would have to retrieve a collection of users, loop over it and to create a new notification record owned by each users that needs to be notified.\n⌚ Wait for an article to be published Now, when the Flow is turned on, you will receive a notification each time new blog post is published. Never miss out again on this precious info, Isn\u0026rsquo;t it great ;)\nTake away This post shows how easy it is to create simple notifications using Power Automate flows in a way that is accessible to any app makers without any coding required.\nYou can download the flow I demoed here:\nNote: The Flow export file is no longer available for download.\nIn my next article, I will show how we can spice thing up a little bit and start embedding images to create kick-ass notifications.\nPhoto by grunge texture from Pexels\n","date":"2021-09-03T17:15:43Z","image":"/send-model-driven-in-app-notifications-with-power-automate/pexels-grunge-texture-2610378.jpg","permalink":"/send-model-driven-in-app-notifications-with-power-automate/","title":"Send Model-Driven In-App Notifications with Power Automate"},{"content":"In-App notifications for PowerPlatform model-driven apps has been released in public preview ( see official Microsoft blog post below). I am particularly excited about this new feature as it opens up very interesting scenarios that can have a significant impact on the user experience.\nApp notification with single action Announcing public preview for in-app notifications in model-driven apps With this public preview, notifications can be send to users within the model-driven app and are displayed using a notification center and notification toasts. powerapps.microsoft.com Before you can start flooding your users with all those cool notifications, since its a preview, the very first action to take is to enable the feature at the app-level.\nIt is not possible to enable the feature in the user interface of the Maker Portal. Therefore we need to rely on some coding magic to make things happen. In this case, the official documentation suggest sending a JavaScript command using the browser console.\nKeep in mind that the feature will most probably be enabled by default in the future and we won\u0026rsquo;t have to execute the command at all.\nWhat this code does is simply calling an out-of-the-box action called SaveSettingValue, and setting a parameter called AllowNotificationsEarlyAccess to true.\nSaveSettingValue Action (Microsoft.Dynamics.CRM) Creates or updates app/organization level override. docs.microsoft.com Not very complicated but also not very citizen-friendly either 🤷.\nEnable In-App notifications with a Flow Let\u0026rsquo;s see how we can use a very simple Power Automate Flow to achieve the same result. That way, we can have a centralized and generic way to enable and disable in-app notifications in any model-driven app of an environment.\n1️⃣ Setup the Trigger For the example, I will make use of the Manual Trigger for the Flow.\nSince I want the Flow to be generic and reusable, there will be 2 input values that we will expect to receive from the caller of the Flow.\nAppUniqueName(string) : This is the uniquename of your model-driven app AllowNotification(yes/no) : switch to enable ✔️ or disable ❌ the feature 2️⃣ Call SetSettingValue Action To call this action we will use the Perform Unbound Action step of the Dataverse connector.\nChoose the SaveSettingValue action from the dropdown list and map the AppUniqueName and Value parameters to the corresponding Inputs received from the trigger. The SettingName can be hardcoded to \u0026rsquo; AllowNotificationsEarlyAccess'.\n3️⃣ Run the Flow Now you just need to run your Flow to enable and/or disable the feature in any model-driven app deployed in your environment.\nJust pass the AppUniqueName and AllowNotification(true/false) input parameters.\nAfter you run the Flow, you will still need tomanually publish your app in the maker portal. Once published, log in to your app and you will see a 🔔 bell icon on the top ribbon. Clicking on this icon will pop-up the notification center of the logged-in user.\nThat\u0026rsquo;s all there is, you can now start to send In-App notifications to your users, see the link below for some examples.\nI will surely explore the possibilities in future blog post and I\u0026rsquo;m very curious to see how developers will make use of this shiny new toy ✨.\nYou can download and import the Flow I used in the example here :\nNote: The Flow export file is no longer available for download.\nSend in-app notifications within model-driven apps - Power Apps Learn how to configure notifications in model-driven apps by using a client API. docs.microsoft.com Photo by Chris Leipelt on Unsplash\n","date":"2021-08-29T20:45:22Z","image":"/enable-model-driven-in-app-notifications-with-power-automate/chris-leipelt-4UgUpo3YdKk-unsplash-1-1.jpg","permalink":"/enable-model-driven-in-app-notifications-with-power-automate/","title":"Enable Model-Driven In-App Notifications with Power Automate"},{"content":"I was invited for the 2nd time on the XrmToolCast podcast with Scott Durrow and Daryl Labar, this time to talk about the Custom Api Manager and Catalog Manager for XrmToolbox. XrmToolCast: Dataverse Catalog Manager With David Rivard We’ve challenged David Rivard in to create a tool for Managing Custom APIs . Not only did he accept that challenge and created the , he has also extended it to create another one, the , both of which we dive into on this show. David’s Info and other links: Blog: LinkedIn: … xrmtoolcast.libsyn.com ","date":"2021-07-21T02:25:41Z","image":"/xrmtoolcast-part-2/xrmtoolcast.jpg","permalink":"/xrmtoolcast-part-2/","title":"XrmToolCast – Part 2"},{"content":"Business Events ( still in preview at the time of writing) are opening up new paradigms for event-driven patterns in the Dataverse. (👉see Microsoft press release).\nEssentially, They rely on 2 new tables Catalog and Catalog Assignment that are surfaced in the Solution explorer.\nHowever, the authoring capabilities are limited for the moment and it\u0026rsquo;s hard to have a high level view of the Catalogs in your environment. Hence the idea behind the Catalog Manager tool for XrmToolBox.\nCatalog Manager Tool The tool can be downloaded within the XrmToolBox Plugin manager. Once installed it will be available in the tools section.\n360° View on Catalogs\nThe goal of the tool is to provide full visibility on the Catalogs and Catalog Assignements registered in your Dataverse environment.\nYou can (1) select existing Catalogs or (2) Create new ones from scratch.\nOnce a root Catalog is selected, you have access to all the relevant information about the Catalog at your fingertips. There is also a treeview to see the Catalog full structure.\nYou can perform all CRUD operations on the Catalogs, Categories (2nd level Catalogs) and Catalog Assignment s very efficiently in the same UX.\nFor Catalog Assignments, you can link your assignment to a (1) Table, (2) a Custom API or (3) a Custom Process.\nscreenshot_create_assignment.png (560×302) To create Custom APIs for your Catalogs, you can use the Custom API Manager tool for XrmToolBox\nMore on Business Events If you are curious about the Dataverse Business Event model, don\u0026rsquo;t miss these official Microsoft press release.\nThere is also a very good post from Natraj Yegnaraman that shows how to leverage Business Events to trigger a PowerAutomate Flow.\nWhile the Business Events model is still in it\u0026rsquo;s infancy, I have a feeling that we will hear more and more about it and that it will open new possibilities for developers. I hope the Catalog Manager tool will prove to be handy.\nI would greatly appreciate any feedback so I can improve the user experience. Also if you have any ❓ questions or 💡 feature requests don\u0026rsquo;t hesitate to contact me in the discussion area of the GitHub repo. drivardxrm/Driv.XTB.CatalogManager Manager tool for Dataverse Catalog and Catalog Assignments - drivardxrm/Driv.XTB.CatalogManager github.com Microsoft Dataverse business events (preview) - Power Apps Learn about how to use business events to connect and integrate business applications. docs.microsoft.com Catalog and CatalogAssignment tables (Microsoft Dataverse) - Power Apps Learn how to use the Catalog and CatalogAssignment tables to expose events in your solution docs.microsoft.com Using Custom API as a trigger for Flow Dropping new goodies straight to Microsoft Docs, without any formal announcement, has now been normalised. Couple of Virtual Table features have been “announced” without much fanfare th… dreamingincrm.com Custom API Manager for XrmToolBox Like most Power Platform developers, I am a heavy user of the XrmToolBox. This is the story of creating a tool to contribute to the community. itmustbecode.com ","date":"2021-06-23T14:52:36Z","image":"/catalog-manager-for-xrmtoolbox/image-4.png","permalink":"/catalog-manager-for-xrmtoolbox/","title":"Catalog Manager for XrmToolBox"},{"content":"If you are developing Dataverse Custom APIs, you might have noticed that a new column (field) called \u0026rsquo; Enabled For Workflow\u0026rsquo; recently showed up in the Custom API form. In this post, we will try to make sense of this new feature, understand its impact on the Custom API extension model, and show how to use workflow-enabled APIs.\nAt the time of writing the feature is not yet \u0026rsquo; officially\u0026rsquo; documented, I will update the post and put the link here when available\nWhat does it enable? Well, the name of the attribute speaks for itself. If you set the \u0026rsquo; Enabled For Worflow\u0026rsquo; (schema name: \u0026rsquo; workflowsdkstepenabled\u0026rsquo;) column to True ✅, your Custom API will be available to be called inside a Dataverse classic workflow using a \u0026rsquo; Perform Action\u0026rsquo; step.\nIt\u0026rsquo;s important to note that setting this attribute can only be done at the creation of an API and cannot be updated after ( more on that later).\nWait\u0026hellip; did you say Classic Workflows? You might find it unusual that Microsoft would invest in anything related to classic workflows since we are \u0026rsquo; supposed\u0026rsquo; to move away from that model and adopt Power Automate Flows.\nFor me, it makes a lot of sense, especially for the user (or developer) adoption of the Custom API model. It crosses out one of the limitations that might keep some developers away from Custom APIs.\nPersonally, I still use classic workflows (a lot less I admit), and the fact that I wasn\u0026rsquo;t able to use my Custom APIs inside a workflow like I would with a Custom Action always bugged me. An API by definition should be as universal and agnostic as possible, and I should be able to call it from wherever I want.\nAlso, with this new feature,the Custom APIs now have (virtually) full parity with classic Custom Actions. So If you were reluctant to migrate to Custom APIs for your custom messages development, there\u0026rsquo;s one less reason.\nXrmToolBox Custom API Manager update I have added the new attribute in the latest release of my Custom API Manager for XrmToolbox, so please update the tool to the latest version (v1.2021.5.35 or +) if you are using it.\nIf you don\u0026rsquo;t know this tool, I strongly recommend that you take a look at it as it provides a great authoring experience for Custom API\u0026rsquo;s (shameless plug 😁)\nHow-to use a Workflow-Enabled Custom API To consume your Custom API inside a classic workflow, you only have to set the \u0026lsquo;Enabled for Workflow\u0026rsquo; attribute to True ✅.\nYour workflow-enabled API will now be surfaced in the workflow designer using the \u0026rsquo; Perform Action\u0026rsquo; Step. After that, the process is exactly the same as consuming a classic custom action.\n1- Select the \u0026lsquo;Perform Action\u0026rsquo; Step 2- Select your workflow-enabled API In this example, I use the GetEnvironmentVariable Custom API from my collection of Custom API community projects. 👉 See the details of the implementation of this API here.\nNote here that any Custom API where the \u0026lsquo;Enabled for Workflow\u0026rsquo; is set to false ❌ will not be surfaced in the list.\n3- Set the Inputs (Request Parameters) of the API After you select your workflow-enabled API, you can set the input parameters by clicking on the \u0026rsquo; set properties\u0026rsquo; button. Here I supply the schema name of the environment variable I want to retrieve in the input property called \u0026rsquo; Key\u0026rsquo;\n4- Outputs (Response Properties) are accessible The outputs of your API are now accessible in the following steps and you can use the values in your workflow logic.\nIn this particular example, I check If the environment variable called \u0026lsquo;driv_SendMail\u0026rsquo; exists in my environment and if the value of the environment variable is true, If Yes then I will send an email.\n5- Execute the workflow You can see the result of the workflow execution, my custom API was called inside the workflow, the results of the API call were used to make a decision, and a mail was sent\u0026hellip; et voilà.\nBumps on the road One thing to keep in mind is that the attribute cannot be modified after creation. This poses a problem for any API created before the rollout of this new functionality. If you want to use your existing custom API in workflows, you will need to erase and recreate them with the \u0026rsquo; Enabled for Workflow\u0026rsquo; flag set to True. 🤷‍♂️\nImpact on my Custom API project Because I really want to take advantage of this feature, I had to come up with a plan to update my community project that contains a set of very useful generic APIs. But as said before, the \u0026rsquo; Enabled for Workflow\u0026rsquo; can only be set at creation. drivardxrm/Dataverse-CustomApis Collection of Dataverse Custom Apis. Contribute to drivardxrm/Dataverse-CustomApis development by creating an account on GitHub. github.com By mingling with the solution XML files, repackage an unmanaged solution and reinstall the solution in a fresh environment, I was able to recreate the APIs and make them work with classic workflows \u0026hellip;. So far so good. The latest version is available on my Github repo.\nProblem is that if you had a previous installation of the solution, you will need to uninstall everything and install the latest version (v1.2021.05.41 or +), sorry for the inconvenience if any.\nConclusion The new \u0026rsquo; Enabled for Workflow\u0026rsquo; field on Dataverse Custom API is a great addition that enables your APIs to be called inside classic workflows. It removes a limitation and gives more reach to your APIs.\nKeep in mind that this setting can only be set at the creation of an API record and cannot be updated afterward, so you might have to recreate your existing APIs.\nFor this reason, I strongly advise that you set that you always check this attribute to True when you create a new custom API, you never know if someone would want to consume your API inside a workflow, don\u0026rsquo;t limit yourself.\nHappy API\u0026rsquo;ing!\nBlog Post Image by Gerd Altmann from Pixabay\n","date":"2021-05-25T11:56:49Z","image":"/dataverse-custom-api-enabled-for-workflow/image-14.png","permalink":"/dataverse-custom-api-enabled-for-workflow/","title":"Dataverse Custom API: Enabled For Workflow"},{"content":"I had the great pleasure to give a presentation on Dataverse Custom API during the PowerPlatform 24 event on May 5, 2021.\nPower Platform 24 Conference May 2021 cover image You can find the recording here:\nhttps://365.training/Player/Index/Power24-05-2021/3daa9377-b3a2-eb11-b1ac-00224808418b\n","date":"2021-05-13T02:41:07Z","image":"/power-platform-24-may-5-2021/power24.png","permalink":"/power-platform-24-may-5-2021/","title":"Power Platform 24 - May 5, 2021"},{"content":"The new Dataverse Custom API feature ( now in General Availability 🚀) empowers developers with the ability to create their own custom messages to extends the capabilities of the Power Platform. These custom messages are then exposed by the Dataverse endpoints (WebApi and Organizationservice) like other out-of-the-box messages (Create, Update, etc..).\nWhile the Custom API model shares a lot of similarities with the traditional Custom Action model that is available since Dynamics 2013, it also exposes a bunch of unique features that are worth taking a look at.\nSo to continue on my series of posts on Dataverse Custom API\u0026rsquo;s unique features, this one will explore the IsFunction flag that can be found on the Custom API Table. We will try to understand how this attribute affects the way end-users interact with Custom APIs.\nPlease, refer to Microsoft\u0026rsquo;s official documentation for the most up-to-date information.\nSetting the IsFunction Attribute When you create a new Dataverse Custom API record, you will notice that you are asked to set a boolean (yes/no) attribute called IsFunction. Setting this attribute will have a deep impact on how your custom message will be exposed and consumed so it\u0026rsquo;s very important to understand the intricacies associated with this choice.\nThe example below shows how to set the attribute using the Custom API Manager for XrmToolBox. Be careful, setting this attribute is only available at the creation and you cannot change it afterward.\nAs to WHY someone would set a Custom API as a function or not is really a philosophical choice (and a practical one as we will see later), the purpose and internals of your API stay more or less the same whether you set IsFunction to true or false :\nYou have a collection of inputs ( request parameters) You execute some code (the plugin bound to your Custom API record) You return a collection of outputs ( response properties) To further illustrate some of the concepts, we will compare 2 unbound custom APIs that expose exactly the same functionality which is to retrieve an environment variable value given an input parameter called \u0026rsquo; Key\u0026rsquo;. The only difference will be the IsFunction flag.\ndriv_GetEnvironmentVariable_FUNCTION IsFunction = true ✔️ -\u0026gt; Function driv_GetEnviromentVariable IsFunction = false ❌ -\u0026gt; Action 👉You can download and install an implementation of the GetEnviromentVariable in my collection of Dataverse Custom API available here\nFunction (GET) or Action (POST) The fundamental difference of setting your API to be a function or an action is found in the way your message will be exposed and consumed using the Dataverse REST endpoint (Web API).\nIf IsFunction = true ✔️, your message will be exposed using the GET HTTP verb, meaning that any inputs ( request parameters) will need to be sent directly in the URL.\nWhereas, if IsFunction = false ❌, your message will be exposed using the POST HTTP verb.In that case, the inputs ( request parameters) will be sent as a JSON payload in the body of the request.\nNotice that the outputs of the 2 calls are identical. You will receive a collection of response properties in JSON format, so no difference on that end.\nThe difference between GET and POST can look trivial for this simple example having only one input parameter of type string, but when you have several inputs with different types (ex. dates, entity references etc\u0026hellip;) I find that the GET notation can become a bit messy. For me the JSON Body notation of the POST is much easier to understand.\nOK! So why choose one over the other? That is to say, if you are a \u0026rsquo; purist\u0026rsquo; and you want to RESpecT the REST conventions, if your API doesn\u0026rsquo;t make any change to the Database(verse) your message might be better expressed as a function ( GET), and if your message implies any mutation to the data you might want to consider an action ( POST).\nBut like I said earlier it\u0026rsquo;s a philosophical choice and I will show you why I think that at this point in time, it\u0026rsquo;s much better to always define your Custom API as actions ( POST) and leave the IsFunction attribute to false.\nCalling Functions and Actions in Power Automate I think that Power Automate is a place where the Custom API model shines the most. It can provide flow makers with robust ( hopefully tested 😏) and easy-to-use functions that encapsulate complex business logic.\nOne major plus 🌟 for actions APIs (POST), is that they can be called in Power Automate using the ‘ Perform Action’ step of the Common Data service (current environment) connector. Unfortunately ( at the time of writing) Functions APIs (GET) are not surfaced using this connector.\nUsing the Perform Action step, any Actions APIs (POST) existing in your environment will be surfaced in the Action Name dropdown. Upon selection, input parameters will be dynamically listed and available for edition.\nAlso, all individual outputs of your API will be directly and easily accessible in the Dynamic content tab for subsequent use. The connector automatically parses the JSON output for you, ain\u0026rsquo;t that amazing 👏.\nSo, for that reason alone, I tend to set the IsFunction flag to \u0026rsquo; false\u0026rsquo; on my Custom APIs just so they can be used easily and without a fuss in Power Automate.\nIf you really want to call a function API in Power Automate (or if you want to use one of the many out-of-the-box functions 👉 see the list here), you can always use the HTTP with Azure AD connector and send the same kind of request seen earlier in the PostMan example for the function API ( GET). The API code will be executed and the results ( response properties) in JSON will be available in the Body section of the Outputs.\nAlthough, this approach is far less portable and more complicated to use to than using the Perform Action step. Here is why :\nIf you want to install your Flow in different environments, You will need to provide the base URL dynamically ( by using an environment variable for example) or change it manually on each environment ( who wants to do that? 🤷‍♂️ ) You need to know the name and input parameters of your message, no help from the platform here to surface the available messages and parameters. ( Not very Citizen Developer friendly) Outputs will not be directly available in the dynamics content panel, you will have to parse the JSON output if you want to access the values directly. Should I say more\u0026hellip; I think you get the idea. Calling Functions and Actions from Plugins Interestingly there are no difference in the code that would be needed to call a function ( GET) or an action ( POST) Custom API inside another plugin (or any C# program) using Microsoft.Xrm.Sdk objects from Microsoft.CrmSdk.CoreAssemblies Nuget package.\nIn this case, we are closer to the metal, and using the good\u0026rsquo;ol Organizationservice endpoint. The 2 APIs can be called exactly the same way using the generic OrganizationRequest object. The inputs will be set in the \u0026rsquo; Parameters\u0026rsquo; collection and any outputs can be retrieved in the \u0026rsquo; Results\u0026rsquo; collection of the OrganizationResponse object received from the execution of the request.\nSo if you design a Custom API and you know for a fact that it will only be called in that manner, there is no harm defining it as a function ( GET), but why limit yourself? I would still prefer to use a POST API just in case.\nConclusion So to wrap this up, it\u0026rsquo;s important to understand the effects of the IsFunction attribute on Dataverse Custom APIs, mainly affecting how APIs are called on the wire (WebApi REST endpoint) with GET or POST HTTP Verbs.\nAlso in a Power Automate context, the Perform Action step of the Common Data Service (current environment) connector is a fantastic vehicle for calling POST Custom APIs. Providing API discoverability as well as a wrapper around the inputs and outputs of custom messages.\nHappy API\u0026lsquo;ing!\nLinks Create and use Custom APIs (Microsoft Dataverse) - Power Apps Custom API is a new code-first way to define custom messages for the Microsoft Dataverse. learn.microsoft.com Use Web API functions (Microsoft Dataverse) - Power Apps Functions are reusable operations that are used with a GET request to retrieve data from Microsoft Dataverse docs.microsoft.com Dataverse Custom API Manager · XrmToolBox Management tool that provides 360° View of Dataverse Custom APIs. Provides CRUD operations on Custom API, Request Parameters (Inputs) and Response Properties (Outputs). www.xrmtoolbox.com Release v1.2021.01.28 · drivardxrm/Dataverse-CustomApis Added API RemoveDiacritics github.com functions?WT.mc_id=DX-MVP-5004959 A function is an operation which does not have observable side effects. They typically retrieve data. They may have parameters and they may return values. Functions may be bound to entity types. docs.microsoft.com Microsoft.CrmSdk.CoreAssemblies 9.0.2.32 This package contains the official Microsoft.Xrm.Sdk.dll and Microsoft.Crm.Sdk.Proxy.dll assemblies plus tools and has been authored by the Microsoft Common Data Service SDK team. www.nuget.org ","date":"2021-03-25T21:45:30Z","image":"/dataverse-custom-api-function-get-vs-action-post/2021-01-28_23-38-02.png","permalink":"/dataverse-custom-api-function-get-vs-action-post/","title":"Dataverse Custom API: Function (GET) vs Action (POST)"},{"content":"I had the great pleasure to speak at the Scottish Summit 2021. Here is the link to my session on Youtube.\n","date":"2021-03-10T12:56:04Z","image":"/my-scottish-summit-2021-session/David-Rivard.png","permalink":"/my-scottish-summit-2021-session/","title":"My Scottish Summit 2021 session"},{"content":"Pursuing my series of blog posts on Dataverse Custom API features, this one will be \u0026lsquo;short and sweet\u0026rsquo; and explores the usage of the IsPrivate attribute that can be found on the Custom API Table.\nThe ability to set an API as a Private message is a unique feature of the Custom API model and does not exist for classic Workflow Custom Actions.\n🚨The IsPrivate Attribute is (currently) not available/editable using the out-of-the-box Custom API authoring experience (Model-Driven form). That\u0026rsquo;s a very good reason to try my Custom API manager tool for XrmToolBox where the attribute can be set easily. 😏\nKeep It For Yourself As per Microsoft documentation, a Custom API with IsPrivate set to true will be hidden (ghosted) from metadata and documentation. Meaning it will not be discoverable by metadata queries running against the Dataverse environment.\nA good use case for this functionality is for an ISV scenario. For instance, If you develop and ship products/extensions that are installed on your customer\u0026rsquo;s Dataverse environments, you may want to leverage the power of Custom APIs for the internal operations of your product.\nNow, for obvious functional and IP reasons, you don\u0026rsquo;t necessarily want to expose your Custom APIs signature to other users/developers of the environments where your product is installed. That is where the IsPrivate attribute might come useful.\nHowever, It\u0026rsquo;s important to understand that even if a Custom API is hidden, anyone who knows the existence and the signature (inputs/outputs) of a private message will be able to use it like any other (public) Custom APIs. So if you really want to completely lock your Custom API from \u0026rsquo;nosy\u0026rsquo; 👃 developers, you will have to implement some kind of authorization mechanism. (out of the scope of this blog post)\nTooling in a Private Message context Setting a Custom API as private also has side-effects on any tooling that uses metadata queries. For example, tools like crmsvcutil will skip Private Messages when generating \u0026rsquo;early bound\u0026rsquo; classes.\nIf you really need to generate early bound classes for a Private Message, here is a workaround.\n1- Uncheck the IsPrivate attribute temporarily Using the Custom API Manager tool for XrmToolBox, you can set the IsPrivate attribute to False\n2- Generate Early Bound Classes Generate your early bound classes like you would normally do. I\u0026rsquo;m using Daryl Labar EarlyBound Generator for XrmToolBox in the example below, which is a wrapper around the crmsvcutil tool. You can see that when I generate classes for the Actions, my Custom API gets picked-up by the tool.\nYou can then use the generated early bound class of your Custom API in your other plugins assemblies or external programs.\n3- Put back the IsPrivate flag on the API Now you can set the IsPrivate attrtibute back to true and ship your Private Custom API to end-users.\nExtending Private Messages One thing I noticed while playing around with the feature is that even if you set your API to be extendable by 3rd parties ( AllowCustomProcessingStep = SyncAndAsync) ( see my previous blog post on that matter) and your API is marked as Private, you will not be able to attach a plugin step on the message using the plugin registration tool.\nThis makes sense since the plugin registration tool needs to make a metadata query to show available messages where you can attach a plugin step.\nSummary There is not much more to say, the name of the IsPrivate attribute speaks by itself. It gives Dataverse developers a way to hide Custom API messages by making them impossible to discover. It\u0026rsquo;s a feature that is unique to the Custom API model and it can have a real business value in certain scenarios.\nHappy API\u0026lsquo;ing!\nLinks Dataverse Custom API Manager · XrmToolBox Manage Dataverse Custom APIs and their request parameters and response properties with XrmToolBox. itmustbecode.com Early Bound Generator · XrmToolBox Generates Early Bound Entities/Option Sets/Actions. Uses CrmSvcUtil from the SDK, and shows command line used to create the classes. www.xrmtoolbox.com Dataverse Custom API: AllowCustomProcessing Explained This article explains the AllowedCustomProcessingStep attribute and the differences between Dataverse Custom APIs and traditional Workflow Custom Actions. itmustbecode.com Create and use Custom APIs (Microsoft Dataverse) - Power Apps Custom API is a new code-first way to define custom messages for the Microsoft Dataverse learn.microsoft.com Create early bound entity classes with the code generation tool (CrmSvcUtil.exe) (Developer Guide for Dynamics 365 Customer Engagement) Learn how to create early bound entity classes with the code generation tool, CrmSvcUtil.exe, for Dynamics 365 Customer Engagement (on-premises). docs.microsoft.com Post Image by PublicDomainPictures from Pixabay\n","date":"2021-01-25T02:40:22Z","image":"/dataverse-custom-api-keep-it-private/no-access-71232_640.jpg","permalink":"/dataverse-custom-api-keep-it-private/","title":"Dataverse Custom API: Keep It Private"},{"content":"I had the great pleasure to geek out with Jonas Rapp and Daryl Labar on this episode of XrmToolCast\nXrmToolCast: The Dataverse Custom API Collection with David Rivard Dataverse has had custom actions for some time now, and now, a similar new tool is available to Dataverse developer, Custom APIs. We’ve brought David Rivard on to not only help define what they are, but to talk about his new . Other topics covered: What’s the difference between Custom A… xrmtoolcast.libsyn.com ","date":"2021-01-19T04:29:00Z","permalink":"/xrmtoolcast-podcast/","title":"XrmToolCast - Podcast"},{"content":"This is the first article in a series of posts aimed at showing the main differences between Dataverse Custom API s and the more traditional Workflow Custom Actions. This article will focus on the AllowedCustomProcessingStep attribute of Custom APIs.\nCustom API vs Custom Action Dataverse Custom APIs and Workflow Custom Action share common ground. The 2 models will expose custom Messages that can be called by the Dataverse WebApi like other Out-of-the-Box Messages of the Platform (ex. Create, Update). The differences are found in the underlying implementation of each model.\nYou can find Microsoft official documentation that compares the 2 models here\nOne of the most notable differences in my opinion is that with a Custom API you have the ability to restrict how 3rd Party developers can mingle with your custom Message by using the AllowedCustomProcessingStepType attribute.\nBut first, let\u0026rsquo;s go under the hood and see how a Custom API works.\nCoding on the 30 If you are familiar with the Dataverse Message execution pipeline you know that there are 4 Stages PreValidation(10), PreOperation(20), MainOperation(30) and PostOperation(40). The Main Operation (30) is reserved for the platform core operation and has always been (until now) obfuscated to developers.\nThen, a bit like a suckerfish that attaches itself to a shark, developers can extend the Messages by attaching plugin steps to stages before or after the Main operation to alter the message behavior.\nThat is exactly the strategy that can be used to execute custom code using classic Workflow Custom Actions. You would start by defining your Action, Inputs, and Outputs in the classic workflow designer and leave the (low-code) execution part blank. This would create a new Message on which you can attach custom code on Pre or Post Operation.\nThings are a bit different with Custom APIs, where you are actually coding the Message core operation itself , and the custom code triggered by the API executes on the Main Operation (30)( see Plugin trace below).\nAs a Power Platform developer, I personally felt a great deal of power ⚡ when I first realized that I was coding on the 30\u0026hellip; but maybe I spend too much time in front of my computer 🤓 .\nIn fact, with the Custom API model, you won\u0026rsquo;t even need to register any plugin steps with the Plugin Registration Tool for the code to be executed. You only need to configure your Custom API record to point on a Plugin exposed by a plugin assembly. Once this link between the Custom API record and a Plugin Type is made, the API is up and running.\nTo Allow or Not To Allow. That is the Question. That being said, there is an attribute on the Custom API Table called AllowedCustomProcessingStepType that enables the author to configure how others will be able to attach or not to the Message exposed by the API. This attribute contains the following values.\nNone This blocks completely any extension of the message AsyncOnly Only asynchronous plugins can be registered on the message SyncAndAsync Allows any kind of extensions on the message This can be very important especially if the message being exposed by the Custom API carries sensitive information. For example, a message that would expose the Licensing status of an ISV product.\nLet\u0026rsquo;s illustrate this with an example Say we have an Environment Variable called \u0026rsquo; SensitiveUrl\u0026rsquo; that contains an URL that is critical to our business logic. A Custom API is responsible to retrieve the Environment variable value at run-time.\nWe have 2 Custom APIs that will execute the exact same code, but one has the AllowedCustomProcessingStepType set to None and the other set to SyncAndAsync.\nNameAllowedCustomProcessingStepType****GetEnvironementVariableNoneGetEnvironmentVariable_OPENSyncAndAsync\nIf you are interested, the GetEnvironmentVariable API implementation can be found in my collection of generic Dataverse Custom API .\nNow let\u0026rsquo;s register a new Plugin Assembly on the Dataverse environment called HackTheApi. Since the GetEnvironmentVariable_OPEN is extendable because of its AllowedCustomProcessingStepType status (SyncAndAsync), it is possible to attach to the message synchronously and execute a diabolic 😈 hack. ( Overdramatization )\nNote that because of its AllowProcessingStep value set to None, the message GetEnvironmentVariable will not even appear in the list of available messages to extend.\nThe code of this nifty hack will substitute the value of the environment variable contained in the OutputParameters collection of the PluginExecutionContext with a different value.\nWhen we test the APIs, we get completely different behavior.\nGetEnvironmentVariable will give the expected result.\nWhile GetEnvironmentVariable_OPEN will return the \u0026rsquo; hacked value'.\nI\u0026rsquo;m being dramatic on purpose here but you can see that leaving an API opened could have a significant impact on your business logic . This doesn\u0026rsquo;t mean that you should always block your APIs, it might be totally worth it and legit to allow Message extension in certain scenarios.\nAsync Only The 3rd option for the AllowedCustomProcessingStepType is to allow only Asynchronous plugin steps to be registered on the Custom API message.\nUsing this option will assure you that the Outputs of your API call cannot be tampered with while offering to 3rd party developers a way to trigger async custom code after a specific API has been called. For example, every time an API is called, I want to increment a counter.\nSummary There are differences in the way custom code is executed between the Custom API and the Custom Action extension model. A Custom API custom code executes on the Main Operation (30) of the message execution pipeline, something that is not possible in other extension models.\nWe demonstrated how the AllowedCustomProcessingStepType attribute can have a significant impact on the behavior of Custom API. This level of control is only available on the new Custom API functionality and doesn\u0026rsquo;t exist for classic Workflow Custom Actions.\nThere is no Good or Bad way, every option has its pros and cons, and you need to understand the intent and the desired usage of your APIs before releasing them to the wild.\nHappy API\u0026lsquo;ing!\nLinks and references Create your own messages (Microsoft Dataverse) - Power Apps Learn about creating your own custom Microsoft Dataverse messages to be executed from your applications, and how these custom messages differ from using the Custom API feature. docs.microsoft.com drivardxrm/Dataverse-CustomApis Collection of Dataverse Custom Apis. Contribute to drivardxrm/Dataverse-CustomApis development by creating an account on GitHub. github.com Plugin Trace Viewer for XrmToolBox The primary goal of the tool is to give developers and administrators of Microsoft Dynamics CRM an easy to use tool to investigate the Plugin Trace Log. This includes the possibility to filter the logs and display the information in ways not currently possible within the Micr… ptv.xrmtoolbox.com Custom API Manager for XrmToolBox Like most Power Platform developers, I am a heavy user of the XrmToolBox. This is the story of creating a tool to contribute to the community. itmustbecode.com ","date":"2021-01-11T12:58:32Z","image":"/dataverse-custom-api-allowcustomprocessing-explained/messagehack-2.png","permalink":"/dataverse-custom-api-allowcustomprocessing-explained/","title":"Dataverse Custom API: AllowCustomProcessing Explained"},{"content":"Like most Power Platform developers, I am a heavy user of the XrmToolBox a community project led by Tanguy Touzard. The myriad of tools it surfaces just makes my day to day job a lot less painful. I also secretly been wanting to write a tool of my own to contribute to this amazing project for a long time.\nThe wait is over 🎉 Today, I\u0026rsquo;m proud to release my first tool called Custom API Manager, and I really think that it will fill a gap in the current Custom API authoring experience.\nDataverse Custom API Manager · XrmToolBox Management tool that provides 360° View of Dataverse Custom APIs. Provides CRUD operations on Custom API, Request Parameters (Inputs) and Response Properties (Outputs). www.xrmtoolbox.com If you want to skip the details, you can fire up your XrmToolBox application and install the Tool from the Tool Library. You will then have access to it in the Tools section.\nIf you need some APIs to play around with, you can install my collection of generic Dataverse Custom API ( Shameless plug 😏)\ndrivardxrm/Dataverse-CustomApis Collection of Dataverse Custom Apis. Contribute to drivardxrm/Dataverse-CustomApis development by creating an account on GitHub. github.com What\u0026rsquo;s a Custom API anyway? At the time of writing, Dataverse Custom APIs are still considered a preview feature. If you want more information please look at Microsoft official documentation\nI will blog more deeply into Dataverse Custom APIs but, In a nutshell, they give developers the ability to define their own REST messages to encapsulate business logic written in C# (using IPLugin interface from the Xrm SDK) with a set of Inputs ( Request parameters) and Outputs ( Response properties).\nThese messages are then exposed by the Dataverse WebApi and can be consumed by any method that can connect to it (Plugins, Power Automate, PCF, Modern-Driven Form javascript, External programs, etc\u0026hellip;). The use cases are unlimited.\nA current limitation of the Custom API is the lack of an editor for authoring and management purposes (like the Custom Action/Workflow Editor). Instead, the APIs, Inputs, and Outputs need to be managed separately and it can be hard to get the full picture of the APIs that are defined in a system. This is where the Custom API Manager comes in handy.\nThis is where the Custom API Manager comes in handy.\n360° View of Custom API The goal of the tool is to provide full visibility of the Dataverse Custom APIs and related components like request parameters (inputs) and response properties (outputs) that are registered in your Dataverse environment.\nYou can (1) select existing APIs or (2) Create new ones from scratch.\nOnce an API is selected, you have access to all the relevant information about the API at your fingertips. You can perform all CRUD operations on the API, Request Parameters (inputs), and Response Properties (outputs) very efficiently in the same UX.\nIntegration with Custom API Tester Custom API Tester · XrmToolBox Browse Custom APIs, enter input parameters, execute the action, investigate output parameters. www.xrmtoolbox.com My favorite feature is that the tool is integrated (both ways) with the Custom API Tester from Jonas Rapp. I had the opportunity to speak with him lately and we decided to make our tools communicate, I personally think that this joint-venture provides added value to both tools. 1️⃣ + 1️⃣ = 3️⃣\nWith this integration, you can Define your API in the Custom API Manager, and Test it right away using the Custom API Tester. ( Bonus! You can even Monitor the test execution using the Plugin Trace Viewer that is integrated with the API tester\u0026hellip; how cool is that 🤯)\nOn a technical side, I found it quite easy to implement tool integration and I encourage every XrmToolBox Tool author to find synergies with other existing tools in order to provide better experiences to the end-users.\nFollow these 3 simple steps to leverage tools integration. 1- Implement the IMessageBusHost interface First, you need your control to implement the IMessageBusHost interface contained in XrmToolBox.Extensibility.Interfaces Library.\nThe interface need the following methods and event to be defined on your plugin class.\nOnOutgoingMessage: Event that will send request from your tool to another tool OnIncomingMessage: Method that will accept a request from another tool to fire up your tool 2- Define Outgoing Message To send a request to another Tool from your own tool, you will need to define an event called OnOutgoingMessage. ( this line of code will be added automatically in your class when you implement the interface)\nOnce defined, you can call the event from your business logic. Here I\u0026rsquo;m calling the OnOutgoingMessage event when the user clicks on the Open With Custom API Tester button.\nWhen calling the event you need to specify the following in the arguments ( MessageBusEventArgs)\nName of the tool to call TargetArgument: this is the object that the receiving tool is expects (Context). In our case, we send a string that contains the GUID of the Custom API to Open in the Custom API Tester 3- Define Incoming Message To receive a request from another tool, we need to implement the OnIncomingMessage method from the interface.\nHere we can get the Context information from the TargetArgument object contained in MessageBusEventArgs received from the caller. It\u0026rsquo;s then up to you to do what you need with this information in your code. For example, get the GUID of the Custom API that we want to display in the form.\nAs a side-note Jonas Rapp just released a tool called XrmToolBox Integration Tester to test these kinds of inter-tools integrations, it really helped me during the development.\nXrmToolBox Integration Tester ⋆ The Power Platform Trenches The XrmToolBox Integration Tester tool helps tool developers validate any integration scenarios where other tools call their own tools. jonasr.app Lessons learned Looking back on my XrmToolBox Tool authoring experience, I have to say that it is a personal challenge I am happy to have accomplished.\nThere is definitely a learning curve and you need to dust up your good\u0026rsquo;ol WinForm skills which is the stack that the ToolBox is built on. There are a lot of good resources to get you started ( see link section at the end of the post ). I also found a lot of inspiration looking at some of the top Tools GitHub repos (ain\u0026rsquo;t that what open-source is all about).\nOne of the hidden gems 💎 I found that saved me tons of time ( and lines of code) was this collection of WinForm controls adapted to Dataverse: xrmtb.XrmToolBox.Controls. Particularly the CDSDataTextBox and the CDSLookupDialog that used extensively in my tool. Just install the NuGet package in your project.\njamesnovak/xrmtb.XrmToolBox.Controls Repository of shared controls that can be used for building XrmToolBox Tools - jamesnovak/xrmtb.XrmToolBox.Controls github.com Going forward This is the first release of the Custom API Manager, I hope it will help some of you adopt and enjoy this new Power Platform extensibility option.\nI would greatly appreciate any feedback so I can improve the user experience. Also if you have any ❓ questions or 💡 feature requests don\u0026rsquo;t hesitate to contact me in the discussion area of the GitHub repo.\ndrivardxrm/XTB.CustomApiManager Dataverse Custom Api Manager for XrmToolBox. Contribute to drivardxrm/XTB.CustomApiManager development by creating an account on GitHub. github.com Useful links and references 25 Nov 2020 | Let’s build an XrmToolBox tool! by Jonas Rapp Autoplay youtu.be Use Azure DevOps to publish XrmToolBox tools ⋆ The Power Platform Trenches In this article I demonstrate how to create a complete CI/CD pipeline for your XrmToolBox tools using GitHub, Visual Studio Team Services, and NuGet. jonasr.app Create and use Custom APIs (Microsoft Dataverse) - Power Apps Custom API is a new code-first way to define custom messages for the Microsoft Dataverse learn.microsoft.com ","date":"2021-01-04T02:46:01Z","image":"/customapi-manager-for-xrmtoolbox/2021-01-03_19-53-32.png","permalink":"/customapi-manager-for-xrmtoolbox/","title":"Custom API Manager for XrmToolBox"},{"content":" drivardxrm/XTB.CustomApiManager Dataverse Custom Api Manager for XrmToolBox. Contribute to drivardxrm/XTB.CustomApiManager development by creating an account on GitHub. github.com Management tool that provides 360° View of Dataverse Custom APIs. Provides CRUD operations on Custom API, Request Parameters (Inputs) and Response Properties (Outputs).\nIntegrates with Custom API Tester Tool\nPlease submit any ideas 💡 or questions ❓ here.\nDataverse Custom API Manager · XrmToolBox Management tool that provides 360° View of Dataverse Custom APIs. Provides CRUD operations on Custom API, Request Parameters (Inputs) and Response Properties (Outputs). www.xrmtoolbox.com XTB.CustomApiManager 1.2020.12.27 Management tool that provides 360° View of Dataverse Custom APIs. Provides CRUD operations on Custom API, Request Parameters (Inputs) and Response Properties (Outputs). www.nuget.org ","date":"2021-01-02T21:33:54Z","permalink":"/xtbcustomapimanager-for-xrmtoolbox/","title":"XTB.CustomApiManager for XrmToolBox"},{"content":" drivardxrm/Dataverse-CustomApis Collection of Dataverse Custom Apis. Contribute to drivardxrm/Dataverse-CustomApis development by creating an account on GitHub. github.com This project contains a set of generic Dataverse Custom APIs that can be installed and consumed in any Dataverse environment.\nThe goal of the project is to enhance the capability of PowerPlatform developers and makers by providing robust and easy to use API that can be consumed agnostically by any calling mechanism. (Ex. Power Automate, PCF, Model-Driven Form javascript, \u0026hellip;)\nPlease submit any ideas 💡 or questions ❓ here.\n🚀 Find the latest release here\nCurrent API list (see Wiki for API Definitions) AgeCalculation (🆕 v1.2020.12.25) DateInfo(🆕 v1.2020.12.25) DateCompare(🆕 v1.2020.12.25) GetEnvironmentVariable GetLocalizedChoiceLabel GetTableInfo GetUserTimezone ","date":"2021-01-02T21:20:57Z","permalink":"/dataverse-custom-api-collection/","title":"Dataverse Custom API collection"},{"content":"This image has an empty alt attribute; its file name is image-1.png PCF Gallery Rating PCF A control to create a configurable rating system based on FluentUI. pcf.gallery GitHub repo drivardxrm/Rating.PCF Contribute to drivardxrm/Rating.PCF development by creating an account on GitHub. github.com ","date":"2020-06-10T21:12:43Z","image":"/rating-pcf/image-1.png","permalink":"/rating-pcf/","title":"Rating PCF"},{"content":"Power Platform Saturday – Developer Edition June 2020 - Build awesome PCF’s using React Hooks Here is the video of my session\n","date":"2020-06-07T11:01:00Z","permalink":"/power-platform-saturday-build-awesome-pcfs-using-react-hooks/","title":"Power Platform Saturday - Build awesome PCF’s using React Hooks"},{"content":"Date Two Option PCF Gallery Date Two Option A control that turns a PowerApps date field into a checkbox. When the checkbox is clicked, the current date is stored in the backing date field. pcf.gallery GitHub repo drivardxrm/DateTwoOption.PCF Contribute to drivardxrm/DateTwoOption.PCF development by creating an account on GitHub. github.com ","date":"2020-05-09T20:50:33Z","image":"/date-two-option-pcf/image-7.png","permalink":"/date-two-option-pcf/","title":"Date Two Option PCF"},{"content":" Country Picker A control that renders a Text field as a Combobox displaying country names and flags. Country information comes from the public API https://restcountries.eu. pcf.gallery drivardxrm/CountryPicker.PCF Country Picker PCF. Contribute to drivardxrm/CountryPicker.PCF development by creating an account on GitHub. github.com ","date":"2020-01-15T21:45:05Z","image":"/country-picker-pcf/image.png","permalink":"/country-picker-pcf/","title":"Country Picker PCF"},{"content":"OptionSet Icons PCF Gallery OptionSet Icons A control to transform an OptionSet field into a configurable Fabric-UI Choice group with Icons, compatible with up to five options. Optionset labels are used as icon labels, list of icons available here. pcf.gallery GitHub Repo drivardxrm/IconOptionSet.PCF Display an Optionset with Office UI Fabric icons. Contribute to drivardxrm/IconOptionSet.PCF development by creating an account on GitHub. github.com ","date":"2019-12-04T21:56:04Z","image":"/optionseticons-pcf/image-6.png","permalink":"/optionseticons-pcf/","title":"OptionsetIcons PCF"},{"content":"This image has an empty alt attribute; its file name is image-5.png PCF Gallery Two Options Icons A control to transform a Two Options field with Fabric-UI Icons. List of icons available here. pcf.gallery GitHub Repo drivardxrm/IconTwoOption.PCF Contribute to drivardxrm/IconTwoOption.PCF development by creating an account on GitHub. github.com ","date":"2019-11-20T22:29:03Z","image":"/two-option-icons-pcf/image-5.png","permalink":"/two-option-icons-pcf/","title":"Two Option Icons PCF"},{"content":" PCF Gallery Sparkline A control to render sparkline graphs based on react-sparklines. It takes an array of numbers and several display parameters (color, height, width, type, fill, separator, …). pcf.gallery GitHub Repo drivardxrm/Sparkline.PCF Beautiful and expressive PCF sparkline control based on react-sparklines. - drivardxrm/Sparkline.PCF github.com ","date":"2019-11-11T22:17:00Z","image":"/sparkline-pcf/image-3.png","permalink":"/sparkline-pcf/","title":"Sparkline PCF"},{"content":"PCF Gallery Time Picker A control based on React Time Picker (rc-time-picker). The Time Picker is based on 2 whole number backing fields (hours and minutes). pcf.gallery GitHub Repo drivardxrm/TimePicker.PCF Time Picker PCF Control based on React time Picker (rc-time-picker) - drivardxrm/TimePicker.PCF github.com ","date":"2019-11-04T22:23:48Z","image":"/time-picker-pcf/image-4.png","permalink":"/time-picker-pcf/","title":"Time Picker PCF"}]