Skip to content

Commit e131a35

Browse files
committedJul 22, 2022
Add the customizer template
1 parent 2a69f33 commit e131a35

13 files changed

+6722
-0
lines changed
 

‎.gitignore

+2
Original file line numberDiff line numberDiff line change
@@ -288,3 +288,5 @@ __pycache__/
288288
*.odx.cs
289289
*.xsd.cs
290290

291+
# MAC OS
292+
.DS_Store
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
{
2+
"env": {
3+
"browser": true,
4+
"es2021": true
5+
},
6+
"extends": [
7+
"eslint:recommended",
8+
"plugin:react/recommended"
9+
],
10+
"globals": {
11+
"ComponentFramework": true
12+
},
13+
"parser": "@typescript-eslint/parser",
14+
"parserOptions": {
15+
"ecmaVersion": 12,
16+
"sourceType": "module"
17+
},
18+
"plugins": [
19+
"@typescript-eslint"
20+
],
21+
"rules": {
22+
"no-unused-vars": "off"
23+
}
24+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
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
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<?xml version="1.0" encoding="utf-8" ?>
2+
<manifest>
3+
<control namespace="SampleNamespace" constructor="PAGridCustomizer" version="0.0.1" display-name-key="PAGridCustomizer" description-key="PAGridCustomizer description" control-type="virtual" >
4+
<property name="EventName" display-name-key="EventName" description-key="EventName" of-type="SingleLine.Text" usage="bound" required="true" />
5+
<resources>
6+
<code path="index.ts" order="1"/>
7+
<platform-library name="React" version="16.8.6" />
8+
<platform-library name="Fluent" version="8.29.0" />
9+
</resources>
10+
</control>
11+
</manifest>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import * as React from 'react';
2+
import { CellEditorOverrides } from '../types';
3+
4+
export const cellEditorOverrides: CellEditorOverrides = {
5+
["Text"]: (props, col) => {
6+
// TODO: Add your custom cell editor overrides here
7+
return null
8+
}
9+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import * as React from 'react';
2+
import { CellRendererOverrides } from '../types';
3+
4+
export const cellRendererOverrides: CellRendererOverrides = {
5+
["Text"]: (props, col) => {
6+
// TODO: Add your custom cell editor overrides here
7+
return null
8+
}
9+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import { IInputs, IOutputs } from "./generated/ManifestTypes";
2+
import { cellRendererOverrides } from "./customizers/CellRendererOverrides";
3+
import { cellEditorOverrides } from "./customizers/CellEditorOverrides";
4+
import { PAOneGridCustomizer } from "./types";
5+
import * as React from "react";
6+
7+
export class PAGridCustomizer implements ComponentFramework.ReactControl<IInputs, IOutputs> {
8+
/**
9+
* Empty constructor.
10+
*/
11+
constructor() { }
12+
13+
/**
14+
* Used to initialize the control instance. Controls can kick off remote server calls and other initialization actions here.
15+
* Data-set values are not initialized here, use updateView.
16+
* @param context The entire property bag available to control via Context Object; It contains values as set up by the customizer mapped to property names defined in the manifest, as well as utility functions.
17+
* @param notifyOutputChanged A callback method to alert the framework that the control has new outputs ready to be retrieved asynchronously.
18+
* @param state A piece of data that persists in one session for a single user. Can be set at any point in a controls life cycle by calling 'setControlState' in the Mode interface.
19+
*/
20+
public init(
21+
context: ComponentFramework.Context<IInputs>,
22+
notifyOutputChanged: () => void,
23+
state: ComponentFramework.Dictionary
24+
): void {
25+
const eventName = context.parameters.EventName.raw;
26+
if (eventName) {
27+
const paOneGridCustomizer: PAOneGridCustomizer = { cellRendererOverrides, cellEditorOverrides };
28+
(context as any).factory.fireEvent(eventName, paOneGridCustomizer);
29+
}
30+
}
31+
32+
/**
33+
* Called when any value in the property bag has changed. This includes field values, data-sets, global values such as container height and width, offline status, control metadata values such as label, visible, etc.
34+
* @param context The entire property bag available to control via Context Object; It contains values as set up by the customizer mapped to names defined in the manifest, as well as utility functions
35+
* @returns ReactElement root react element for the control
36+
*/
37+
public updateView(context: ComponentFramework.Context<IInputs>): React.ReactElement {
38+
return React.createElement(React.Fragment);
39+
}
40+
41+
/**
42+
* It is called by the framework prior to a control receiving new data.
43+
* @returns an object based on nomenclature defined in manifest, expecting object[s] for property marked as “bound” or “output”
44+
*/
45+
public getOutputs(): IOutputs {
46+
return {};
47+
}
48+
49+
/**
50+
* Called when the control is to be removed from the DOM tree. Controls should use this call for cleanup.
51+
* i.e. cancelling any pending remote calls, removing listeners, etc.
52+
*/
53+
public destroy(): void {
54+
// Add code to cleanup control if necessary
55+
}
56+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
1+
import * as React from "react";
2+
3+
/** Provides APIs to customize Power Apps OneGrid */
4+
export interface PAOneGridCustomizer {
5+
/**
6+
* Provides customizations for the grid.
7+
* This will include prop overrides, cell renderers and editors,
8+
* @notice If you just need to override few cell renderers or editors,
9+
* its better to use cellRendererOverrides, cellEditorOverrides props
10+
*/
11+
gridCustomizer?: GridCustomizer;
12+
/** Provides overrides for built -in cell renderers */
13+
cellRendererOverrides?: CellRendererOverrides;
14+
/** Provides overrides for built -in cell editors */
15+
cellEditorOverrides?: CellEditorOverrides;
16+
}
17+
18+
export interface CellRendererOverrides {
19+
[dataType: string]: (props: CellRendererProps, rendererParams: GetRendererParams)
20+
=> React.ReactElement | null | undefined;
21+
}
22+
23+
export interface CellEditorOverrides {
24+
[dataType: string]: (defaultProps: CellEditorProps, rendererParams: GetEditorParams)
25+
=> React.ReactElement | null | undefined;
26+
}
27+
28+
export interface GridCustomizer {
29+
/** Returns react element for the column headers */
30+
GetHeaderRenderer?(params: GetHeaderParams): React.ReactElement;
31+
/** Returns the cell renderer react element */
32+
GetCellRenderer?(params: GetRendererParams): React.ReactElement;
33+
/** Return renderer for a row in a loading state */
34+
GetLoadingRowRenderer?(): React.ReactElement;
35+
/** Returns the cell editor react element */
36+
GetCellEditor?(params: GetEditorParams): React.ReactElement;
37+
/** Returns the component and properties to use for empty grid overlay */
38+
GetNoRowsOverlayConfiguration?(): NoRowsOverlayConfig;
39+
}
40+
41+
export interface CellRendererProps {
42+
value: unknown;
43+
isRTLMode?: boolean;
44+
onCellClicked?: (event?: React.MouseEvent<HTMLElement, MouseEvent> | MouseEvent) => void;
45+
validationError?: Error | null;
46+
isRightAligned?: boolean;
47+
startEditing?: (editorInitValue?: unknown) => void;
48+
isLastRow?: boolean;
49+
rowHeight?: number;
50+
columnDataType?: ColumnDataType;
51+
formattedValue?: string;
52+
cellContainerElement?: HTMLElement;
53+
cellErrorLabelId?: string;
54+
columnEditable?: boolean;
55+
}
56+
57+
export interface GetRendererParams {
58+
colDefs: ColumnDefinition[];
59+
columnIndex: number;
60+
rowData?: RowData;
61+
/** Renderer can call this function to switch the cell to edit mode */
62+
startEditing?: (editorInitValue?: unknown) => void;
63+
isMobileLayout?: boolean;
64+
isRTLMode?: boolean;
65+
cellElement?: HTMLElement;
66+
allowTabKeyNavigation?: boolean;
67+
setExpanded?: (isExpanded: boolean) => void;
68+
getExpanded?: () => boolean;
69+
}
70+
71+
export interface CellEditorProps {
72+
secured?: boolean;
73+
value: unknown;
74+
isRTLMode?: boolean;
75+
rowHeight?: number;
76+
isRequired?: boolean;
77+
onFormat?: (newValue: unknown) => unknown;
78+
onValidate?: (newValue: unknown) => string;
79+
charPress?: string | null;
80+
columnDataType?: ColumnDataType;
81+
onChange(newValue: unknown): void;
82+
}
83+
84+
export interface GetEditorParams {
85+
colDefs: ColumnDefinition[];
86+
columnIndex: number;
87+
onCellValueChanged: (newValue: unknown) => void;
88+
rowData?: RowData;
89+
isMobileLayout?: boolean;
90+
isRTLMode?: boolean;
91+
/** the character pressed when the editor was activated */
92+
charPress?: string | null;
93+
stopEditing: (cancel?: boolean) => void;
94+
}
95+
96+
export interface GetHeaderParams {
97+
colDefs: ColumnDefinition[];
98+
columnIndex: number;
99+
isFirstVisualColumn?: boolean;
100+
isLastVisualColumn?: boolean;
101+
rowData?: RowData;
102+
isMobileLayout?: boolean;
103+
isRTLMode?: boolean;
104+
allowTabKeyNavigation?: boolean;
105+
}
106+
107+
export interface NoRowsOverlayConfig {
108+
component: React.ComponentClass | undefined;
109+
props: unknown | undefined;
110+
}
111+
112+
export const RECID = '__rec_id';
113+
export interface RowData {
114+
/** Unique id for the row */
115+
[RECID]: string;
116+
}
117+
118+
export interface ColumnDefinition {
119+
/** Field name (should be unique) */
120+
name: string;
121+
/** Column display name. Will be shown as column header.If none provided shimmer will be shown in place of header */
122+
displayName?: string;
123+
/** The unique ID to give the column. This is optional. If missing, the ID will default to the name.
124+
* If defined, this ID will be used to identify the column in the API for sorting and filtering. */
125+
colId?: string;
126+
/** Data type for the values in the column. */
127+
dataType: string;
128+
/** Custom Renderer type to be used for this column when custom renderer override is provided. */
129+
CustomRendererType?: string;
130+
/** Width of the column. Auto calculated if not set. */
131+
width?: number;
132+
/** Min width, in pixels, of the cell */
133+
minWidth?: number;
134+
/** Max width, in pixels, of the cell */
135+
maxWidth?: number;
136+
/** True if column is initially hidden
137+
* @Notice To show/hide columns after the first render use PAGridAPI.setColumnVisible()
138+
*/
139+
hide?: boolean;
140+
/** Column is primary field */
141+
isPrimary: boolean;
142+
}
143+
144+
export type ColumnDataType =
145+
| 'Text'
146+
| 'Email'
147+
| 'Phone'
148+
| 'Ticker'
149+
| 'URL'
150+
| 'TextArea'
151+
| 'Lookup'
152+
| 'Customer'
153+
| 'Owner'
154+
| 'MultiSelectPicklist'
155+
| 'OptionSet'
156+
| 'TwoOptions'
157+
| 'Duration'
158+
| 'Language'
159+
| 'Multiple'
160+
| 'TimeZone'
161+
| 'Integer'
162+
| 'Currency'
163+
| 'Decimal'
164+
| 'FloatingPoint'
165+
| 'AutoNumber'
166+
| 'DateOnly'
167+
| 'DateAndTime'
168+
| 'Image'
169+
| 'File'
170+
| 'Persona';
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<Project ToolsVersion="15.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
3+
<PropertyGroup>
4+
<PowerAppsTargetsPath>$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v$(VisualStudioVersion)\PowerApps</PowerAppsTargetsPath>
5+
</PropertyGroup>
6+
7+
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" />
8+
<Import Project="$(PowerAppsTargetsPath)\Microsoft.PowerApps.VisualStudio.Pcf.props" Condition="Exists('$(PowerAppsTargetsPath)\Microsoft.PowerApps.VisualStudio.Pcf.props')" />
9+
10+
<PropertyGroup>
11+
<Name>PowerAppsGridCustomizerControl</Name>
12+
<ProjectGuid>82cab210-4e37-471b-8150-43d377102d13</ProjectGuid>
13+
<OutputPath>$(MSBuildThisFileDirectory)out\controls</OutputPath>
14+
</PropertyGroup>
15+
16+
<PropertyGroup>
17+
<TargetFrameworkVersion>v4.6.2</TargetFrameworkVersion>
18+
<!--Remove TargetFramework when this is available in 16.1-->
19+
<TargetFramework>net462</TargetFramework>
20+
<RestoreProjectStyle>PackageReference</RestoreProjectStyle>
21+
</PropertyGroup>
22+
23+
<ItemGroup>
24+
<PackageReference Include="Microsoft.PowerApps.MSBuild.Pcf" Version="1.*" />
25+
<PackageReference Include="Microsoft.NETFramework.ReferenceAssemblies" Version="1.0.0" PrivateAssets="All" />
26+
</ItemGroup>
27+
28+
<ItemGroup>
29+
<ExcludeDirectories Include="$(MSBuildThisFileDirectory)\.gitignore" />
30+
<ExcludeDirectories Include="$(MSBuildThisFileDirectory)\bin\**" />
31+
<ExcludeDirectories Include="$(MSBuildThisFileDirectory)\obj\**" />
32+
<ExcludeDirectories Include="$(OutputPath)\**" />
33+
<ExcludeDirectories Include="$(MSBuildThisFileDirectory)\*.pcfproj" />
34+
<ExcludeDirectories Include="$(MSBuildThisFileDirectory)\*.pcfproj.user" />
35+
<ExcludeDirectories Include="$(MSBuildThisFileDirectory)\*.sln" />
36+
<ExcludeDirectories Include="$(MSBuildThisFileDirectory)\node_modules\**" />
37+
</ItemGroup>
38+
39+
<ItemGroup>
40+
<None Include="$(MSBuildThisFileDirectory)\**" Exclude="@(ExcludeDirectories)" />
41+
</ItemGroup>
42+
43+
<Import Project="$(MSBuildToolsPath)\Microsoft.Common.targets" />
44+
<Import Project="$(PowerAppsTargetsPath)\Microsoft.PowerApps.VisualStudio.Pcf.targets" Condition="Exists('$(PowerAppsTargetsPath)\Microsoft.PowerApps.VisualStudio.Pcf.targets')" />
45+
46+
</Project>

‎component-framework/PowerAppsGridCustomizerControl/package-lock.json

+6,340
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
{
2+
"name": "powerapps-grid-customizer-control",
3+
"version": "1.0.0",
4+
"description": "Project containing your PowerApps Grid Customizer control.",
5+
"scripts": {
6+
"build": "pcf-scripts build",
7+
"clean": "pcf-scripts clean",
8+
"rebuild": "pcf-scripts rebuild",
9+
"start": "pcf-scripts start",
10+
"refreshTypes": "pcf-scripts refreshTypes"
11+
},
12+
"dependencies": {
13+
"react": "16.8.6",
14+
"@fluentui/react": "8.29.0",
15+
"react-dom": "16.8.6"
16+
},
17+
"devDependencies": {
18+
"@types/node": "^16.4.10",
19+
"@types/powerapps-component-framework": "^1.3.0",
20+
"@types/react": "^16.8",
21+
"@typescript-eslint/eslint-plugin": "^4.29.0",
22+
"@typescript-eslint/parser": "^4.29.0",
23+
"eslint": "^7.32.0",
24+
"eslint-plugin-import": "^2.23.4",
25+
"eslint-plugin-node": "^11.1.0",
26+
"eslint-plugin-promise": "^5.1.0",
27+
"eslint-plugin-react": "^7.29.3",
28+
"pcf-scripts": "^1",
29+
"pcf-start": "^1",
30+
"typescript": "^4.3"
31+
}
32+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"outDir": "./out/controls"
3+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"extends": "./node_modules/pcf-scripts/tsconfig_base.json",
3+
"compilerOptions": {
4+
"typeRoots": ["node_modules/@types"],
5+
}
6+
}

0 commit comments

Comments
 (0)
Please sign in to comment.