Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions ImageCrop/ImageCrop/imageCropApp.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import * as React from "react";
import { PcfContextProvider } from "./services/pcfContext";
import { PcfContextService } from "./services/pcfContextService";
import { PcfContextProvider } from "pcf-context-service";
import { PcfContextService } from "pcf-context-service";
import ImageCropControl from "./components/imageCropControl";
import { IImageCropControlProps } from "./types/imageCropTypes";

Expand Down
2 changes: 1 addition & 1 deletion ImageCrop/ImageCrop/services/pcfContext.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@

import * as React from "react";
import { PcfContextService } from './pcfContextService'
import { PcfContextService } from 'pcf-context-service'
// Provides a React context for sharing the PCF context service across the component tree.

// Props for the PcfContextProvider component
Expand Down
3 changes: 2 additions & 1 deletion ImageCrop/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@
"@types/react-dom": "^19.1.6",
"react-dom": "^19.1.0",
"react-image-crop": "^11.0.10",
"uuid": "^11.1.0"
"uuid": "^11.1.0",
"pcf-context-service": "file:../packages/pcf-context-service"
},
"devDependencies": {
"@eslint/js": "^9.25.1",
Expand Down
6 changes: 5 additions & 1 deletion ImageCrop/tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
{
"extends": "./node_modules/pcf-scripts/tsconfig_base.json",
"compilerOptions": {
"typeRoots": ["node_modules/@types"]
"typeRoots": ["node_modules/@types"],
"baseUrl": "./ImageCrop",
"paths": {
"pcf-context-service": ["../packages/pcf-context-service/src"]
}
}
}
2 changes: 1 addition & 1 deletion Scheduler/Scheduler/hooks/useAvailableViews.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { SCHEDULER_VIEWS } from "../types/schedulerViews";
import { getLocalizedViewName } from "../utils/localization";
import { DEFAULT_VIEW_NAMES } from "../utils/constants";
import { SchedulerData } from "react-big-schedule";
import { PcfContextService } from "../services/pcfContextService";
import { PcfContextService } from "pcf-context-service";
import { SchedulerAction } from "../types";

export function useAvailableViews(
Expand Down
2 changes: 1 addition & 1 deletion Scheduler/Scheduler/hooks/useDayViewOptions.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { useEffect, useState } from "react";
import { SchedulerData } from "react-big-schedule";
import { PcfContextService } from "../services/pcfContextService";
import { PcfContextService } from "pcf-context-service";
import { SchedulerAction } from "../types";

export interface DayViewOptions {
Expand Down
2 changes: 1 addition & 1 deletion Scheduler/Scheduler/hooks/useDisplayWeekend.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { useEffect, useState } from "react";
import { SchedulerData } from "react-big-schedule";
import { PcfContextService } from "../services/pcfContextService";
import { PcfContextService } from "pcf-context-service";
import { SchedulerAction } from "../types";

/**
Expand Down
2 changes: 1 addition & 1 deletion Scheduler/Scheduler/hooks/useNonWorkingTimeColors.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { secureHeapUsed } from "crypto";
import { useEffect, useState } from "react";
import { SchedulerData } from "react-big-schedule";
import { PcfContextService } from "../services/pcfContextService";
import { PcfContextService } from "pcf-context-service";
import { SchedulerAction } from "../types";

export interface NonWorkingTimeColors {
Expand Down
2 changes: 1 addition & 1 deletion Scheduler/Scheduler/hooks/useResourceNameHeader.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { useState, useEffect } from "react";
import { SchedulerData } from "react-big-schedule";
import { getLocalizedResourceName } from "../utils/localization";
import { PcfContextService } from "../services/pcfContextService";
import { PcfContextService } from "pcf-context-service";
import { SchedulerAction } from "../types";

export function useResourceNameHeader(
Expand Down
2 changes: 1 addition & 1 deletion Scheduler/Scheduler/hooks/useSchedulerDate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { useState, useEffect } from "react";
import { SchedulerData } from "react-big-schedule";
import { Event, SchedulerAction } from "../types/schedulerTypes";
import { parseDateOnly } from "../utils/formattingHelpers";
import { PcfContextService } from "../services/pcfContextService";
import { PcfContextService } from "pcf-context-service";

export function useSchedulerDate(
pcfContext: PcfContextService,
Expand Down
2 changes: 1 addition & 1 deletion Scheduler/Scheduler/hooks/useSchedulerView.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { useState, useEffect } from "react";
import { getViewByName, View } from "../types/schedulerViews";
import { SchedulerData } from "react-big-schedule";
import { Event, SchedulerAction } from "../types/schedulerTypes";
import { PcfContextService } from "../services/pcfContextService";
import { PcfContextService } from "pcf-context-service";

export function useSchedulerView(
pcfContext: PcfContextService,
Expand Down
2 changes: 1 addition & 1 deletion Scheduler/Scheduler/hooks/useShowHeader.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { useState, useEffect } from "react";
import { SchedulerData } from "react-big-schedule";
import { PcfContextService } from "../services/pcfContextService";
import { PcfContextService } from "pcf-context-service";
import { SchedulerAction } from "../types";

export function useShowHeader(
Expand Down
2 changes: 1 addition & 1 deletion Scheduler/Scheduler/hooks/useWorkWeekDays.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { useState, useEffect } from "react";
import { SchedulerData } from "react-big-schedule";
import { Event, SchedulerAction } from "../types/schedulerTypes";
import { PcfContextService } from "../services/pcfContextService";
import { PcfContextService } from "pcf-context-service";

/**
* Returns an array of day numbers representing the work week range,
Expand Down
4 changes: 2 additions & 2 deletions Scheduler/Scheduler/schedulerApp.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import * as React from "react";
import { PcfContextProvider } from "./services/pcfContext";
import { PcfContextService } from "./services/pcfContextService";
import { PcfContextProvider } from "pcf-context-service";
import { PcfContextService } from "pcf-context-service";
import SchedulerControl from "./components/scheduler";
import { DndProvider } from 'react-dnd';
import { HTML5Backend } from 'react-dnd-html5-backend';
Expand Down
2 changes: 1 addition & 1 deletion Scheduler/Scheduler/services/pcfContext.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@

import * as React from "react";
import { PcfContextService } from './pcfContextService'
import { PcfContextService } from 'pcf-context-service'
// Provides a React context for sharing the PCF context service across the component tree.

// Props for the PcfContextProvider component
Expand Down
12 changes: 6 additions & 6 deletions Scheduler/Scheduler/test/testApp.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@ import * as React from "react";
import { DndProvider } from "react-dnd";
import { HTML5Backend } from "react-dnd-html5-backend";
import SchedulerControl from "../components/scheduler";
import { PcfContextProvider } from "../services/pcfContext";
import { PcfContextService } from "../services/pcfContextService";
import { MockPCFContext } from "../mocks/MockPCFContext";
import { MockPCFParameters } from "../mocks/MockPCFParameters";
import { MockPCFMode } from "../mocks/MockPCFMode";
import { MockPCFDataSet } from "../mocks/MockPCFDataSet";
import { PcfContextProvider } from "pcf-context-service";
import { PcfContextService } from "pcf-context-service";
import { MockPCFContext } from "pcf-mocks";
import { MockPCFParameters } from "pcf-mocks";
import { MockPCFMode } from "pcf-mocks";
import { MockPCFDataSet } from "pcf-mocks";
import { ISchedulerControlProps } from "../types";

// Use the new mock context for testing
Expand Down
4 changes: 3 additions & 1 deletion Scheduler/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,9 @@
"react-dnd": "^14.0.5",
"react-dnd-html5-backend": "^14.0.5",
"react-dom": "^18.3.1",
"uuid": "^11.1.0"
"uuid": "^11.1.0",
"pcf-context-service": "file:../packages/pcf-context-service",
"pcf-mocks": "file:../packages/pcf-mocks"
},
"devDependencies": {
"@eslint/js": "^9.17.0",
Expand Down
9 changes: 7 additions & 2 deletions Scheduler/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,15 @@
"compilerOptions": {
"typeRoots": [
"node_modules/@types"
],
],
"allowSyntheticDefaultImports": true,
"esModuleInterop": true,
"jsx": "react-jsx"
"jsx": "react-jsx",
"baseUrl": "./Scheduler",
"paths": {
"pcf-context-service": ["../../packages/pcf-context-service/src"],
"pcf-mocks": ["../../packages/pcf-mocks/src"]
}
},
"exclude": ["./out"]
}
6 changes: 6 additions & 0 deletions packages/pcf-context-service/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"name": "pcf-context-service",
"version": "0.1.0",
"main": "src/index.ts",
"types": "src/index.ts"
}
2 changes: 2 additions & 0 deletions packages/pcf-context-service/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './pcfContextService';
export * from './pcfContext';
29 changes: 29 additions & 0 deletions packages/pcf-context-service/src/pcfContext.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@

import * as React from "react";
import { PcfContextService } from './pcfContextService'
// Provides a React context for sharing the PCF context service across the component tree.

// Props for the PcfContextProvider component
interface PcfContextProviderProps {
pcfcontext: PcfContextService;
children: React.ReactNode;
}


// Create a React context for the PCF context service
const PcfContext = React.createContext<PcfContextService>(undefined!)

// Provider component for the PCF context service
export const PcfContextProvider = ({ pcfcontext, children }: PcfContextProviderProps) => {
return (
<PcfContext.Provider value={pcfcontext}>
{children}
</PcfContext.Provider>
)
}


// Custom hook to access the PCF context service
export const usePcfContext = () => {
return React.useContext(PcfContext);
}
176 changes: 176 additions & 0 deletions packages/pcf-context-service/src/pcfContextService.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
//import { Theme } from "@fluentui/react-components";
import { IInputs } from "../generated/ManifestTypes";


// Props for constructing a PcfContextService instance
export interface IPcfContextServiceProps {
context: ComponentFramework.Context<IInputs>;
instanceid: string;
height: number;
}


// Maximum width for small form factor (e.g., phone)
const SmallFormFactorMaxWidth = 350;


// Enum for supported form factors
const enum FormFactors {
Unknown = 0,
Desktop = 1,
Tablet = 2,
Phone = 3,
}


// Interface for context info (entity type and ID)
interface ContextInfo {
entityTypeName: string;
entityId: string;
}


// Service for accessing and managing PCF context and environment details
export class PcfContextService {
instanceid: string;
context: ComponentFramework.Context<IInputs>;
//theme: Theme;
formFactor: string;
height: number;

/**
* Construct a new PcfContextService
* @param props - context, instanceid, and height for the control
*/
constructor(props: IPcfContextServiceProps) {
this.instanceid = props.instanceid;
this.context = props.context;
//this.theme = this.getTheme();
this.formFactor =
props.context.client.getFormFactor() == (FormFactors.Phone as number) ||
props.context.mode.allocatedWidth < SmallFormFactorMaxWidth
? "small"
: "large";
this.height = props.height;
}


/**
* Update the context reference (e.g., on re-render)
*/
updateContext(context: ComponentFramework.Context<IInputs>) {
this.context = context;
}

/**
* Returns true if the control is running in the Power Apps designer
*/
public inDesignMode(): boolean {
// Previously only handled commercial cloud.
// Updated to also handle GCC, GCC High, and DoD maker portal URLs.
const designModeUrls = [
"make.powerapps.com",
"make.gov.powerapps.us", // GCC
"make.high.powerapps.us", // GCC High
"make.apps.appsplatform.us", // DoD
];
const currentUrl = window.location.href;
return designModeUrls.some((url) => currentUrl.includes(url));
}

/**
* Returns true if the control is running in a Canvas app
*/
public isCanvasApp(): boolean {
return this.context.mode.allocatedHeight !== -1;
}

/**
* Returns true if the control is disabled
*/
public isControlDisabled(): boolean {
// Return the control's disabled state from the context
return this.context.mode.isControlDisabled;
}

/**
* Returns true if the control is visible
*/
public isVisible(): boolean {
return this.context.mode.isVisible;
}

// public getTheme(): Theme {
// const defaultTheme: Theme = this.context.fluentDesignLanguage
// ?.tokenTheme as Theme;
// return this.isControlDisabled() && !this.isCanvasApp()
// ? {
// ...defaultTheme,
// colorCompoundBrandStroke: defaultTheme?.colorNeutralStroke1,
// colorCompoundBrandStrokeHover: defaultTheme?.colorNeutralStroke1Hover,
// colorCompoundBrandStrokePressed:
// defaultTheme?.colorNeutralStroke1Pressed,
// }
// : defaultTheme;
// }

/**
* Returns the entity type name from the context (model-driven only)
*/
public getEntityTypeName(): string {
// @ts-expect-error Assert contextInfo to a known type.
const contextInfo = this.context.mode.contextInfo as ContextInfo;
return contextInfo.entityTypeName;
}

/**
* Returns the entity ID from the context (model-driven only)
*/
public getEntityId(): string {
// @ts-expect-error Assert contextInfo to a known type.
const contextInfo = this.context.mode.contextInfo as ContextInfo;
return contextInfo.entityId;
}

// Returns the base URL for the current context in Model-driven apps only.
// In Canvas apps, this will be undefined.
/**
* Returns the base URL for the current context (model-driven only)
*/
public getBaseUrl(): string | undefined {
if (this.isCanvasApp()) {
return undefined;
} else {
// @ts-expect-error context is available in model apps
return this.context.page.getClientUrl();
}
}

/**
* Returns a localized string from the context resources
*/
public getResourceString(key: string): string {
return this.context.resources.getString(key) || key;
}

// If the pcf is in full page mode such as when it's being loaded through the sitemap
// this will return any parameters that were passed in the URL.
/**
* Returns a parameter from the full page URL (model-driven only)
*/
public getFullPageParam(key: string): string {
// @ts-expect-error fullPageParam is available in full page mode
const configuration = this.context.mode.fullPageParam as Record<
string,
string
>;
if (configuration) {
const pageParam = configuration[key];
if (pageParam && typeof pageParam === "string") {
return pageParam; // Return the raw value if it exists and is a string
}
}
// Return an empty string if the key doesn't exist or the value is invalid
return "";
}
}
Loading