GitHub : Export issues to a CSV file

In this article, let’s see how to export GitHub issues to a CSV file using the Git CLI.

The steps I am going to show you are tailored for a Windows machine, but the steps for non-Windows machines are mostly the same. I will also share the official documentation link in case you encounter any issues.

Lets get started with the steps.

Install the GitHub CLI:

  • Refer to this documentation for steps to install CLI on various OS. Since I’m using Windows OS, if you’re a Windows user, follow along.
  • Open the command prompt and execute following command:
winget install --id GitHub.cli

  • Note : Make sure you close and open the terminal again. Simply opening a new tab will not be sufficient.

After installing the CLI, the next step is to complete authentication.

Authenticate with GitHub account:

  • Execute the following command to start the authentication process.
gh auth login
  • Select the options and keep pressing Enter button.
  • You will be presented with a one-time code.
  • Press Enter again, which will open a browser window asking for the code.
  • Enter the code copied from the command prompt, and then press Continue
  • In the next screen, click on Authorize github
  • You will be redirected to the following success screen.
  • Go back to the command bar, and you will see the message as below.

Now that we have completed the authentication, we can proceed with exporting issues to CSV.

Export the issues to csv:

  • Open the official documentation to understand the syntax of gh issue list command, where you can apply filters to narrow down the list.
  • In my scenario, I want to export all the issues with the ‘Documentation’ label. Hence, I executed the following command:
gh issue list --label "documentation" -R <github_project-name> --limit 1000
  • Note : If you don’t provide –limit, by default you get only 30 items.
  • The above command will fetch and display the list of issues within the command prompt, as shown below.
  • To store the list in a CSV file, execute the following command:
gh issue list --label "documentation" -R microsoft/coe-starter-kit --limit 1000 > Documentation_Issues.csv
  • A CSV file with the list of issues is generated in the command execution path.

Hope you understand the steps to download the issues using the GitHub CLI.

🙂

Categories: Git Tags: , ,

[Beginners] Power Fx: ShowColumns, AddColumns, RenameColumns and DropColumns

ShowColumns, AddColumns, RenameColumns and DropColumns are Power Fx functions which helps you to shape your collection. In this article, I will try to explain these functions with a simple scenario.

Scenario:

  • Create a new Canvas App.
  • Add a Dataverse Contact table as a Canvas App DataSource
  • Read the Contact table to a Collection and by default, all the columns of the Contact table are added to the Collection.
  • We will shape the collection to keep only the required columns.
  • Add a new column ‘Fullname’ to the collection.
  • Rename columns and remove unwanted columns.

Let’s get started and execute our scenario by building a simple Canvas App.

Steps to create the canvas App:

  • Create a new Canvas App and add a Contact Dataverse table as Datasource.
  • On App > OnStart write following formula to read the Contact table records in to a collection collContact.
Collect(
    collContact,
    Contacts
);
  • Execute the Run OnStart and check the collContact records, which contain all the columns of the Contact table.
  • Let’s say we only need to add the following highlighted columns to the collContact collection. We can use the ShowColumns function.

Using ShowColumns function:
  • The syntax of ShowColumns function is as follows:
ShowColumns( Table, ColumnName1 [, ColumnName2, ... ] )

- Table - Required. Table to operate on.
- ColumnName(s) - Required. Names of the columns to include.
  • Let’s see how we can achieve our requirement of adding only specific Contact table columns to the collContact collection.
  • Add following formula in App > OnStart
Collect(
    collContact,
    ShowColumns(
        Contacts,
        'First Name',
        'Middle Name',
        'Last Name',
        Email,
        'Mobile Phone'
    )
);
  • Execute the Run OnStart, and check the collContact records.
  • The collContact collection will only have the columns you want. That’s the use of the ShowColumns function.

Using AddColumns function:
  • The collContact collection now shows the firstname, lastname and middlename columns as below.
  • How about creating a new column ‘Fullname’ by joining firstname, lastname, and middlename columns? Let’s see how to achieve that using AddColumns.
  • Following is the syntax of AddColumns.
AddColumns( Table, ColumnName1, Formula1 [, ColumnName2, Formula2, ... ] )

  - Table - Required. Table to operate on.
  - ColumnName(s) - Required. Names of the columns to add.
  - Formula(s) - Required. Formulas to evaluate for each record. The result is added as the value of the corresponding new column. You can reference other columns of the table in this formula.
  • Let’s achieve our requirement by updating the previous formula with the following formula:
Collect(
    collContact,
    AddColumns(
        ShowColumns(
            Contacts,
            'First Name',
            'Middle Name',
            'Last Name',
            Email,
            'Mobile Phone'
        ),
        Fullname,
        firstname & " " & middlename & " " & lastname
    )
);
  • Execute the Run OnStart and check the collContact records. collContact collection will now have a new Fullname column.

Using RenameColumn function:
  • If you notice, the column names of the collContact collection are not intuitive. Lets rename the columns using the RenameColumns function.
  • Following is the syntax of RenameColumns function.
RenameColumns( Table, OldColumnName1, NewColumnName1 [, OldColumnName2, NewColumnName2, ... ] )

  - Table - Required. Table to operate on.
  - OldColumnName(s) - Required. Names of the columns to rename from the original table. 
  - NewColumnName(s) - Required. Replacement names. 
  • Lets achieve our requirement by updating the previous formula with the following formula:
Collect(
    collContact,
    RenameColumns(
        AddColumns(
            ShowColumns(
                Contacts,
                'First Name',
                'Middle Name',
                'Last Name',
                Email,
                'Mobile Phone'
            ),
            Fullname,
            firstname & " " & middlename & " " & lastname
        ),
        emailaddress1,
        'Email Address',
        firstname,
        'First Name',
        middlename,
        'Middle Name',
        mobilephone,
        'Mobile Number'
    )
);
  • Execute the Run OnStart and check the collContact records. collContact collection will now have the new column names.

Using DropColumns function:
  • The collContact collection looks as below after applying above formulas.
  • How about removing ‘First Name’, ‘Middle Name and ‘lastname’ from the collContact collection, since we already have the ‘Fullname’ column? Let’s drop the columns using the DropColumns function.
  • Following is the syntax of DropColumns:
DropColumns( Table, ColumnName1 [, ColumnName2, ... ] )

  - Table - Required. Table to operate on.
  - ColumnName(s) - Required. Names of the columns to drop.
  • Lets achieve our requirement by updating formula as below:
Collect(
    collContact,
    DropColumns(
        RenameColumns(
            AddColumns(
                ShowColumns(
                    Contacts,
                    'First Name',
                    'Middle Name',
                    'Last Name',
                    Email,
                    'Mobile Phone'
                ),
                Fullname,
                firstname & " " & middlename & " " & lastname
            ),
            emailaddress1,
            'Email Address',
            firstname,
            'First Name',
            middlename,
            'Middle Name',
            mobilephone,
            'Mobile Number'
        ),
        'First Name',
        'Middle Name',
        lastname
    )
);
  • Execute the Run OnStart and check the collContact records. collContact collection will not have the ‘First Name’, ‘Middle Name and ‘lastname’ columns.

Hope you understand the basics of ShowColumns, AddColumns, RenameColumns and DropColumns functions.

🙂

[Tip] Stick a control to the right side of the Parent

I have a button added to a Gallery control, and I want it to always be positioned to the right side of the gallery.

So, as shown below, I set the X property of the button control to a specific number, which positioned the button to appear on the right side of the gallery.

However, when I play the app and change the resolution, the button moves to the left, which is understandable since we provided a static X property.

To stick the button to the right of the Gallery/Containers, use the following formula:

X : Parent.Width - {current-control-id}.Width

You can even test the custom page on the Model-Driven App, and the button will always stick to the right.

🙂

Categories: Canvas Apps Tags: ,

[Tip] Dataverse | Quickly copy column’s Logical and Schema names

Did you know that you can quickly copy the columns Logical and Schema names from the column’s context menu?

  • Open a Solution and select the Table
  • Go to Columns and select a column > Advanced > Tools
  • Use either Copy schema name or Copy logical name to copy.

🙂

Categories: CRM

Power Automate | Insert a new option for a global or local option set (Choice) field

In this article, let’s learn how to insert a new option for a global or local option set using the InsertOptionValue unbound action in Power Automate.

Create new option in global choices field:

  • I have a global option set (i.e., Choice) field by name ‘Location’
  • To add the new option ‘Delhi’ to the option set, use the following properties. Set the label in the following JSON format. Here :
    • Label : Optionset label text.
    • LanguageCode : 1033 is language code for English.
{
  "LocalizedLabels": [
    {
      "Label": "Delhi",
      "LanguageCode": 1033
    }
  ]
}
  • After saving, test the flow. This should create a new option named ‘Delhi’ in the global option set.

Now lets see how to create new option in local choice field.

Create new choice in local choice field:

  • I’ve a local option set by name ‘Favorite Sports’ in my table ‘Employee’.
  • To insert new option ‘Football’ in the ‘Favorite Sports’ local option set, use following properties. Set the Label in the following json format.
  • After saving and testing the flow, a new option named ‘Football’ will be created in the local option set.

That’s it! I hope you’ve learned how to create options in both global and local option sets using Power Automate.

🙂

Categories: CRM

Microsoft Adoption | Sample solution gallery

Imagine you’re new to Power Platform and eager to learn from others’ experiences in app development. Did you know that you can explore and download amazing apps/solutions of others from a sample gallery?

Go to Microsoft Adoption portal and navigate to Solutions > Sample Solution Gallery.


Let’s discover how to explore and find a Power Apps solution, then put it to use.

Steps to find a Power App solution and download:

  • Open the Microsoft Adoption portal and navigate to Solutions > Sample Solution Gallery
  • Filter by Products > Power Apps
  • Select the app you’re interested in and navigate to its GitHub page.
  • Review the selected app’s summary from the README.md file.
  • Download the solution and install it in your environment.
  • Likewise, you can also find sample solutions for other Microsoft products.

Happy exploring 🙂

Power Automate | Achieve transaction and rollbacks using Changeset request

Imagine a scenario where you need to perform the following actions as a transaction: if any operation fails, all completed operations should be rolled back.

  • Create an Account record.
  • Create a Contact record by setting the Contact.CompanyName as Account created in previous step.

To achieve this scenario in Power Automate, we can utilize the Perform a changeset request action. However, it’s not straightforward, and I’ll explain why.

Lets first understand Perform a changeset request action before proceeding with our scenario.

Perform a changeset request:

  • Change sets provide a way to bundle several operations that either succeed or fail as a group.
  • When multiple operations are contained in a changeset, all the operations are considered atomic, which means that if any one of the operations fails, any completed operations are rolled back.

Now lets configure the flow with Perform a changeset request action to achieve our scenario.

Configure flow using Perform a changeset request action:

  • Create a new Instant flow
  • Add a Initialize variable action and set Value as guid() expression.
    • If you are wondering why we need a new GUID, you’ll find out by the end of this post.
variables('vAccountId')
  • In the second Add a new row action, set ‘Table name’ as ‘Contacts’ and set ‘Company Name (Accounts)’ column as :
accounts(variables('vAccountId'))
  • Once configured, flow looks as below.
  • Save and test the flow.
  • After the flow run, you’ll see a new Account created along with the child Contact record.
  • Now, to test the rollback behavior of the Perform a changeset request action, let’s intentionally fail the Contact creation action and observe if it also rolls back the completed Account creation.
  • To intentionally fail the Contact creation, I’m setting a non-existing GUID in the ‘Company Name (Contacts)’ field.
  • Save and Test the flow.
  • After the flow run, you’ll notice that it failed with the message ‘Entity ‘Contact’ With Id = xxxx-xxx-xxx-xxxx Does Not Exist’. This occurred because we intentionally passed a non-existing GUID. Additionally, the ‘Create Account’ action was skipped, which demonstrates that the Perform a changeset request action ensures that if any operation fails, any completed operations will be rolled back.

Now that we understand how the Perform a changeset request action behaves, let’s also explore why I had to use pre-generated GUID in our flow.

Reason for using a pre-generated GUID in our flow:

Perform a changeset request action has following limitation:

  • We can’t reference an output of a previous action in the changeset scope.
  • In the changeset scope, you see that there are no arrows between each of the actions, indicating that there aren’t dependencies between these actions (they all run at once).

In our scenario for creating Accounts and Contacts, if we don’t use pre-generated GUIDs, we can’t get the platform-generated ‘Account GUID’ from the ‘Create Account’ step to pass it to the ‘Create Contact’ step.

So, I had to use the prepopulated GUID in both the ‘Create Account’ and ‘Create Contact’ steps to work around the limitation with the Perform a changeset request action.

That’s all for this post. I hope you now understand how to use the Perform a changeset request action.

🙂

Power Automate | Dataverse | Create row by setting lookup column with ‘Key’

Imagine you’re in the midst of creating a Contact record in Cloud Flow using Dataverse > Add a new row action. You can easily set the ‘Company Name’ field, which is a lookup, with the syntax: accounts({account_guid}), as shown below.

Did you know that instead of parent record’s GUID, you can also use the Alternate Key to set the look up column?. In this article, let’s learn how to set the lookup column using Alternate Key.

What is an Alternate Key:

  •  With alternate keys you can now define a column in a Dataverse table to correspond to a unique identifier (or unique combination of columns) used by the external data store.
  • This alternate key can be used to uniquely identify a row in Dataverse in place of the primary ke (i.e., GUID).

Steps to Create a Key:

To create an alternate key in Account table,

  • Navigate to Account > Keys
  • Click on New Key and choose column as shown below. I’ve chosen Account Number column.
  • Click on Save

  • Wait for some time until the status changes to Active.
  • Now, go ahead and create a new Account record with ‘Account Number’. Copy the value of the ‘Account Number’ (i.e., 989898) which we will be using in the flow.

Now that we have created an alternate key in the Accounts table and added a new Account record, let’s proceed with creating a flow to generate a Contact record using the account’s alternate key.

Create a flow:

  • Create an Instant Flow.
  • Add Dataverse > Add a new row action.
  • Set the ‘Company Name’ lookup column to accounts(accountnumber=’989898‘). Here is an explanation of the syntax.
    • accounts : Schema name of ‘Account’ table.
    • accountnumber : The logical name of the column configured in Keys.
      • Since we configured the ‘Account Number’ column in ‘Keys’, use ‘accountnumber’, which is the logical name of the ‘Account Number’ column.
    • 989898 : Account Number value of the Account record.
  • Save and Test the flow. You will notice that the Add a new row action succeeds.
  • Open the Contact record in Dataverse, and you will notice the Account Name look up is set with the ‘Contoso Ltd’ Account.

Hope you learned about using alternate keys while setting up lookup columns in flows.

🙂

Categories: CRM Tags: ,

[Tip] Useful Free Web APIs to Use in Your Apps

I stumbled upon these two fantastic free web APIs that you can use to test your applications/flows.

Bored API:

  • If you need a API to quick test your application, try the https://www.boredapi.com/api/activity/
  • This awesome GET Web API delivers a random JSON response every time you hit the endpoint, as shown below!
  • I can instantly test the connector using the Test option.

httpstat.us API:

  • It’s useful for testing how your own Apps/Flows deal with varying responses.
  • Let’s say you’ve built an app that consumes APIs, and you want to unit test the app with various types of API response codes. In that case, https://httpstat.us/ is your friend.

🙂

Categories: Power Platform Tags:

Power Apps Component Framework (PCF) | Create React (virtual) code component.

April 11, 2024 1 comment

In 2020, I created the PCF Beginner Guide post, which explains the basics of Power Apps component framework. Since then, there have been numerous changes to the framework, prompting me to write another blog post on React based virtual code components.

Please note that if you are familiar with the term ‘PCF Component’ but not ‘Code Component,’ they both refer to the same concept. I will be using ‘Code Component’ terminology throughout this post.

In this blog post, I will cover the following topics:

  • What is a Standard code component
  • What is a React based virtual code component
  • Differences between React based virtual code component and standard components
  • Scenario
  • Demo : Creating a React code component and deploying to Dataverse

Lets get started.

What is Standard code component:

  • Standard code components are standard html control types.
  • Controls are allocated an HtmlDivElement in it’s init lifecycle method and mounts its UX/UI inside the allocated Div directly working on DOM.
  • Please refer to this article for a detailed understanding of standard components.

What is a React based virtual code component:

  • Virtual or React based virtual code components are built using the React framework.
    • React apps are made out of components.
    • A component is a piece of the UI (user interface) that has its own logic and appearance
  • React (virtual) controls provide a new pattern optimized for using React library in code components.
  • If you are not clear at this point, don’t worry; you will understand during the next sections.

Differences Between React based virtual code component and Standard code components:

  • Virtual code components can have performance gains which are at par with some of the 1st party controls.
  • You can expect much better performance across web and mobile, especially on slower networks.
  • Following are some high-level numbers comparing standard and virtual versions of FacePile control on development machine.
  • As you can see from the statistics above, in React-based code components, the React and Fluent libraries aren’t included in the package because they’re shared. Therefore, the size of bundle.js is smaller.

Now that you have the basics of both Standard and React code components, let’s proceed with our scenario and demo.

Scenario:

  • We will be building a simple React component with a ‘Label’ control, which animates the text from left to right.
  • Our React component takes 4 parameters
    • textcontent
    • fontsize
    • fontcolor
    • animationpace

Now we have the scenario, lets get started with building the component. Please ensure that the prerequisites mentioned here are fulfilled before proceeding with the next steps.

Steps to create a React component project:

  • Create an empty folder as shown below.
  • Open the VSCode editor. Navigate to the newly created folder mentioned above and open a new terminal, which should appear as shown below.
  • Create a new ‘React Code Component’ project by executing the pac pcf init command with --framework parameter set to react.
pac pcf init --namespace LearnReactPCF --name animatedtextreactcontrol --template field --framework react -npm

  • Above pac pcf init command may take a few seconds to complete execution. Once finished, you will see folders rendered as shown below. You can safely ignore any warnings and proceed with the next steps.

Understand the files of the project:

“Let’s understand the files that were created and the changes made in the index.ts file compared to a standard code component project.

  • A new React class component file HelloWorld.tsx gets created, by default returns a simple ‘Label’ control.
  • In the index.ts file, The ReactControl.init method for control initialization doesn’t have <div> parameters because React controls don’t render the DOM directly.
  • Instead ReactControl.updateView returns a ReactElement that has the details of the actual control in React format.

  • An important thing to notice is that an interface IHelloWorldProps will be available in both HelloWorld.tsx and index.ts files. This interface helps you to pass parameters to the react component, which you will see in next sections.

Now that we’ve understood the files and key points, let’s proceed with executing our scenario.

As mentioned in the Scenario section, our animation text component will have four parameters. Let’s start by defining these parameters in the ControlManifest.Input.xml file.

Define properties in ControlManifest.Input.xml file:
  • Open the ControlManifest.Input.xml file, delete the default ‘sampleproperty’ node, and add our four parameters (i.e., textcontent,fontsize,fontcolor,animationpace) as shown below.
     <property name="textcontent" display-name-key="textcontent" description-key="content to be displayed" of-type="SingleLine.Text" usage="bound" required="true" />
    <property name="fontsize" display-name-key="fontsize" description-key="fontsize" of-type="SingleLine.Text" usage="input" required="true" />
    <property name="fontcolor" display-name-key="fontcolor" description-key="color of the font" of-type="SingleLine.Text" usage="input" required="true" />
    <property name="animationpace" display-name-key="animationpace" description-key="animation pace" of-type="SingleLine.Text" usage="input" required="false" />

Update the ‘IHelloWorldProps’ interface with new properties:

As we added the four new parameters in ControlManifest.Input.xml file, we need to update the IHelloWorldProps interface with new properties in both HelloWorld.tsx and index.ts files.

  • Open the index.ts file and update the IHelloWorldProps interface with following code block.
    const props: IHelloWorldProps = { 
        content: context.parameters.textcontent.raw, 
        fontsize: context.parameters.fontsize.raw,
        color: context.parameters.fontcolor.raw, 
        animationpace: context.parameters.animationpace.raw
    };
  • Next, open the HelloWorld.tsx file and update the IHelloWorldProps interface with following code block.
export interface IHelloWorldProps {
  content?: any;
  fontsize?: any;
  color?: any;
  animationpace?: any;
}

Render the animated control in the react component:

Now that we defined properties, lets read the property values and render our React component.

  • Open the HelloWorld.tsx file and replace the default ‘Label’ render logic with below code block.
    • In the below code, we have mapped all the four properties from this.props to four constants.
    • Next, we defined labelStyle constant with the styling which we have used in <Label style={labelStyle}>
    • Finally we are returning the <Label> control using return. This is a standard React component behavior, if you are familiar with React framework.
    const { content, fontsize, color, animationpace = '5s' } = this.props;
    const labelStyle = {
      fontSize: fontsize,
      color: color,
      animation: `moveLeft ${animationpace} linear infinite`
    };

    return (
      <Label style={labelStyle}>
        {content}
      </Label>
    )
  • Notice that we are using ‘moveLeft‘ css class to achieve the animated effect. To do this, we need to add a new .css file to our project and define the ‘moveLeft‘ class in it.
Add a new .css file:
  • If you open the ControlManifest.Input.xml file, under <resources> node, you will find a commented-out line for the <css> node. Uncomment the line as shown below. Your <resources> node should look like the following:”
    <resources>
      <code path="index.ts" order="1"/>
      <platform-library name="React" version="16.8.6" />
      <platform-library name="Fluent" version="8.29.0" />
      <css path="css/animatedtextreactcontrol.css" order="1" />
      <!-- UNCOMMENT TO ADD MORE RESOURCES
      <resx path="strings/animatedtextreactcontrol.1033.resx" version="1.0.0" />
      -->
    </resources>

  • Now that we’ve uncommented the <css> node, our application expects a new animatedtextreactcontrol.css file under css folder.
  • Create a new folder named ‘css’ and add a new file named ‘animatedtextreactcontrol.css’. Then, add the following CSS content to the file:
@keyframes moveLeft {
    0% {
      transform: translateX(0);
    }
    100% {
      transform: translateX(100%);
    }
  }

We are good with configuring the properties and rendering the component. Its time to test.

Build and Test the control:
  • Build the project by trigger the npm run build command and ensure that it returns ‘Succeeded’ to confirm successful completion.
  • Next trigger npm start watch command to test the control.
  • The npm start watch command opens a browser window where you can test the control by providing values to its properties directly in the browser interface.

Packaging the code components:

Now that we built and tested the react virtual control, lets package it in to a solution which enables us to transport the the control to Dataverse.

  • Create a new folder named Solutions inside the AnimatedText folder and navigate into the folder.
  • Create a new Dataverse solution project by triggering the pac solution init command.
    • The publisher-name and publisher-prefix values must be the same as either an existing solution publisher, or a new one that you want to create in your target environment.

pac solution init –publisher-name Rajeev –publisher-prefix raj

  • After executing the above ‘pac solution init’ command, a new Dataverse solution project with a .cdsproj extension is created
  • Now, we need to link our ‘react code component’ project location (i.e., pcfproj file location) to the newly created Dataverse solution project using pac solution add-reference command.

pac solution add-reference –path D:\Practice\PCFSamples\AnimatedText

  • We left with one last pac cli command. Generate the Dataverse solution file, trigger following msbuild command.
msbuild /t:build /restore

  • Post successful build, generated Dataverse solution zip file will be located in the Solutions\bin\debug folder.
    • Note that the solution zip file name will be same as the root folder (i.e., Solutions)

As we successfully built the control and generated a Dataverse solution, lets import the solution to an environment and test the control using a Canvas app.

Import the solution to Dataverse:

  • Connect to the Power Apps Maker portal.
  • Select an environment and import the generated solution.
  • Post the solution import, open the solution and click on Publish all customizations.

Test the component in Canvas App:

  • Lets create a new Canvas app to test our react code component.
  • From the new Canvas app, import our react code component as shown below.
  • Test the control with different parameter values as shown below.

Test the component in Model Driven App (MDA):

We can add our ‘Animated Text’ react component to any of the table’s control. I am going to use Account table to test.

  • Open the Account > Forms > Information form
  • I am going to replace the default Account Name control with our React component.
  • Select the Account Name control and map to our React component as shown below.
  • Now go ahead and specify the properties and click on Done
  • Now, open any of the Account record and you will see the Account Name default control replaced with our animated React component.

That’s it. You can also add this component to Power Pages as well.

Hope you got the basics of creating React Virtual Code Component. Happy learning.

🙂