= (props) => {
8 | // pcfContextService now provides ajax and data functions.
9 | const pcfContextService = new PcfContextService({ context: props.context, instanceid: props.instanceid, updatePrimaryProperty: props.updatePrimaryProperty });
10 |
11 | return (
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 | );
20 | };
21 |
22 | export default PortalFilesApp;
23 |
--------------------------------------------------------------------------------
/PowerPagesFileManager/PowerPagesFileManager/components/HeaderButtons.tsx:
--------------------------------------------------------------------------------
1 | import * as React from "react";
2 | import { Button } from "@fluentui/react-components";
3 | import { getTranslation, LanguageCode, Message } from "../utils/localization";
4 |
5 | export interface IHeaderButtonsProps {
6 | selectedCount: number;
7 | uploadingCount: number;
8 | onDelete: () => void;
9 | onCancel: () => void;
10 | onToggleCollapse: () => void;
11 | language: LanguageCode; // Added language prop
12 | }
13 |
14 | export const HeaderButtons = (props: IHeaderButtonsProps): JSX.Element => {
15 | return (
16 |
17 |
25 |
33 |
40 |
41 | );
42 | };
43 |
44 | export default HeaderButtons;
45 |
--------------------------------------------------------------------------------
/PowerPagesFileManager/PowerPagesFileManager/hooks/useAnnotations.ts:
--------------------------------------------------------------------------------
1 | import { useState, useEffect, useCallback } from "react";
2 | import { IAnnotation } from "../types";
3 | import { usePcfContext } from "../services/PcfContext";
4 | import { annotationService } from "../services/AnnotationService";
5 |
6 | export function useAnnotations() {
7 | const pcfContext = usePcfContext();
8 | const [annotations, setAnnotations] = useState([]);
9 | const [error, setError] = useState("");
10 |
11 | const refreshAnnotations = useCallback(() => {
12 | annotationService
13 | .loadAnnotations(pcfContext.getEntityTypeName(), pcfContext.getEntityId())
14 | .then((result) => {
15 | let updatedAnnotations = result as IAnnotation[];
16 | if (!pcfContext.displayAllFiles) {
17 | updatedAnnotations = updatedAnnotations.map(annotation => ({
18 | ...annotation,
19 | display: false
20 | }));
21 | }
22 | setAnnotations(updatedAnnotations);
23 | return updatedAnnotations;
24 | })
25 | .catch(() => setError("Failed to load files"));
26 | }, []);
27 |
28 | useEffect(() => {
29 | refreshAnnotations();
30 | }, [refreshAnnotations]);
31 |
32 | // Watch for changes in the annotations state and update the primary property
33 | useEffect(() => {
34 | pcfContext.updatePrimaryProperty(
35 | annotations.length > 0 ? annotations.length.toString() : undefined
36 | );
37 | }, [annotations]);
38 |
39 | return { annotations, error, refreshAnnotations, setAnnotations, setError };
40 | }
41 |
--------------------------------------------------------------------------------
/PowerPagesFileManager/PowerPagesFileManager/hooks/useWindowSize.ts:
--------------------------------------------------------------------------------
1 | import { useState, useEffect } from "react";
2 |
3 | export function useWindowSize() {
4 | const [windowSize, setWindowSize] = useState<{ width: number; height: number }>({
5 | width: window.innerWidth,
6 | height: window.innerHeight
7 | });
8 |
9 | useEffect(() => {
10 | const handleResize = () => {
11 | setWindowSize({ width: window.innerWidth, height: window.innerHeight });
12 | };
13 | window.addEventListener("resize", handleResize);
14 | return () => window.removeEventListener("resize", handleResize);
15 | }, []);
16 |
17 | return windowSize;
18 | }
19 |
--------------------------------------------------------------------------------
/PowerPagesFileManager/PowerPagesFileManager/services/PcfContext.tsx:
--------------------------------------------------------------------------------
1 | import * as React from "react";
2 | import { PcfContextService } from './PcfContextService'
3 |
4 | interface PcfContextProviderProps {
5 | pcfcontext: PcfContextService,
6 | children: React.ReactNode
7 | }
8 |
9 | const PcfContext = React.createContext(undefined!)
10 |
11 | export const PcfContextProvider = ({ pcfcontext, children }: PcfContextProviderProps) => {
12 | return (
13 |
14 | {children}
15 |
16 | )
17 | }
18 |
19 | export const usePcfContext = () => {
20 | return React.useContext(PcfContext)
21 | }
22 |
--------------------------------------------------------------------------------
/PowerPagesFileManager/PowerPagesFileManager/types/Annotations.ts:
--------------------------------------------------------------------------------
1 | export interface IAnnotation {
2 | annotationid: string;
3 | filename: string;
4 | createdon: string;
5 | filesize?: number; // NEW property in bytes (optional)
6 | display?: boolean; // NEW property to control visibility (optional)
7 | objectid?: string;
8 | objecttypecode?: string;
9 | }
10 |
11 | export interface IAnnotationsResponse {
12 | value: IAnnotation[];
13 | }
14 |
15 | export interface FileUploadOptions {
16 | onProgress?: (percent: number) => void;
17 | abortSignal?: AbortSignal;
18 | }
--------------------------------------------------------------------------------
/PowerPagesFileManager/PowerPagesFileManager/types/index.ts:
--------------------------------------------------------------------------------
1 | export * from "./Annotations";
2 |
--------------------------------------------------------------------------------
/PowerPagesFileManager/PowerPagesFileManager/utils/constants.ts:
--------------------------------------------------------------------------------
1 | export const AZURE_FILE_EXTENSION = ".azure.txt";
2 |
--------------------------------------------------------------------------------
/PowerPagesFileManager/PowerPagesFileManager/utils/formatDate.ts:
--------------------------------------------------------------------------------
1 | export function formatDate(dateString: string): string {
2 | const date = new Date(dateString);
3 | const year = date.getFullYear();
4 | const month = String(date.getMonth() + 1).padStart(2, '0');
5 | const day = String(date.getDate()).padStart(2, '0');
6 | const hours = String(date.getHours()).padStart(2, '0');
7 | const minutes = String(date.getMinutes()).padStart(2, '0');
8 | return `${year}:${month}:${day} - ${hours}:${minutes}`;
9 | }
10 |
--------------------------------------------------------------------------------
/PowerPagesFileManager/PowerPagesFileManager/utils/index.ts:
--------------------------------------------------------------------------------
1 | export * from "./formatDate";
2 | export * from "./themeGenerator";
3 | export * from "./constants";
4 | export * from "./localization";
5 | export * from "./layouts";
6 |
--------------------------------------------------------------------------------
/PowerPagesFileManager/PowerPagesFileManager/utils/layouts.ts:
--------------------------------------------------------------------------------
1 | export enum Layout {
2 | Horizontal = "Horizontal",
3 | Vertical = "Vertical"
4 | }
5 |
6 | export function getLayout(rawLayout: string): Layout {
7 | // Mapping raw values to a Layout enum; defaults to Vertical
8 | const layoutMap: Record = {
9 | "0": Layout.Vertical,
10 | "1": Layout.Horizontal,
11 | "Vertical": Layout.Vertical,
12 | "Horizontal": Layout.Horizontal
13 | };
14 | return layoutMap[rawLayout] || Layout.Vertical;
15 | }
16 |
--------------------------------------------------------------------------------
/PowerPagesFileManager/Solution/PowerPagesFileManagerSolution/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # msbuild output directories
4 | /bin
5 | /obj
6 |
7 | # MSBuild Binary and Structured Log
8 | *.binlog
9 |
--------------------------------------------------------------------------------
/PowerPagesFileManager/Solution/PowerPagesFileManagerSolution/src/Other/Customizations.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 | 1033
17 |
18 |
--------------------------------------------------------------------------------
/PowerPagesFileManager/Solution/PowerPagesFileManagerSolution/src/Other/Relationships.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/PowerPagesFileManager/eslint.config.mjs:
--------------------------------------------------------------------------------
1 | import eslintjs from "@eslint/js";
2 | import microsoftPowerApps from "@microsoft/eslint-plugin-power-apps";
3 | import pluginPromise from "eslint-plugin-promise";
4 | import globals from "globals";
5 | import typescriptEslint from "typescript-eslint";
6 |
7 | /** @type {import('eslint').Linter.Config[]} */
8 | export default [
9 | {
10 | ignores: ["**/generated/"],
11 | },
12 | eslintjs.configs.recommended,
13 | ...typescriptEslint.configs.recommended,
14 | ...typescriptEslint.configs.stylistic,
15 | pluginPromise.configs["flat/recommended"],
16 | microsoftPowerApps.configs.paCheckerHosted,
17 | {
18 | plugins: {
19 | "@microsoft/power-apps": microsoftPowerApps,
20 | },
21 |
22 | languageOptions: {
23 | globals: {
24 | ...globals.browser,
25 | ComponentFramework: true,
26 | },
27 | parserOptions: {
28 | ecmaVersion: 2020,
29 | sourceType: "module",
30 | projectService: true,
31 | tsconfigRootDir: import.meta.dirname,
32 | },
33 | },
34 |
35 | rules: {
36 | "@typescript-eslint/no-unused-vars": "off",
37 | },
38 | },
39 | ];
40 |
--------------------------------------------------------------------------------
/PowerPagesFileManager/images/PowerPagesFileManager.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rwilson504/PCFControls/61d3085266806324fc5b48150a7a8a8a237eaffa/PowerPagesFileManager/images/PowerPagesFileManager.gif
--------------------------------------------------------------------------------
/PowerPagesFileManager/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "pcf-project",
3 | "version": "1.0.0",
4 | "description": "Project containing your PowerApps Component Framework (PCF) control.",
5 | "scripts": {
6 | "build": "pcf-scripts build",
7 | "clean": "pcf-scripts clean",
8 | "lint": "pcf-scripts lint",
9 | "lint:fix": "pcf-scripts lint fix",
10 | "rebuild": "pcf-scripts rebuild",
11 | "start": "pcf-scripts start",
12 | "start:watch": "pcf-scripts start watch",
13 | "refreshTypes": "pcf-scripts refreshTypes"
14 | },
15 | "dependencies": {
16 | "@fluentui/react-components": "^9.59.0",
17 | "@types/chroma-js": "^3.1.1",
18 | "@types/jquery": "^3.5.32",
19 | "axios": "^1.8.1",
20 | "chroma-js": "^3.1.2",
21 | "react": "^18.0.0",
22 | "react-dom": "^18.0.0",
23 | "uuid": "^11.1.0"
24 | },
25 | "devDependencies": {
26 | "@eslint/js": "^9.17.0",
27 | "@microsoft/eslint-plugin-power-apps": "^0.2.51",
28 | "@types/node": "^18.19.54",
29 | "@types/powerapps-component-framework": "^1.3.15",
30 | "eslint-plugin-promise": "^7.1.0",
31 | "globals": "15.13.0",
32 | "pcf-scripts": "^1",
33 | "pcf-start": "^1",
34 | "typescript": "^4.9.5",
35 | "typescript-eslint": "^8.18.1"
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/PowerPagesFileManager/pcfconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "outDir": "./out/controls"
3 | }
--------------------------------------------------------------------------------
/PowerPagesFileManager/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "./node_modules/pcf-scripts/tsconfig_base.json",
3 | "compilerOptions": {
4 | "typeRoots": ["node_modules/@types"],
5 | "module": "es2015",
6 | "moduleResolution": "node"
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/RestrictedChoice/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 |
6 | # generated directory
7 | **/generated
8 |
9 | # output directory
10 | /out
11 |
12 | # msbuild output directories
13 | /bin
14 | /obj
15 |
16 | # MSBuild Binary and Structured Log
17 | *.binlog
18 |
19 | # Visual Studio cache/options directory
20 | /.vs
21 |
22 | # macos
23 | .DS_Store
24 |
--------------------------------------------------------------------------------
/RestrictedChoice/RestrictedChoice/RestrictedChoiceApp.tsx:
--------------------------------------------------------------------------------
1 | import * as React from "react";
2 | import { IdPrefixProvider, FluentProvider} from "@fluentui/react-components";
3 | import { PcfContextProvider } from "./services/PcfContext";
4 | import { PcfContextService, IPcfContextServiceProps } from "./services/PcfContextService";
5 | import { RestrictedChoiceControl } from "./components/RestrictedChoice";
6 | import { useStyles } from "./utils/styles";
7 |
8 | // Extend the props interface to include both PCF context and control props.
9 | export interface IRestrictedChoiceAppProps extends IPcfContextServiceProps {
10 | onChange: (newValue: number | number[] | null) => void;
11 | // These props are passed from index.ts
12 | options: ComponentFramework.PropertyHelper.OptionMetadata[];
13 | restrictedOptions: number[];
14 | restrictedChoiceVisibility: number; // 1 for Disabled, 0 for Hide
15 | currentValue: number | number[] | null;
16 | restrictChoices: boolean;
17 | isMultiSelect: boolean;
18 | defaultValue?: number | number[] | null;
19 | }
20 |
21 | export const RestrictedChoiceApp: React.FC = (props) => {
22 | const styles = useStyles();
23 | // Create the context service.
24 | const pcfContextService = new PcfContextService({ context: props.context, instanceid: props.instanceid });
25 |
26 | return (
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 | );
35 | };
36 |
37 | export default RestrictedChoiceApp;
--------------------------------------------------------------------------------
/RestrictedChoice/RestrictedChoice/services/PcfContext.tsx:
--------------------------------------------------------------------------------
1 | import * as React from "react";
2 | import { PcfContextService } from './PcfContextService'
3 |
4 | interface PcfContextProviderProps {
5 | pcfcontext: PcfContextService,
6 | children: React.ReactNode
7 | }
8 |
9 | const PcfContext = React.createContext(undefined!)
10 |
11 | export const PcfContextProvider = ({ pcfcontext, children }: PcfContextProviderProps) => {
12 | return (
13 |
14 | {children}
15 |
16 | )
17 | }
18 |
19 | export const usePcfContext = () => {
20 | return React.useContext(PcfContext)
21 | }
22 |
--------------------------------------------------------------------------------
/RestrictedChoice/RestrictedChoice/utils/styles.ts:
--------------------------------------------------------------------------------
1 | import { makeStyles } from "@fluentui/react-components";
2 |
3 | export const useStyles = makeStyles({
4 | root: {
5 | width: "100%",
6 | },
7 | });
--------------------------------------------------------------------------------
/RestrictedChoice/Solution/RestrictedChoiceControl/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # msbuild output directories
4 | /bin
5 | /obj
6 |
7 | # MSBuild Binary and Structured Log
8 | *.binlog
9 |
--------------------------------------------------------------------------------
/RestrictedChoice/Solution/RestrictedChoiceControl/src/Other/Customizations.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 | 1033
17 |
18 |
--------------------------------------------------------------------------------
/RestrictedChoice/Solution/RestrictedChoiceControl/src/Other/Relationships.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/RestrictedChoice/eslint.config.mjs:
--------------------------------------------------------------------------------
1 | import eslintjs from "@eslint/js";
2 | import microsoftPowerApps from "@microsoft/eslint-plugin-power-apps";
3 | import pluginPromise from "eslint-plugin-promise";
4 | import reactPlugin from "eslint-plugin-react";
5 | import globals from "globals";
6 | import typescriptEslint from "typescript-eslint";
7 |
8 | /** @type {import('eslint').Linter.Config[]} */
9 | export default [
10 | {
11 | ignores: ["**/generated"],
12 | },
13 | eslintjs.configs.recommended,
14 | ...typescriptEslint.configs.recommendedTypeChecked,
15 | ...typescriptEslint.configs.stylisticTypeChecked,
16 | pluginPromise.configs["flat/recommended"],
17 | microsoftPowerApps.configs.paCheckerHosted,
18 | reactPlugin.configs.flat.recommended,
19 | {
20 | plugins: {
21 | "@microsoft/power-apps": microsoftPowerApps,
22 | },
23 |
24 | languageOptions: {
25 | globals: {
26 | ...globals.browser,
27 | ComponentFramework: true,
28 | },
29 | parserOptions: {
30 | ecmaVersion: 2020,
31 | sourceType: "module",
32 | projectService: true,
33 | tsconfigRootDir: import.meta.dirname,
34 | },
35 | },
36 |
37 | rules: {
38 | "@typescript-eslint/no-unused-vars": "off",
39 | },
40 | settings: {
41 | react: {
42 | version: "detect",
43 | },
44 | },
45 | },
46 | ];
47 |
--------------------------------------------------------------------------------
/RestrictedChoice/featureconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "pcfAllowCustomWebpack": "on"
3 | }
--------------------------------------------------------------------------------
/RestrictedChoice/images/2025-03-07_15-36-00.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rwilson504/PCFControls/61d3085266806324fc5b48150a7a8a8a237eaffa/RestrictedChoice/images/2025-03-07_15-36-00.png
--------------------------------------------------------------------------------
/RestrictedChoice/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "pcf-project",
3 | "version": "1.0.0",
4 | "description": "Project containing your PowerApps Component Framework (PCF) control.",
5 | "scripts": {
6 | "build": "pcf-scripts build",
7 | "clean": "pcf-scripts clean",
8 | "lint": "pcf-scripts lint",
9 | "lint:fix": "pcf-scripts lint fix",
10 | "rebuild": "pcf-scripts rebuild",
11 | "start": "pcf-scripts start",
12 | "start:watch": "pcf-scripts start watch",
13 | "refreshTypes": "pcf-scripts refreshTypes"
14 | },
15 | "dependencies": {
16 | "@fluentui/react-components": "9.46.2",
17 | "react": "16.14.0",
18 | "react-dom": "16.14.0",
19 | "uuidv4": "^6.2.13"
20 | },
21 | "devDependencies": {
22 | "@eslint/js": "^9.17.0",
23 | "@microsoft/eslint-plugin-power-apps": "^0.2.51",
24 | "@types/powerapps-component-framework": "^1.3.15",
25 | "@types/react": "^16.14.60",
26 | "@types/react-dom": "^16.9.24",
27 | "clean-webpack-plugin": "^4.0.0",
28 | "eslint-plugin-promise": "^7.1.0",
29 | "eslint-plugin-react": "^7.37.2",
30 | "globals": "^15.13.0",
31 | "pcf-scripts": "^1",
32 | "pcf-start": "^1",
33 | "react": "^16.14.0",
34 | "speed-measure-webpack-plugin": "^1.5.0",
35 | "typescript": "^4.9.5",
36 | "typescript-eslint": "^8.18.1"
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/RestrictedChoice/pcfconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "outDir": "./out/controls"
3 | }
--------------------------------------------------------------------------------
/RestrictedChoice/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "./node_modules/pcf-scripts/tsconfig_base.json",
3 | "compilerOptions": {
4 | "typeRoots": ["node_modules/@types"],
5 | "module": "es2015",
6 | "moduleResolution": "node"
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/RestrictedChoice/webpack.config.js:
--------------------------------------------------------------------------------
1 | const SpeedMeasurePlugin = require("speed-measure-webpack-plugin");
2 | const smp = new SpeedMeasurePlugin();
3 | const { CleanWebpackPlugin } = require('clean-webpack-plugin');
4 |
5 | module.exports = smp.wrap({
6 | devtool: 'source-map',
7 | plugins: [
8 | // will clean the build folder on successful build
9 | new CleanWebpackPlugin(),
10 | ]
11 | });
--------------------------------------------------------------------------------
/RotationalImage/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "env": {
3 | "browser": true,
4 | "es2020": true
5 | },
6 | "extends": [
7 | "eslint:recommended",
8 | "plugin:@typescript-eslint/recommended",
9 | "plugin:promise/recommended"
10 | ],
11 | "globals": {
12 | "ComponentFramework": true
13 | },
14 | "parser": "@typescript-eslint/parser",
15 | "parserOptions": {
16 | "ecmaVersion": 2020,
17 | "sourceType": "module"
18 | },
19 | "plugins": [
20 | "@microsoft/power-apps",
21 | "@typescript-eslint"
22 | ],
23 | "rules": {
24 | "@typescript-eslint/no-unused-vars": "off"
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/RotationalImage/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 |
6 | # generated directory
7 | **/generated
8 |
9 | # output directory
10 | /out
11 |
12 | # msbuild output directories
13 | /bin
14 | /obj
--------------------------------------------------------------------------------
/RotationalImage/Solution/RotationalImageComponent/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # msbuild output directories
4 | /bin
5 | /obj
--------------------------------------------------------------------------------
/RotationalImage/Solution/RotationalImageComponent/src/Other/Customizations.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 | 1033
17 |
18 |
--------------------------------------------------------------------------------
/RotationalImage/Solution/RotationalImageComponent/src/Other/Relationships.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/RotationalImage/featureconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | }
--------------------------------------------------------------------------------
/RotationalImage/images/AddComponentToForm.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rwilson504/PCFControls/61d3085266806324fc5b48150a7a8a8a237eaffa/RotationalImage/images/AddComponentToForm.png
--------------------------------------------------------------------------------
/RotationalImage/images/ComponentProperties.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rwilson504/PCFControls/61d3085266806324fc5b48150a7a8a8a237eaffa/RotationalImage/images/ComponentProperties.png
--------------------------------------------------------------------------------
/RotationalImage/images/ConverImageToBase64.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rwilson504/PCFControls/61d3085266806324fc5b48150a7a8a8a237eaffa/RotationalImage/images/ConverImageToBase64.gif
--------------------------------------------------------------------------------
/RotationalImage/images/ImportComponent.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rwilson504/PCFControls/61d3085266806324fc5b48150a7a8a8a237eaffa/RotationalImage/images/ImportComponent.png
--------------------------------------------------------------------------------
/RotationalImage/images/ImportComponentRibbon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rwilson504/PCFControls/61d3085266806324fc5b48150a7a8a8a237eaffa/RotationalImage/images/ImportComponentRibbon.png
--------------------------------------------------------------------------------
/RotationalImage/images/RotationalImage.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rwilson504/PCFControls/61d3085266806324fc5b48150a7a8a8a237eaffa/RotationalImage/images/RotationalImage.gif
--------------------------------------------------------------------------------
/RotationalImage/images/RunOnStart.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rwilson504/PCFControls/61d3085266806324fc5b48150a7a8a8a237eaffa/RotationalImage/images/RunOnStart.png
--------------------------------------------------------------------------------
/RotationalImage/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "pcf-project",
3 | "version": "1.0.0",
4 | "description": "Project containing your PowerApps Component Framework (PCF) control.",
5 | "scripts": {
6 | "build": "pcf-scripts build",
7 | "clean": "pcf-scripts clean",
8 | "lint": "pcf-scripts lint",
9 | "lint:fix": "pcf-scripts lint fix",
10 | "rebuild": "pcf-scripts rebuild",
11 | "start": "pcf-scripts start",
12 | "start:watch": "pcf-scripts start watch",
13 | "refreshTypes": "pcf-scripts refreshTypes"
14 | },
15 | "dependencies": {
16 | "@types/node": "^10.12.18",
17 | "hex-and-rgba": "^1.4.2",
18 | "react": "^16.13.1",
19 | "react-dom": "^16.13.1"
20 | },
21 | "devDependencies": {
22 | "@microsoft/eslint-plugin-power-apps": "^0.2.51",
23 | "@types/powerapps-component-framework": "^1.3",
24 | "@types/react-dom": "^16",
25 | "@typescript-eslint/eslint-plugin": "^8.18.0",
26 | "@typescript-eslint/parser": "^8.18.0",
27 | "eslint": "^8.57.0",
28 | "eslint-plugin-import": "^2.31.0",
29 | "eslint-plugin-node": "^11.1.0",
30 | "eslint-plugin-promise": "^7.1.0",
31 | "pcf-scripts": "^1",
32 | "pcf-start": "^1",
33 | "typescript": "^4.9.5"
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/RotationalImage/pcfconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "outDir": "./out/controls"
3 | }
--------------------------------------------------------------------------------
/RotationalImage/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "./node_modules/pcf-scripts/tsconfig_base.json",
3 | "compilerOptions": {
4 | "typeRoots": ["node_modules/@types"],
5 | }
6 | }
--------------------------------------------------------------------------------
/RuntimeInfo/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "env": {
3 | "browser": true,
4 | "es2020": true
5 | },
6 | "extends": [
7 | "eslint:recommended",
8 | "plugin:@typescript-eslint/recommended",
9 | "plugin:promise/recommended"
10 | ],
11 | "globals": {
12 | "ComponentFramework": true
13 | },
14 | "parser": "@typescript-eslint/parser",
15 | "parserOptions": {
16 | "ecmaVersion": 2020,
17 | "sourceType": "module"
18 | },
19 | "plugins": [
20 | "@microsoft/power-apps",
21 | "@typescript-eslint"
22 | ],
23 | "rules": {
24 | "@typescript-eslint/no-unused-vars": "off",
25 | "@typescript-eslint/no-empty-object-type": "off"
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/RuntimeInfo/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 |
6 | # generated directory
7 | **/generated
8 |
9 | # output directory
10 | /out
11 |
12 | # msbuild output directories
13 | /bin
14 | /obj
--------------------------------------------------------------------------------
/RuntimeInfo/RuntimeInfo/browser-info.d.ts:
--------------------------------------------------------------------------------
1 | declare module 'browser-info';
--------------------------------------------------------------------------------
/RuntimeInfo/Solution/RuntimeInfoComponent/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # msbuild output directories
4 | /bin
5 | /obj
--------------------------------------------------------------------------------
/RuntimeInfo/Solution/RuntimeInfoComponent/src/Other/Customizations.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 | 1033
17 |
18 |
--------------------------------------------------------------------------------
/RuntimeInfo/Solution/RuntimeInfoComponent/src/Other/Relationships.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/RuntimeInfo/featureconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | }
--------------------------------------------------------------------------------
/RuntimeInfo/images/EditComponentName.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rwilson504/PCFControls/61d3085266806324fc5b48150a7a8a8a237eaffa/RuntimeInfo/images/EditComponentName.png
--------------------------------------------------------------------------------
/RuntimeInfo/images/EditComponentNameUpdateName.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rwilson504/PCFControls/61d3085266806324fc5b48150a7a8a8a237eaffa/RuntimeInfo/images/EditComponentNameUpdateName.png
--------------------------------------------------------------------------------
/RuntimeInfo/images/ImportComponent.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rwilson504/PCFControls/61d3085266806324fc5b48150a7a8a8a237eaffa/RuntimeInfo/images/ImportComponent.png
--------------------------------------------------------------------------------
/RuntimeInfo/images/ImportComponentFromCode.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rwilson504/PCFControls/61d3085266806324fc5b48150a7a8a8a237eaffa/RuntimeInfo/images/ImportComponentFromCode.png
--------------------------------------------------------------------------------
/RuntimeInfo/images/RunTimeInfo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rwilson504/PCFControls/61d3085266806324fc5b48150a7a8a8a237eaffa/RuntimeInfo/images/RunTimeInfo.png
--------------------------------------------------------------------------------
/RuntimeInfo/images/RuntimeInfoDesktopFirefox.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rwilson504/PCFControls/61d3085266806324fc5b48150a7a8a8a237eaffa/RuntimeInfo/images/RuntimeInfoDesktopFirefox.png
--------------------------------------------------------------------------------
/RuntimeInfo/images/RuntimeInfoPhone.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rwilson504/PCFControls/61d3085266806324fc5b48150a7a8a8a237eaffa/RuntimeInfo/images/RuntimeInfoPhone.png
--------------------------------------------------------------------------------
/RuntimeInfo/images/UtilizePropertyInTextField.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rwilson504/PCFControls/61d3085266806324fc5b48150a7a8a8a237eaffa/RuntimeInfo/images/UtilizePropertyInTextField.png
--------------------------------------------------------------------------------
/RuntimeInfo/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "pcf-project",
3 | "version": "1.0.0",
4 | "description": "Project containing your PowerApps Component Framework (PCF) control.",
5 | "scripts": {
6 | "build": "pcf-scripts build",
7 | "clean": "pcf-scripts clean",
8 | "lint": "pcf-scripts lint",
9 | "lint:fix": "pcf-scripts lint fix",
10 | "rebuild": "pcf-scripts rebuild",
11 | "start": "pcf-scripts start",
12 | "start:watch": "pcf-scripts start watch",
13 | "refreshTypes": "pcf-scripts refreshTypes"
14 | },
15 | "dependencies": {
16 | "@types/node": "^18.19",
17 | "@types/ua-parser-js": "^0.7.33",
18 | "ua-parser-js": "^0.7.28"
19 | },
20 | "devDependencies": {
21 | "@types/powerapps-component-framework": "^1.3",
22 | "@microsoft/eslint-plugin-power-apps": "^0.2.51",
23 | "@typescript-eslint/eslint-plugin": "^8.18.0",
24 | "@typescript-eslint/parser": "^8.18.0",
25 | "eslint": "^8.57.0",
26 | "eslint-plugin-import": "^2.31.0",
27 | "eslint-plugin-node": "^11.1.0",
28 | "eslint-plugin-promise": "^7.1.0",
29 | "pcf-scripts": "^1",
30 | "pcf-start": "^1",
31 | "typescript": "^4.9.5"
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/RuntimeInfo/pcfconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "outDir": "./out/controls"
3 | }
--------------------------------------------------------------------------------
/RuntimeInfo/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "./node_modules/pcf-scripts/tsconfig_base.json",
3 | "compilerOptions": {
4 | "typeRoots": ["node_modules/@types"],
5 | }
6 | }
--------------------------------------------------------------------------------
/Scheduler/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 |
6 | # generated directory
7 | **/generated
8 |
9 | # output directory
10 | /out
11 |
12 | # msbuild output directories
13 | /bin
14 | /obj
15 |
16 | # MSBuild Binary and Structured Log
17 | *.binlog
18 |
19 | # Visual Studio cache/options directory
20 | /.vs
21 |
22 | # macos
23 | .DS_Store
24 |
--------------------------------------------------------------------------------
/Scheduler/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "github.copilot.chat.codeGeneration.useInstructionFiles": true,
3 | "chat.instructionsFilesLocations": {
4 | ".github": true
5 | },
6 | }
--------------------------------------------------------------------------------
/Scheduler/Sample/RAW! Scheduler Sample.msapp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rwilson504/PCFControls/61d3085266806324fc5b48150a7a8a8a237eaffa/Scheduler/Sample/RAW! Scheduler Sample.msapp
--------------------------------------------------------------------------------
/Scheduler/Scheduler/components/callbacks/eventClicked.ts:
--------------------------------------------------------------------------------
1 | import { SchedulerData, EventItem } from "react-big-schedule"; // adjust import paths as needed
2 |
3 | export function createEventClickedCallback(
4 | onClickSelectedRecord: (eventId: string) => void
5 | ) {
6 | return (schedulerData: SchedulerData, event: EventItem) => {
7 | const eventId = event.id as string;
8 | if (eventId) {
9 | onClickSelectedRecord?.(eventId);
10 | }
11 | };
12 | }
13 |
--------------------------------------------------------------------------------
/Scheduler/Scheduler/components/callbacks/index.ts:
--------------------------------------------------------------------------------
1 | export {createEventClickedCallback} from "./eventClicked";
2 | export {createSlotClickedFuncCallback} from "./slotClickedFunc";
3 | export {createNewEventCallback} from "./newEvent";
4 | export {createToggleExpandFuncCallback} from "./toggleExpandFunc";
5 | export {createNextClickCallback} from "./nextClick";
6 | export {createPrevClickCallback} from "./prevClick";
7 | export {createOnViewChangeCallback} from "./onViewChange";
--------------------------------------------------------------------------------
/Scheduler/Scheduler/components/callbacks/newEvent.ts:
--------------------------------------------------------------------------------
1 | import { SchedulerData, EventItem } from "react-big-schedule";
2 |
3 | export function createNewEventCallback(
4 | onNewEvent: (slotId: string, start: Date, end: Date) => void
5 | ) {
6 | return (
7 | schedulerData: SchedulerData,
8 | slotId: string,
9 | slotName: string,
10 | start: string | Date,
11 | end: string | Date,
12 | type: string,
13 | item: EventItem
14 | ) => {
15 | let startDate = start;
16 | let endDate = end;
17 | if (typeof start === "string") {
18 | startDate = new Date(start);
19 | }
20 | if (typeof end === "string") {
21 | endDate = new Date(end);
22 | }
23 | if (onNewEvent) {
24 | onNewEvent(
25 | slotId,
26 | startDate as Date,
27 | endDate as Date
28 | );
29 | }
30 | };
31 | }
32 |
--------------------------------------------------------------------------------
/Scheduler/Scheduler/components/callbacks/nextClick.ts:
--------------------------------------------------------------------------------
1 | import { SchedulerData } from "react-big-schedule";
2 | import { SchedulerAction, Event } from "../../types";
3 |
4 | export function createNextClickCallback(
5 | events: Event[],
6 | schedulerView: string,
7 | dispatch: (action: SchedulerAction) => void,
8 | onDateChange: (start: Date, viewStart: Date, viewEnd: Date, view: string) => void
9 | ) {
10 | return (schedulerData: SchedulerData) => {
11 | schedulerData.next();
12 | schedulerData.setEvents(events);
13 | dispatch({ type: "UPDATE_SCHEDULER", payload: schedulerData });
14 | onDateChange?.(
15 | schedulerData.getViewStartDate().toDate(),
16 | schedulerData.getViewStartDate().toDate(),
17 | schedulerData.getViewEndDate().toDate(),
18 | schedulerView
19 | );
20 | };
21 | }
22 |
--------------------------------------------------------------------------------
/Scheduler/Scheduler/components/callbacks/onViewChange.ts:
--------------------------------------------------------------------------------
1 | import { SchedulerData } from "react-big-schedule";
2 | import { View } from "../../types";
3 |
4 | export function createOnViewChangeCallback(
5 | availableViews: View[],
6 | setSchedulerView: (viewName: string) => void
7 | ) {
8 | return (schedulerData: SchedulerData, view: View) => {
9 | const foundView = availableViews.find(v => v.viewType === view.viewType);
10 | if (foundView) {
11 | setSchedulerView(foundView.name);
12 | }
13 | };
14 | }
15 |
--------------------------------------------------------------------------------
/Scheduler/Scheduler/components/callbacks/prevClick.ts:
--------------------------------------------------------------------------------
1 | import { SchedulerData } from "react-big-schedule";
2 | import { SchedulerAction, Event} from "../../types";
3 |
4 | export function createPrevClickCallback(
5 | events: Event[],
6 | schedulerView: string,
7 | dispatch: (action: SchedulerAction) => void,
8 | onDateChange: (start: Date, viewStart: Date, viewEnd: Date, view: string) => void
9 | ) {
10 | return (schedulerData: SchedulerData) => {
11 | schedulerData.prev();
12 | schedulerData.setEvents(events);
13 | dispatch({ type: "UPDATE_SCHEDULER", payload: schedulerData });
14 | onDateChange?.(
15 | schedulerData.getViewStartDate().toDate(),
16 | schedulerData.getViewStartDate().toDate(),
17 | schedulerData.getViewEndDate().toDate(),
18 | schedulerView
19 | );
20 | };
21 | }
22 |
--------------------------------------------------------------------------------
/Scheduler/Scheduler/components/callbacks/slotClickedFunc.ts:
--------------------------------------------------------------------------------
1 | import { SchedulerData, EventItem, ResourceEvent } from "react-big-schedule";
2 | import { Slot } from "../../types";
3 |
4 | export function createSlotClickedFuncCallback(
5 | onClickSelectedSlot: (resourceId: string) => void
6 | ) {
7 | return (schedulerData: SchedulerData, slot: ResourceEvent) => {
8 | const slotExtended = slot as Slot
9 | if (slotExtended && slotExtended.slotId) {
10 | const resourceId = slotExtended.slotId;
11 | onClickSelectedSlot(resourceId);
12 | }
13 | };
14 | }
15 |
--------------------------------------------------------------------------------
/Scheduler/Scheduler/components/callbacks/toggleExpandFunc.ts:
--------------------------------------------------------------------------------
1 | import { SchedulerData } from "react-big-schedule";
2 | import { SchedulerAction } from "../../types";
3 |
4 | export function createToggleExpandFuncCallback(
5 | dispatch: (action: SchedulerAction) => void
6 | ) {
7 | return (schedulerData: SchedulerData, slotId: string) => {
8 | schedulerData.toggleExpandStatus(slotId);
9 | dispatch({ type: "UPDATE_SCHEDULER", payload: schedulerData });
10 | };
11 | }
12 |
--------------------------------------------------------------------------------
/Scheduler/Scheduler/components/renderers/eventItemTemplateResolver.tsx:
--------------------------------------------------------------------------------
1 | import * as React from "react";
2 | import { SchedulerData, EventItem } from "react-big-schedule";
3 | import Color from "color";
4 |
5 | export function eventItemTemplateResolver(
6 | schedulerData: SchedulerData,
7 | event: EventItem,
8 | bgColor: string,
9 | isStart: boolean,
10 | isEnd: boolean,
11 | mustAddCssClass: string,
12 | mustBeHeight: number,
13 | agendaMaxEventWidth: number
14 | ): React.ReactNode {
15 | const additionalClass = 'round-all';
16 |
17 | // Use Color to determine if background is dark or light
18 | let textColor = "#000";
19 | try {
20 | if (Color(bgColor).isDark()) {
21 | textColor = "#fff";
22 | }
23 | } catch {
24 | // fallback if color parsing fails
25 | textColor = "#000";
26 | }
27 |
28 | return (
29 |
35 | {event.title}
36 |
37 | );
38 | }
39 |
--------------------------------------------------------------------------------
/Scheduler/Scheduler/components/renderers/index.ts:
--------------------------------------------------------------------------------
1 | export {eventItemPopoverTemplateResolver} from "./eventItemPopoverTemplateResolver";
2 | export {eventItemTemplateResolver} from "./eventItemTemplateResolver";
3 |
--------------------------------------------------------------------------------
/Scheduler/Scheduler/components/schedulerWrapper.tsx:
--------------------------------------------------------------------------------
1 | import * as React from "react";
2 | import { Scheduler, SchedulerProps, EventItem } from "react-big-schedule";
3 |
4 | // Cast Scheduler to ComponentType for JSX compatibility
5 | const SchedulerWrapper: React.ComponentType> = Scheduler as unknown as React.ComponentType>;
6 |
7 | export default SchedulerWrapper;
--------------------------------------------------------------------------------
/Scheduler/Scheduler/hooks/index.ts:
--------------------------------------------------------------------------------
1 | export { useAvailableViews } from "./useAvailableViews";
2 | export { useShowHeader } from "./useShowHeader";
3 | export { useSchedulerView } from "./useSchedulerView";
4 | export { useSchedulerDate } from "./useSchedulerDate";
5 | export { useSchedulerLanguage } from "./useSchedulerLanguage";
6 | export { useResourceNameHeader } from "./useResourceNameHeader";
7 | export { useWorkWeekDays } from "./useWorkWeekDays";
8 | export {useDisplayWeekend} from "./useDisplayWeekend";
9 | export {useNonWorkingTimeColors} from "./useNonWorkingTimeColors";
10 | export {useDayViewOptions} from "./useDayViewOptions";
--------------------------------------------------------------------------------
/Scheduler/Scheduler/hooks/useDisplayWeekend.ts:
--------------------------------------------------------------------------------
1 | import { useEffect, useState } from "react";
2 | import { SchedulerData } from "react-big-schedule";
3 | import { PcfContextService } from "../services/pcfContextService";
4 | import { SchedulerAction } from "../types";
5 |
6 | /**
7 | * Hook to get the value of the schedulerDisplayWeekend property from PCF context.
8 | * Returns true if weekends should be displayed, false otherwise.
9 | * Defaults to true if the property is not set.
10 | */
11 | export function useDisplayWeekend(
12 | pcfContext: PcfContextService,
13 | schedulerData: SchedulerData | null,
14 | dispatch: (action: SchedulerAction) => void
15 | ): boolean {
16 | const getValue = () => {
17 | return pcfContext.context.parameters?.schedulerDisplayWeekend?.raw || true;
18 | };
19 |
20 | const [displayWeekend, setDisplayWeekend] = useState(getValue);
21 |
22 | useEffect(() => {
23 | setDisplayWeekend(getValue());
24 | }, [pcfContext.context.parameters.schedulerDisplayWeekend?.raw]);
25 |
26 | // Effect to update the scheduler config when displayWeekend changes
27 | useEffect(() => {
28 | if (schedulerData && schedulerData.config) {
29 | schedulerData.config.displayWeekend = displayWeekend;
30 | if (dispatch) {
31 | dispatch({ type: "UPDATE_SCHEDULER", payload: schedulerData });
32 | }
33 | }
34 | }, [displayWeekend]);
35 |
36 | return displayWeekend;
37 | }
--------------------------------------------------------------------------------
/Scheduler/Scheduler/hooks/useResourceNameHeader.ts:
--------------------------------------------------------------------------------
1 | import { useState, useEffect } from "react";
2 | import { SchedulerData } from "react-big-schedule";
3 | import { getLocalizedResourceName } from "../utils/localization";
4 | import { PcfContextService } from "../services/pcfContextService";
5 | import { SchedulerAction } from "../types";
6 |
7 | export function useResourceNameHeader(
8 | pcfContext: PcfContextService,
9 | state: { schedulerData: SchedulerData | null },
10 | dispatch: (action: SchedulerAction) => void
11 | ): string {
12 | const getHeader = () => {
13 | const param = pcfContext.context.parameters.resourceNameHeader?.raw?.trim();
14 | if (param) return param;
15 | const lang = state.schedulerData?.localeDayjs().locale() || "en";
16 | return getLocalizedResourceName(lang);
17 | };
18 |
19 | const [resourceNameHeader, setResourceNameHeader] = useState(getHeader);
20 |
21 | useEffect(() => {
22 | setResourceNameHeader(getHeader());
23 | }, [
24 | pcfContext.context.parameters.resourceNameHeader?.raw,
25 | state.schedulerData?.localeDayjs().locale()
26 | ]);
27 |
28 | useEffect(() => {
29 | if (state.schedulerData) {
30 | state.schedulerData.config.resourceName = resourceNameHeader;
31 | dispatch({ type: "UPDATE_SCHEDULER", payload: state.schedulerData });
32 | }
33 | }, [resourceNameHeader]);
34 |
35 | return resourceNameHeader;
36 | }
--------------------------------------------------------------------------------
/Scheduler/Scheduler/hooks/useShowHeader.ts:
--------------------------------------------------------------------------------
1 | import { useState, useEffect } from "react";
2 | import { SchedulerData } from "react-big-schedule";
3 | import { PcfContextService } from "../services/pcfContextService";
4 | import { SchedulerAction } from "../types";
5 |
6 | export function useShowHeader(
7 | pcfContext: PcfContextService,
8 | state: { schedulerData: SchedulerData | null },
9 | dispatch: (action: SchedulerAction) => void
10 | ): boolean {
11 | const [showHeader, setShowHeader] = useState(
12 | pcfContext.context.parameters.showSchedulerHeader?.raw !== false
13 | );
14 |
15 | // Sync showHeader with parameter changes
16 | useEffect(() => {
17 | setShowHeader(pcfContext.context.parameters.showSchedulerHeader?.raw !== false);
18 | }, [pcfContext.context.parameters.showSchedulerHeader?.raw]);
19 |
20 | // Update SchedulerData and dispatch when showHeader changes
21 | useEffect(() => {
22 | if (state.schedulerData) {
23 | state.schedulerData.config.headerEnabled = showHeader;
24 | dispatch({ type: "UPDATE_SCHEDULER", payload: state.schedulerData });
25 | }
26 | }, [showHeader]);
27 |
28 | return showHeader;
29 | }
--------------------------------------------------------------------------------
/Scheduler/Scheduler/mocks/MockPCFClient.ts:
--------------------------------------------------------------------------------
1 | export interface MockPCFClientOptions {
2 | disableScroll?: boolean;
3 | formFactor?: number;
4 | client?: string;
5 | offline?: boolean;
6 | networkAvailable?: boolean;
7 | }
8 |
9 | export class MockPCFClient implements ComponentFramework.Client {
10 | disableScroll: boolean;
11 | private formFactor: number;
12 | private client: string;
13 | private offline: boolean;
14 | private networkAvailable: boolean;
15 |
16 | constructor(options: MockPCFClientOptions = {}) {
17 | this.disableScroll = options.disableScroll ?? false;
18 | this.formFactor = options.formFactor ?? 1;
19 | this.client = options.client ?? "Web";
20 | this.offline = options.offline ?? false;
21 | this.networkAvailable = options.networkAvailable ?? true;
22 | }
23 |
24 | getFormFactor(): number {
25 | return this.formFactor;
26 | }
27 |
28 | getClient(): string {
29 | return this.client;
30 | }
31 |
32 | isOffline(): boolean {
33 | return this.offline;
34 | }
35 |
36 | isNetworkAvailable(): boolean {
37 | return this.networkAvailable;
38 | }
39 | }
--------------------------------------------------------------------------------
/Scheduler/Scheduler/mocks/MockPCFFactory.ts:
--------------------------------------------------------------------------------
1 | export interface MockPCFFactoryOptions {
2 | getPopupService?: () => ComponentFramework.FactoryApi.Popup.PopupService;
3 | requestRender?: () => void;
4 | }
5 |
6 | export class MockPCFFactory implements ComponentFramework.Factory {
7 | private _getPopupService?: () => ComponentFramework.FactoryApi.Popup.PopupService;
8 | private _requestRender?: () => void;
9 |
10 | constructor(options: MockPCFFactoryOptions = {}) {
11 | this._getPopupService = options.getPopupService;
12 | this._requestRender = options.requestRender;
13 | }
14 |
15 | getPopupService(): ComponentFramework.FactoryApi.Popup.PopupService {
16 | if (this._getPopupService) {
17 | return this._getPopupService();
18 | }
19 | throw new Error("Method not implemented.");
20 | }
21 |
22 | requestRender(): void {
23 | if (this._requestRender) {
24 | this._requestRender();
25 | return;
26 | }
27 | throw new Error("Method not implemented.");
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/Scheduler/Scheduler/mocks/MockPCFMode.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable @typescript-eslint/no-unused-vars */
2 | export interface MockPCFModeOptions {
3 | allocatedHeight?: number;
4 | allocatedWidth?: number;
5 | isControlDisabled?: boolean;
6 | isVisible?: boolean;
7 | label?: string;
8 | contextInfo?: {
9 | entityId?: string;
10 | entityTypeName?: string;
11 | entityRecordName?: string;
12 | [key: string]: any;
13 | };
14 | }
15 |
16 | export class MockPCFMode implements ComponentFramework.Mode {
17 | allocatedHeight: number;
18 | allocatedWidth: number;
19 | isControlDisabled: boolean;
20 | isVisible: boolean;
21 | label: string;
22 | // Add contextInfo property for custom context usage
23 | contextInfo?: {
24 | entityId?: string;
25 | entityTypeName?: string;
26 | entityRecordName?: string;
27 | [key: string]: any;
28 | };
29 |
30 | constructor(options: MockPCFModeOptions = {}) {
31 | this.allocatedHeight = options.allocatedHeight ?? 600;
32 | this.allocatedWidth = options.allocatedWidth ?? 800;
33 | this.isControlDisabled = options.isControlDisabled ?? false;
34 | this.isVisible = options.isVisible ?? true;
35 | this.label = options.label ?? "Mock Mode";
36 | this.contextInfo = options.contextInfo;
37 | }
38 |
39 | setControlState(state: ComponentFramework.Dictionary): boolean {
40 | throw new Error("Method not implemented.");
41 | }
42 | setFullScreen(value: boolean): void {
43 | throw new Error("Method not implemented.");
44 | }
45 | trackContainerResize(value: boolean): void {
46 | throw new Error("Method not implemented.");
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/Scheduler/Scheduler/mocks/MockPCFParameters.ts:
--------------------------------------------------------------------------------
1 | import { MockPCFDataSet } from "./MockPCFDataSet";
2 |
3 | /**
4 | * MockPCFParameterValue represents the structure of a PCF parameter value.
5 | */
6 | export type MockPCFParameterValue = {
7 | raw: T;
8 | formatted?: string;
9 | [key: string]: any;
10 | };
11 |
12 | /**
13 | * MockPCFParameters provides a generic, flexible way to mock PCF context parameters.
14 | * Supports both params.getParameter("key") and params.key access.
15 | */
16 | export class MockPCFParameters {
17 | [key: string]: MockPCFParameterValue | any;
18 |
19 | constructor(initialParams?: Record) {
20 | if (initialParams) {
21 | for (const key of Object.keys(initialParams)) {
22 | this[key] = initialParams[key];
23 | }
24 | }
25 | }
26 |
27 | /**
28 | * Set a parameter value.
29 | */
30 | setParameter(key: string, value: MockPCFParameterValue) {
31 | this[key] = value;
32 | }
33 |
34 | /**
35 | * Get a parameter value.
36 | */
37 | getParameter(key: string): MockPCFParameterValue {
38 | return this[key];
39 | }
40 | }
--------------------------------------------------------------------------------
/Scheduler/Scheduler/mocks/MockPCFResources.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable @typescript-eslint/no-unused-vars */
2 | export interface MockPCFResourcesOptions {
3 | getResource?: (id: string, success: (data: string) => void, failure: () => void) => void;
4 | getString?: (id: string) => string;
5 | }
6 |
7 | export class MockPCFResources implements ComponentFramework.Resources {
8 | private _getResource?: (id: string, success: (data: string) => void, failure: () => void) => void;
9 | private _getString?: (id: string) => string;
10 |
11 | constructor(options: MockPCFResourcesOptions = {}) {
12 | this._getResource = options.getResource;
13 | this._getString = options.getString;
14 | }
15 |
16 | getResource(id: string, success: (data: string) => void, failure: () => void): void {
17 | if (this._getResource) {
18 | this._getResource(id, success, failure);
19 | } else {
20 | throw new Error("Method not implemented.");
21 | }
22 | }
23 |
24 | getString(id: string): string {
25 | if (this._getString) {
26 | return this._getString(id);
27 | }
28 | throw new Error("Method not implemented.");
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/Scheduler/Scheduler/mocks/index.ts:
--------------------------------------------------------------------------------
1 | export * from ".";
2 |
--------------------------------------------------------------------------------
/Scheduler/Scheduler/resources/schedulerOverrides.css:
--------------------------------------------------------------------------------
1 | /* Scheduler Components */
2 | .react-big-schedule {
3 | margin: 0px auto !important;
4 | }
--------------------------------------------------------------------------------
/Scheduler/Scheduler/schedulerApp.tsx:
--------------------------------------------------------------------------------
1 | import * as React from "react";
2 | import { PcfContextProvider } from "./services/pcfContext";
3 | import { PcfContextService } from "./services/pcfContextService";
4 | import SchedulerControl from "./components/scheduler";
5 | import { DndProvider } from 'react-dnd';
6 | import { HTML5Backend } from 'react-dnd-html5-backend';
7 | import { ISchedulerControlProps } from "./types/schedulerTypes";
8 |
9 | export const SchedulerApp: React.FC = (props) => {
10 | // Create the context service.
11 | const pcfContextService = new PcfContextService({
12 | context: props.context,
13 | instanceid: props.instanceid,
14 | height: props.height
15 | });
16 |
17 | // Wrap the SchedulerControl in providers for drag-and-drop and PCF context.
18 | return (
19 |
20 |
21 |
24 |
25 |
26 | );
27 | };
28 |
29 | export default SchedulerApp;
--------------------------------------------------------------------------------
/Scheduler/Scheduler/services/metadataService.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 |
3 | import axios, { AxiosResponse } from "axios";
4 | import { IInputs } from "../generated/ManifestTypes";
5 |
6 | export const getEntities = async (
7 | baseUrl: string,
8 | ): Promise<{ displayName: string; logicalName: string }[]> => {
9 | const filter =
10 | "IsValidForAdvancedFind%20eq%20true%20and%20IsCustomizable/Value%20eq%20true";
11 | const url = `${baseUrl}/api/data/v9.1/EntityDefinitions?$select=LogicalName,DisplayName&$filter=${filter}`;
12 |
13 | try {
14 | const response: AxiosResponse = await axios.get(url, {
15 | headers: {
16 | "OData-MaxVersion": "4.0",
17 | "OData-Version": "4.0",
18 | Accept: "application/json",
19 | "Content-Type": "application/json; charset=utf-8",
20 | },
21 | });
22 |
23 | const result = response.data;
24 | if (result.status < 0) {
25 | throw new Error(result.statusText);
26 | }
27 |
28 | return result.value.map(
29 | (entity: {
30 | DisplayName: { UserLocalizedLabel: { Label: string } };
31 | LogicalName: string;
32 | }) => ({
33 | displayName:
34 | entity.DisplayName?.UserLocalizedLabel?.Label || entity.LogicalName,
35 | logicalName: entity.LogicalName,
36 | })
37 | );
38 | } catch (error) {
39 | if (axios.isAxiosError(error)) {
40 | throw new Error(error.response?.statusText ?? error.message);
41 | } else {
42 | throw new Error(String(error));
43 | }
44 | }
45 | };
46 |
47 | export const getBaseUrl = (): string | undefined => {
48 | // @ts-expect-error context is available in model apps
49 | return (context as any).page.getClientUrl() as string;
50 | };
51 |
--------------------------------------------------------------------------------
/Scheduler/Scheduler/services/pcfContext.tsx:
--------------------------------------------------------------------------------
1 |
2 | import * as React from "react";
3 | import { PcfContextService } from './pcfContextService'
4 | // Provides a React context for sharing the PCF context service across the component tree.
5 |
6 | // Props for the PcfContextProvider component
7 | interface PcfContextProviderProps {
8 | pcfcontext: PcfContextService;
9 | children: React.ReactNode;
10 | }
11 |
12 |
13 | // Create a React context for the PCF context service
14 | const PcfContext = React.createContext(undefined!)
15 |
16 | // Provider component for the PCF context service
17 | export const PcfContextProvider = ({ pcfcontext, children }: PcfContextProviderProps) => {
18 | return (
19 |
20 | {children}
21 |
22 | )
23 | }
24 |
25 |
26 | // Custom hook to access the PCF context service
27 | export const usePcfContext = () => {
28 | return React.useContext(PcfContext);
29 | }
30 |
--------------------------------------------------------------------------------
/Scheduler/Scheduler/test/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Scheduler Test
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/Scheduler/Scheduler/test/main.tsx:
--------------------------------------------------------------------------------
1 | import { StrictMode } from 'react'
2 | import { createRoot } from 'react-dom/client'
3 | import TestApp from "./testApp";
4 |
5 | createRoot(document.getElementById('root')!).render(
6 |
7 |
8 | ,
9 | )
10 |
--------------------------------------------------------------------------------
/Scheduler/Scheduler/test/tsconfig.app.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../tsconfig.json",
3 | "compilerOptions": {
4 | "module": "ES2020",
5 | "target": "ESNext",
6 | "lib": [
7 | "ES2020",
8 | "DOM",
9 | "DOM.Iterable"
10 | ],
11 | "jsx": "react-jsx",
12 | "moduleResolution": "node", // Use "node" for best compatibility
13 | "allowImportingTsExtensions": true,
14 | "verbatimModuleSyntax": true,
15 | "moduleDetection": "force",
16 | "noEmit": true,
17 | "esModuleInterop": true,
18 | "types": [
19 | "vite/client",
20 | "node"
21 | ]
22 | },
23 | "include": [
24 | "./**/*.tsx",
25 | "./**/*.ts"
26 | ],
27 | "exclude": [
28 | "../../out",
29 | "../../node_modules"
30 | ]
31 | }
--------------------------------------------------------------------------------
/Scheduler/Scheduler/test/vite.config.ts:
--------------------------------------------------------------------------------
1 | import { defineConfig } from "vite";
2 | import react from "@vitejs/plugin-react";
3 |
4 | export default defineConfig({
5 | root: __dirname,
6 | plugins: [react()],
7 | server: {
8 | port: 5173,
9 | open: true
10 | },
11 | build: {
12 | outDir: "dist"
13 | }
14 | });
--------------------------------------------------------------------------------
/Scheduler/Scheduler/types/extendedSchedulerData.ts:
--------------------------------------------------------------------------------
1 | import { SchedulerData, SchedulerDataConfig, EventItem, SchedulerDataBehaviors } from "react-big-schedule";
2 |
3 | export interface ExtendedSchedulerDataConfig extends SchedulerDataConfig {
4 | workWeekDays?: number[];
5 | eventItemPopoverShowColor?: boolean; // <-- add this line
6 | }
7 |
8 | export class ExtendedSchedulerData extends SchedulerData {
9 | config: ExtendedSchedulerDataConfig;
10 |
11 | constructor(
12 | startDate: string,
13 | viewType: number,
14 | showAgenda: boolean,
15 | isEventPerspective: boolean,
16 | config: ExtendedSchedulerDataConfig,
17 | behaviors?: SchedulerDataBehaviors
18 | ) {
19 | super(startDate, viewType, showAgenda, isEventPerspective, config, behaviors);
20 | this.config = config;
21 | }
22 | }
--------------------------------------------------------------------------------
/Scheduler/Scheduler/types/index.ts:
--------------------------------------------------------------------------------
1 | export * from "./schedulerTypes";
2 | export * from "./schedulerViews";
3 | export * from "./extendedSchedulerData";
4 | // Add other type files here as needed
--------------------------------------------------------------------------------
/Scheduler/Scheduler/utils/constants.ts:
--------------------------------------------------------------------------------
1 |
2 | /**
3 | * Default view names for the scheduler, used when no available views are specified.
4 | */
5 | export const DEFAULT_VIEW_NAMES = ["day", "week", "month", "year", "event"];
6 |
7 | /**
8 | * Default date format for the scheduler (ISO format)
9 | */
10 | export const DEFAULT_DATE_FORMAT = "YYYY-MM-DD";
11 |
12 | /**
13 | * Default time format for the scheduler (24-hour format)
14 | */
15 | export const DEFAULT_TIME_FORMAT = "HH:mm:ss";
16 |
17 | /**
18 | * Supported language codes for localization
19 | */
20 | export const SUPPORTED_LANGUAGES = ["en", "es", "fr", "de", "pt"];
--------------------------------------------------------------------------------
/Scheduler/Scheduler/utils/formattingHelpers.ts:
--------------------------------------------------------------------------------
1 |
2 | /**
3 | * Formats a Date object as a string suitable for Dynamics form parameters.
4 | * Example output: "5/19/2025 14:30:00"
5 | * @param date - Date object to format
6 | * @returns formatted date string
7 | */
8 | export function formatDateAsParameterString(date: Date): string {
9 | return (
10 | date.getMonth() + 1
11 | ) + "/" +
12 | date.getDate() + "/" +
13 | date.getFullYear() + " " +
14 | date.getHours() + ":" +
15 | date.getMinutes() + ":" +
16 | date.getSeconds();
17 | }
18 |
19 |
20 | /**
21 | * Parses a date string in "YYYY-MM-DD" format and returns a Date object (local time).
22 | * @param dateString - date string in ISO format
23 | * @returns Date object (local time, no time component)
24 | */
25 | export function parseDateOnly(dateString: string): Date {
26 | // Expects "YYYY-MM-DD"
27 | const [year, month, day] = dateString.split("-").map(Number);
28 | return new Date(year, month - 1, day); // JS months are 0-based
29 | }
30 |
31 |
32 | /**
33 | * Converts a language code like 'en' to 'en_EN', 'es' to 'es_ES', etc.
34 | * If the code is empty or not recognized, defaults to 'en_EN'.
35 | * @param lang - language code (e.g., 'en', 'es')
36 | * @returns locale string (e.g., 'en_EN')
37 | */
38 | export function getLocaleFromLanguage(lang: string): string {
39 | if (!lang) return "en_EN";
40 | const code = lang.toLowerCase();
41 | return `${code}_${code.toUpperCase()}`;
42 | }
--------------------------------------------------------------------------------
/Scheduler/Scheduler/utils/locales.ts:
--------------------------------------------------------------------------------
1 | import 'dayjs/locale/en';
2 | import 'dayjs/locale/es';
3 | import 'dayjs/locale/fr';
4 | import 'dayjs/locale/de';
5 | import 'dayjs/locale/pt';
6 | import 'antd/locale/en_US';
7 | import 'antd/locale/es_ES';
8 | import 'antd/locale/fr_FR';
9 | import 'antd/locale/de_DE';
10 | import 'antd/locale/pt_PT';
--------------------------------------------------------------------------------
/Scheduler/Solution/RAWSchedulerComponent/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # msbuild output directories
4 | /bin
5 | /obj
6 |
7 | # MSBuild Binary and Structured Log
8 | *.binlog
9 |
--------------------------------------------------------------------------------
/Scheduler/Solution/RAWSchedulerComponent/src/Other/Customizations.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 | 1033
17 |
18 |
--------------------------------------------------------------------------------
/Scheduler/Solution/RAWSchedulerComponent/src/Other/Relationships.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/Scheduler/eslint.config.mjs:
--------------------------------------------------------------------------------
1 | import eslintjs from "@eslint/js";
2 | import microsoftPowerApps from "@microsoft/eslint-plugin-power-apps";
3 | import pluginPromise from "eslint-plugin-promise";
4 | import globals from "globals";
5 | import typescriptEslint from "typescript-eslint";
6 |
7 | /** @type {import('eslint').Linter.Config[]} */
8 | export default [
9 | {
10 | ignores: ["**/generated/", "**/mocks/*.ts", "**/out/", "**/*.mjs"],
11 | },
12 | eslintjs.configs.recommended,
13 | ...typescriptEslint.configs.recommended,
14 | ...typescriptEslint.configs.stylistic,
15 | pluginPromise.configs["flat/recommended"],
16 | microsoftPowerApps.configs.paCheckerHosted,
17 | {
18 | plugins: {
19 | "@microsoft/power-apps": microsoftPowerApps,
20 | },
21 |
22 | languageOptions: {
23 | globals: {
24 | ...globals.browser,
25 | ComponentFramework: true,
26 | },
27 | parserOptions: {
28 | ecmaVersion: 2020,
29 | sourceType: "module",
30 | projectService: true,
31 | tsconfigRootDir: import.meta.dirname
32 | },
33 | },
34 |
35 | rules: {
36 | "@typescript-eslint/no-unused-vars": "off",
37 | },
38 | },
39 | ];
40 |
--------------------------------------------------------------------------------
/Scheduler/featureconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "pcfAllowCustomWebpack": "on"
3 | }
--------------------------------------------------------------------------------
/Scheduler/images/scheduler-demo.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rwilson504/PCFControls/61d3085266806324fc5b48150a7a8a8a237eaffa/Scheduler/images/scheduler-demo.gif
--------------------------------------------------------------------------------
/Scheduler/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "pcf-project",
3 | "version": "1.0.0",
4 | "description": "Project containing your PowerApps Component Framework (PCF) control.",
5 | "scripts": {
6 | "build": "pcf-scripts build",
7 | "clean": "pcf-scripts clean",
8 | "lint": "pcf-scripts lint",
9 | "lint:fix": "pcf-scripts lint fix",
10 | "rebuild": "pcf-scripts rebuild",
11 | "start": "pcf-scripts start",
12 | "start:watch": "pcf-scripts start watch",
13 | "refreshTypes": "pcf-scripts refreshTypes",
14 | "dev:test": "vite --config Scheduler/test/vite.config.ts"
15 | },
16 | "dependencies": {
17 | "antd": "^5.25.1",
18 | "axios": "^1.9.0",
19 | "color": "^5.0.0",
20 | "dayjs": "^1.11.13",
21 | "lcid": "^5.0.0",
22 | "react": "^18.3.1",
23 | "react-big-schedule": "^4.5.1",
24 | "react-dnd": "^14.0.5",
25 | "react-dnd-html5-backend": "^14.0.5",
26 | "react-dom": "^18.3.1",
27 | "uuid": "^11.1.0"
28 | },
29 | "devDependencies": {
30 | "@eslint/js": "^9.17.0",
31 | "@microsoft/eslint-plugin-power-apps": "^0.2.51",
32 | "@types/node": "^18.19.54",
33 | "@types/powerapps-component-framework": "^1.3.15",
34 | "@types/react-big-scheduler": "^0.2.7",
35 | "@types/react-dom": "^19.1.5",
36 | "@vitejs/plugin-react": "^4.4.1",
37 | "eslint-plugin-promise": "^7.1.0",
38 | "globals": "15.13.0",
39 | "pcf-scripts": "^1",
40 | "pcf-start": "^1",
41 | "typescript": "^5.8.3",
42 | "typescript-eslint": "^8.18.1",
43 | "vite": "^6.3.5"
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/Scheduler/pcfconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "outDir": "./out/controls"
3 | }
--------------------------------------------------------------------------------
/Scheduler/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "./node_modules/pcf-scripts/tsconfig_base.json",
3 | "compilerOptions": {
4 | "typeRoots": [
5 | "node_modules/@types"
6 | ],
7 | "allowSyntheticDefaultImports": true,
8 | "esModuleInterop": true,
9 | "jsx": "react-jsx"
10 | },
11 | "exclude": ["./out"]
12 | }
--------------------------------------------------------------------------------
/WorldDaylightMap/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "env": {
3 | "browser": true,
4 | "es2020": true
5 | },
6 | "extends": [
7 | "eslint:recommended",
8 | "plugin:@typescript-eslint/recommended",
9 | "plugin:promise/recommended"
10 | ],
11 | "globals": {
12 | "ComponentFramework": true
13 | },
14 | "parser": "@typescript-eslint/parser",
15 | "parserOptions": {
16 | "ecmaVersion": 2020,
17 | "sourceType": "module"
18 | },
19 | "plugins": [
20 | "@microsoft/power-apps",
21 | "@typescript-eslint"
22 | ],
23 | "rules": {
24 | "@typescript-eslint/no-unused-vars": "off"
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/WorldDaylightMap/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 |
6 | # generated directory
7 | **/generated
8 |
9 | # output directory
10 | /out
11 |
12 | # msbuild output directories
13 | /bin
14 | /obj
--------------------------------------------------------------------------------
/WorldDaylightMap/Sample/World Daylight Map.msapp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rwilson504/PCFControls/61d3085266806324fc5b48150a7a8a8a237eaffa/WorldDaylightMap/Sample/World Daylight Map.msapp
--------------------------------------------------------------------------------
/WorldDaylightMap/Solution/RAWWorldDaylightMap/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # msbuild output directories
4 | /bin
5 | /obj
--------------------------------------------------------------------------------
/WorldDaylightMap/Solution/RAWWorldDaylightMap/src/Other/Customizations.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 | 1033
17 |
18 |
--------------------------------------------------------------------------------
/WorldDaylightMap/Solution/RAWWorldDaylightMap/src/Other/Relationships.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/WorldDaylightMap/WorldDaylightMap/WorldDaylightMap.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import {IInputs} from "./generated/ManifestTypes";
3 | import {WorldDaylightMap} from 'world-daylight-map';
4 |
5 | export interface IWorldDaylightMapCompProps {
6 | pcfContext: ComponentFramework.Context
7 | }
8 |
9 | export const WorldDaylightMapComp: React.FC = (props) => {
10 | return(
11 |
22 |
);
23 | }
24 |
--------------------------------------------------------------------------------
/WorldDaylightMap/WorldDaylightMap/css/WorldDaylightMap.css:
--------------------------------------------------------------------------------
1 | .RAW\.WorldDaylightMap img {
2 | max-width: -webkit-fill-available;
3 | min-width: 0px;
4 | margin-left: auto;
5 | margin-right: auto;
6 | display: block;
7 | }
8 |
--------------------------------------------------------------------------------
/WorldDaylightMap/WorldDaylightMap/img/preview.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rwilson504/PCFControls/61d3085266806324fc5b48150a7a8a8a237eaffa/WorldDaylightMap/WorldDaylightMap/img/preview.png
--------------------------------------------------------------------------------
/WorldDaylightMap/featureconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | }
--------------------------------------------------------------------------------
/WorldDaylightMap/images/world-daylight-map.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rwilson504/PCFControls/61d3085266806324fc5b48150a7a8a8a237eaffa/WorldDaylightMap/images/world-daylight-map.png
--------------------------------------------------------------------------------
/WorldDaylightMap/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "pcf-project",
3 | "version": "1.0.0",
4 | "description": "Project containing your PowerApps Component Framework (PCF) control.",
5 | "scripts": {
6 | "build": "pcf-scripts build",
7 | "clean": "pcf-scripts clean",
8 | "lint": "pcf-scripts lint",
9 | "lint:fix": "pcf-scripts lint fix",
10 | "rebuild": "pcf-scripts rebuild",
11 | "start": "pcf-scripts start",
12 | "start:watch": "pcf-scripts start watch",
13 | "refreshTypes": "pcf-scripts refreshTypes"
14 | },
15 | "dependencies": {
16 | "@types/react-dom": "^18.2",
17 | "react": "^18.2",
18 | "react-dom": "^18.2",
19 | "world-daylight-map": "^2"
20 | },
21 | "devDependencies": {
22 | "@types/node": "^18.19",
23 | "@types/powerapps-component-framework": "^1.3",
24 | "@microsoft/eslint-plugin-power-apps": "^0.2.51",
25 | "@typescript-eslint/eslint-plugin": "^8.18.0",
26 | "@typescript-eslint/parser": "^8.18.0",
27 | "eslint": "^8.57.0",
28 | "eslint-plugin-import": "^2.31.0",
29 | "eslint-plugin-node": "^11.1.0",
30 | "eslint-plugin-promise": "^7.1.0",
31 | "pcf-scripts": "^1",
32 | "pcf-start": "^1",
33 | "typescript": "^4.9.5"
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/WorldDaylightMap/pcfconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "outDir": "./out/controls"
3 | }
--------------------------------------------------------------------------------
/WorldDaylightMap/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "./node_modules/pcf-scripts/tsconfig_base.json",
3 | "compilerOptions": {
4 | "typeRoots": ["node_modules/@types"],
5 | }
6 | }
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "devDependencies": {
3 | "vite-plugin-dts": "^4.5.4"
4 | }
5 | }
6 |
--------------------------------------------------------------------------------