Skip to main content

Task Activity Timeline

 

1. Overview

The PCF Calendar Control is a custom PowerApps component that displays activities in a calendar-like view. It supports multiple views (monthly, weekly, yearly, daily), allows users to expand/collapse records for each date, and provides a scrollable interface for better usability. The control is built using TypeScript and CSS, adhering to best practices for type safety and maintainability.

2. Features

View Modes:

  • Monthly View: Groups activities by month.

  • Weekly View: Groups activities by week.

  • Yearly View: Groups activities by year.

  • Daily View: Displays activities for individual days.

Expand/Collapse Functionality:

  • Users can click on a date to expand or collapse its associated records.

  • Smooth animations enhance the user experience.

Scrollable Container:

  • A scrollable container ensures that large datasets are manageable.

Responsive Design:

  • The control adjusts its layout for smaller screens.

Type Safety:

  • The code uses TypeScript interfaces to avoid the use of any and ensure type safety.

Status Indicators:

  • Activities are color-coded based on their status (e.g., Completed, In Progress, Canceled).

3. Prerequisites

To build and deploy the PCF Calendar Control, you need the following tools and dependencies:

3.1 Tools:

  • Node.js: Install Node.js from https://nodejs.org/.

  • Power Platform CLI: Install the Power Platform CLI using the command:

    npm install -g @microsoft/powerplatform-cli
  • Visual Studio Code: Download and install VS Code from https://code.visualstudio.com/.

3.2 Dependencies:

  • Install project dependencies by running:

    npm install

4. Project Structure

The project consists of the following files and folders:

4.1 Files:

  • ActivityTimelineControl.ts:

    • Contains the main logic for the calendar control.

    • Handles data grouping, view modes, and UI interactions.

  • style.css:

    • Defines the styles for the calendar control.

    • Includes animations, responsive design, and hover effects.

  • ControlManifest.Input.xml:

    • Defines metadata for the control, including properties, resources, and dataset bindings.

4.2 Folders:

  • generated: Contains auto-generated TypeScript types for the control's inputs and outputs.

  • out: Stores the compiled output after running the build process.

5. Implementation Details

5.1 TypeScript File (ActivityTimelineControl.ts)

This file contains the core logic for the calendar control. Below is a breakdown of its key components:

5.1.1 Interfaces

interface Record {
    getFormattedValue(fieldName: string): string | undefined;
    getValue(fieldName: string): number | undefined;
}

Defines the structure of the dataset records.

5.1.2 Grouping Logic

Activities are grouped based on the selected view mode:

private groupRecordsByViewMode(): { [key: string]: Record[] } {
    const groupedRecords: { [key: string]: Record[] } = {};

    this.activityDataset.sortedRecordIds.forEach((id) => {
        const record = this.activityDataset.records[id];
        const startDate = record.getFormattedValue("scheduledstart") || "No Start Date";

        let groupKey: string;

        switch (this.currentViewMode) {
            case "monthly":
                groupKey = this.formatMonth(startDate);
                break;
            case "weekly":
                groupKey = this.formatWeek(startDate);
                break;
            case "yearly":
                groupKey = this.formatYear(startDate);
                break;
            case "daily":
                groupKey = this.formatDate(startDate);
                break;
            default:
                groupKey = this.formatMonth(startDate);
        }

        if (!groupedRecords[groupKey]) {
            groupedRecords[groupKey] = [];
        }
        groupedRecords[groupKey].push(record);
    });

    return groupedRecords;
}

5.1.3 Expand/Collapse Functionality

Clicking on a date toggles the visibility of its associated records:

header.addEventListener('click', (event) => {
    const target = event.target as HTMLElement;
    const groupKey = target.getAttribute('data-group');
    const itemsContainer = document.querySelector(`[data-items-for="${groupKey}"]`) as HTMLElement;

    const toggleIcon = target.querySelector('.toggle-icon');
    if (!toggleIcon) return;

    if (itemsContainer.style.maxHeight === "0px" || itemsContainer.style.maxHeight === "") {
        itemsContainer.style.maxHeight = `${itemsContainer.scrollHeight}px`;
        toggleIcon.textContent = "▲";
    } else {
        itemsContainer.style.maxHeight = "0px";
        toggleIcon.textContent = "▼";
    }
});

6. Build and Deployment

6.1 Build the Control

Run the following command to compile the control:

npm run build

6.2 Test Locally

Use the Power Platform CLI to test the control locally:

pac pcf start

6.3 Deploy to Power Apps

Deploy the control to your Power Apps environment:

pac pcf push --publisher-prefix yourprefix

7. Usage Instructions

7.1 Adding the Control to a Form

  • Open the form editor in Power Apps.

  • Add the PCF Calendar Control to the form.

  • Bind the control to a dataset containing activity records.

7.2 Configuring the Control

  • Set the view mode (monthly, weekly, yearly, daily) using the provided buttons.

  • Interact with the calendar by clicking on dates to expand/collapse records.

8. Troubleshooting

8.1 Common Errors

ESLint Validation Errors:

  • Ensure all any types are replaced with specific types.

    const groupedRecords: { [key: string]: Record[] } = {};

Build Failures:

  • Verify that all dependencies are installed (npm install).

  • Check for syntax errors in the TypeScript file.

Deployment Issues:

  • Ensure the publisher prefix matches the one used during deployment.

9. Conclusion

The PCF Calendar Control is a versatile and user-friendly tool for displaying activities in a calendar format. By following the steps outlined in this document, you can successfully build, test, and deploy the control to your Power Apps environment.

If you have further questions or need additional assistance, feel free to reach out!

Comments

Popular posts from this blog

Comparison: Using Workflows vs. JavaScript vs. Plugins in Dynamics CRM?

  There are three ways to automate actions in Microsoft Dynamics CRM: workflows, JavaScript, or plugins. In this blog we will discuss the difference between them and how to choose which option is appropriate for your task. Workflows  can perform tasks such as updating data or sending email. They are triggered by saving records, creating records, or changing specific fields on a form, and once triggered, they run on their own in the background. As you can see in the example of  How to Assign a Territory to a Lead in Dynamics CRM , you can even look up data in another entity. JavaScript  runs on the screen while the user is using a form. JavaScript is triggered by events within the page, updating a field or saving, and it is commonly used to hide or show different fields on the forms. You can also, for instance,  Populate a CRM 2011 Lookup or PartyList Field Using JavaScript  by having a lookup automatically linked to the record based on what is entered in an...

Trigger JavaScript on Click of Button PCF Control

  Overview The TriggerJavascript control is a custom PCF (PowerApps Component Framework) control that renders a button with customizable label, icon, and on-click script execution. The control allows users to dynamically trigger JavaScript code upon clicking the button. Dependencies IInputs, IOutputs from ./generated/ManifestTypes (Auto-generated types from PowerApps) CSS styling from ./CSS/TriggerJavascript.css Class: TriggerJavascript This class implements ComponentFramework.StandardControl<IInputs, IOutputs> and manages rendering a button inside a container, dynamically executing JavaScript code on button click. Properties Private Properties _container: HTMLDivElement - A reference to the container element where the button will be rendered. Methods constructor() Initializes a new instance of the TriggerJavascript control. init(context: ComponentFramework.Context<IInputs>, notifyOutputChanged: () => void, state: ComponentFramework.Dictionary, container: HTMLD...