Skip to content

Commit 9a4da45

Browse files
Searchbox (#49)
* Added SearchBox * updated searchbox * added comments to index * renamed component.types.ts and updated searchbox * added tests * enhancement Co-authored-by: Denise Moran <43950360+denisem-msft@users.noreply.github.com>
1 parent 1be5051 commit 9a4da45

36 files changed

+20987
-0
lines changed

SearchBox/.eslintrc.json

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
{
2+
"env": {
3+
"browser": true,
4+
"es2021": true
5+
},
6+
"extends": [
7+
"eslint:recommended",
8+
"plugin:react/recommended",
9+
"plugin:@typescript-eslint/recommended",
10+
"plugin:prettier/recommended",
11+
"prettier",
12+
"plugin:sonarjs/recommended"
13+
],
14+
"globals": {
15+
"ComponentFramework": true
16+
},
17+
"parser": "@typescript-eslint/parser",
18+
"parserOptions": {
19+
"ecmaFeatures": {
20+
"jsx": true
21+
},
22+
"ecmaVersion": 12,
23+
"sourceType": "module"
24+
},
25+
"plugins": [
26+
"react",
27+
"react-hooks",
28+
"@typescript-eslint",
29+
"prettier",
30+
"sonarjs"
31+
],
32+
"settings": {
33+
"react": {
34+
"pragma": "React",
35+
"version": "detect"
36+
}
37+
},
38+
"ignorePatterns": [
39+
"**/generated/*.ts"
40+
],
41+
"rules": {
42+
"eqeqeq": [
43+
2,
44+
"smart"
45+
],
46+
"react-hooks/exhaustive-deps": "warn",
47+
"prettier/prettier": "error",
48+
"arrow-body-style": "off",
49+
"prefer-arrow-callback": "off",
50+
"linebreak-style": [
51+
"error",
52+
"windows"
53+
],
54+
"quotes": [
55+
"error",
56+
"single"
57+
],
58+
"semi": [
59+
"error",
60+
"always"
61+
]
62+
}
63+
}

SearchBox/.gitignore

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
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+
# coverage directory
10+
/coverage
11+
12+
# output directory
13+
/out
14+
15+
# msbuild output directories
16+
/bin
17+
/obj

SearchBox/.prettierrc.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"semi": true,
3+
"trailingComma": "all",
4+
"singleQuote": true,
5+
"printWidth": 120,
6+
"tabWidth": 4,
7+
"endOfLine":"auto"
8+
}

SearchBox/README.md

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
# SearchBox
2+
3+
This code component provides a wrapper around the [Fluent UI SearchBox](https://developer.microsoft.com/en-us/fluentui#/controls/web/searchbox) control for use in canvas & custom pages.
4+
5+
| Canvas apps | Custom pages | Model-driven apps | Portals |
6+
| ----------- | ------------ | ----------------- | ------- |
7+
|||||
8+
9+
## Properties
10+
11+
### Output Properties
12+
13+
| Property | Description |
14+
| -------- | ----------- |
15+
| `SearchText` | The action items to render. The first item is considered the root item. |
16+
17+
### Style properties
18+
19+
| Property | Description |
20+
| -------- | ----------- |
21+
| `Theme` |Accepts a JSON string that is generated using [Fluent UI Theme Designer (windows.net)](https://fabricweb.z5.web.core.windows.net/pr-deploy-site/refs/heads/master/theming-designer/). Leaving this blank will use the default theme defined by Power Apps. Leaving this blank will use the default theme defined by Power Apps. See [theming](theme.md) for guidance on how to configure. |
22+
| `AccessibilityLabel` | Screen reader aria-label |
23+
24+
## Behavior
25+
26+
### Connecting SearchBox to a Datasource
27+
28+
On any dataset `Items` property (e.g., in a gallery or DetailsList controls), add the following Power Fx formula:
29+
30+
```Power Fx
31+
Search( Accounts, SearchBox_1.SearchText, "name" )
32+
```

SearchBox/SearchBox.pcfproj

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
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>SearchBox</Name>
12+
<ProjectGuid>6cfd43cf-c5c7-4352-a7b6-76221b622f52</ProjectGuid>
13+
<OutputPath>$(MSBuildThisFileDirectory)out\controls</OutputPath>
14+
<PcfBuildMode>production</PcfBuildMode>
15+
</PropertyGroup>
16+
17+
<PropertyGroup>
18+
<TargetFrameworkVersion>v4.6.2</TargetFrameworkVersion>
19+
<!--Remove TargetFramework when this is available in 16.1-->
20+
<TargetFramework>net462</TargetFramework>
21+
<RestoreProjectStyle>PackageReference</RestoreProjectStyle>
22+
</PropertyGroup>
23+
24+
<ItemGroup>
25+
<PackageReference Include="Microsoft.PowerApps.MSBuild.Pcf" Version="1.*" />
26+
<PackageReference Include="Microsoft.NETFramework.ReferenceAssemblies" Version="1.0.0" PrivateAssets="All" />
27+
</ItemGroup>
28+
29+
<ItemGroup>
30+
<ExcludeDirectories Include="$(MSBuildThisFileDirectory)\.gitignore" />
31+
<ExcludeDirectories Include="$(MSBuildThisFileDirectory)\bin\**" />
32+
<ExcludeDirectories Include="$(MSBuildThisFileDirectory)\obj\**" />
33+
<ExcludeDirectories Include="$(OutputPath)\**" />
34+
<ExcludeDirectories Include="$(MSBuildThisFileDirectory)\*.pcfproj" />
35+
<ExcludeDirectories Include="$(MSBuildThisFileDirectory)\*.pcfproj.user" />
36+
<ExcludeDirectories Include="$(MSBuildThisFileDirectory)\*.sln" />
37+
<ExcludeDirectories Include="$(MSBuildThisFileDirectory)\node_modules\**" />
38+
</ItemGroup>
39+
40+
<ItemGroup>
41+
<None Include="$(MSBuildThisFileDirectory)\**" Exclude="@(ExcludeDirectories)" />
42+
</ItemGroup>
43+
44+
<Import Project="$(MSBuildToolsPath)\Microsoft.Common.targets" />
45+
<Import Project="$(PowerAppsTargetsPath)\Microsoft.PowerApps.VisualStudio.Pcf.targets" Condition="Exists('$(PowerAppsTargetsPath)\Microsoft.PowerApps.VisualStudio.Pcf.targets')" />
46+
47+
</Project>
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<manifest>
3+
<control namespace="PowerCAT" constructor="SearchBox" version="0.0.1" display-name-key="SearchBox" description-key="SearchBox description" control-type="virtual">
4+
<property name="SearchText" display-name-key="SearchBox_SearchText" description-key="SearchBox_SearchText_Desc" of-type="SingleLine.Text" usage="output" hidden="true" />
5+
<property name="Theme" display-name-key="Theme" of-type="Multiple" usage="input" required="false" />
6+
<property name="AccessibilityLabel" display-name-key="AccessibilityLabel" of-type="SingleLine.Text" usage="input" required="false" />
7+
<property name="IconName" display-name-key="IconName" of-type="SingleLine.Text" usage="input" required="false" default-value="Search" />
8+
<property name="Underlined" display-name-key="Underlined" of-type="TwoOptions" usage="input" required="false" />
9+
<property name="DisableAnimation" display-name-key="DisableAnimation" of-type="TwoOptions" usage="input" required="false" />
10+
<property name="PlaceHolderText" display-name-key="PlaceHolderText" of-type="SingleLine.Text" usage="input" required="false" default-value="Search" />
11+
<resources>
12+
<code path="index.ts" order="1" />
13+
<resx path="strings/SearchBox.1033.resx" version="1.0.0" />
14+
<platform-library name="React" version="16.8.6" />
15+
<platform-library name="Fluent" version="8.29.0" />
16+
</resources>
17+
</control>
18+
</manifest>
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
/* istanbul ignore file */
2+
3+
export class MockContext<T> implements ComponentFramework.Context<T> {
4+
constructor(parameters: T) {
5+
this.parameters = parameters;
6+
this.mode = {
7+
allocatedHeight: -1,
8+
allocatedWidth: -1,
9+
isControlDisabled: false,
10+
isVisible: true,
11+
label: '',
12+
setControlState: jest.fn(),
13+
setFullScreen: jest.fn(),
14+
trackContainerResize: jest.fn(),
15+
};
16+
this.client = {
17+
disableScroll: false,
18+
getClient: jest.fn(),
19+
getFormFactor: jest.fn(),
20+
isOffline: jest.fn(),
21+
};
22+
23+
// Canvas apps currently assigns a positive tab-index
24+
// so we must use this property to assign a positive tab-index also
25+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
26+
(this as any).accessibility = { assignedTabIndex: 0 };
27+
}
28+
client: ComponentFramework.Client;
29+
device: ComponentFramework.Device;
30+
factory: ComponentFramework.Factory;
31+
formatting: ComponentFramework.Formatting;
32+
mode: ComponentFramework.Mode;
33+
navigation: ComponentFramework.Navigation;
34+
resources: ComponentFramework.Resources;
35+
userSettings: ComponentFramework.UserSettings;
36+
utils: ComponentFramework.Utility;
37+
webAPI: ComponentFramework.WebApi;
38+
parameters: T;
39+
updatedProperties: string[] = [];
40+
}
41+
42+
export class MockState implements ComponentFramework.Dictionary {}
43+
44+
export class MockStringProperty implements ComponentFramework.PropertyTypes.StringProperty {
45+
constructor(raw?: string | null, formatted?: string | undefined) {
46+
this.raw = raw ?? null;
47+
this.formatted = formatted;
48+
}
49+
raw: string | null;
50+
attributes?: ComponentFramework.PropertyHelper.FieldPropertyMetadata.StringMetadata | undefined;
51+
error: boolean;
52+
errorMessage: string;
53+
formatted?: string | undefined;
54+
security?: ComponentFramework.PropertyHelper.SecurityValues | undefined;
55+
type: string;
56+
}
57+
58+
export class MockWholeNumberProperty implements ComponentFramework.PropertyTypes.WholeNumberProperty {
59+
constructor(raw?: number | null, formatted?: string | undefined) {
60+
this.raw = raw ?? null;
61+
this.formatted = formatted;
62+
}
63+
attributes?: ComponentFramework.PropertyHelper.FieldPropertyMetadata.WholeNumberMetadata | undefined;
64+
raw: number | null;
65+
error: boolean;
66+
errorMessage: string;
67+
formatted?: string | undefined;
68+
security?: ComponentFramework.PropertyHelper.SecurityValues | undefined;
69+
type: string;
70+
}
71+
72+
export class MockDecimalNumberProperty implements ComponentFramework.PropertyTypes.DecimalNumberProperty {
73+
constructor(raw?: number | null, formatted?: string | undefined) {
74+
this.raw = raw ?? null;
75+
this.formatted = formatted;
76+
}
77+
attributes?: ComponentFramework.PropertyHelper.FieldPropertyMetadata.DecimalNumberMetadata | undefined;
78+
raw: number | null;
79+
error: boolean;
80+
errorMessage: string;
81+
formatted?: string | undefined;
82+
security?: ComponentFramework.PropertyHelper.SecurityValues | undefined;
83+
type: string;
84+
}
85+
86+
export class MockEnumProperty<T> implements ComponentFramework.PropertyTypes.EnumProperty<T> {
87+
constructor(raw?: T, type?: string) {
88+
if (raw) this.raw = raw;
89+
if (type) this.type = type;
90+
}
91+
type: string;
92+
raw: T;
93+
}
94+
95+
export class MockTwoOptionsProperty implements ComponentFramework.PropertyTypes.TwoOptionsProperty {
96+
constructor(raw?: boolean) {
97+
if (raw) this.raw = raw;
98+
}
99+
raw: boolean;
100+
attributes?: ComponentFramework.PropertyHelper.FieldPropertyMetadata.TwoOptionMetadata | undefined;
101+
error: boolean;
102+
errorMessage: string;
103+
formatted?: string | undefined;
104+
security?: ComponentFramework.PropertyHelper.SecurityValues | undefined;
105+
type: string;
106+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
/* istanbul ignore file */
2+
3+
import { IInputs } from '../generated/ManifestTypes';
4+
import { MockStringProperty, MockTwoOptionsProperty } from './mock-context';
5+
6+
export function getMockParameters(): IInputs {
7+
return {
8+
Theme: new MockStringProperty(),
9+
AccessibilityLabel: new MockStringProperty(),
10+
Underlined: new MockTwoOptionsProperty(),
11+
PlaceHolderText: new MockStringProperty(),
12+
IconName: new MockStringProperty(),
13+
DisableAnimation: new MockTwoOptionsProperty(),
14+
};
15+
}

0 commit comments

Comments
 (0)