diff --git a/CHANGELOG.json b/CHANGELOG.json index 14556a3b..afa68199 100644 --- a/CHANGELOG.json +++ b/CHANGELOG.json @@ -1,5 +1,16 @@ { "versions": [ + { + "version": "3.17.1", + "changes": { + "new": [], + "enhancements": [], + "fixes": [ + "Fixes for Webpack 5: [#621](https://github.com/pnp/sp-dev-fx-property-controls/pull/621)" + ] + }, + "contributions": [] + }, { "version": "3.17.0", "changes": { diff --git a/CHANGELOG.md b/CHANGELOG.md index 7fac9ab7..de7f4a29 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,10 +1,17 @@ # Releases +## 3.17.1 + +### Fixes + +- Fixes for Webpack 5: [#621](https://github.com/pnp/sp-dev-fx-property-controls/pull/621) + ## 3.17.0 ### New control(s) - `PropertyFieldButton`: New Control PropertyFieldButton [#613](https://github.com/pnp/sp-dev-fx-property-controls/pull/613) +- `PropertyFieldGrid`: New Control PropertyFieldGrid [#614](https://github.com/pnp/sp-dev-fx-property-controls/pull/614) ### Enhancements diff --git a/docs/documentation/docs/about/release-notes.md b/docs/documentation/docs/about/release-notes.md index 7fac9ab7..de7f4a29 100644 --- a/docs/documentation/docs/about/release-notes.md +++ b/docs/documentation/docs/about/release-notes.md @@ -1,10 +1,17 @@ # Releases +## 3.17.1 + +### Fixes + +- Fixes for Webpack 5: [#621](https://github.com/pnp/sp-dev-fx-property-controls/pull/621) + ## 3.17.0 ### New control(s) - `PropertyFieldButton`: New Control PropertyFieldButton [#613](https://github.com/pnp/sp-dev-fx-property-controls/pull/613) +- `PropertyFieldGrid`: New Control PropertyFieldGrid [#614](https://github.com/pnp/sp-dev-fx-property-controls/pull/614) ### Enhancements diff --git a/docs/documentation/docs/controls/PropertyFieldGrid.md b/docs/documentation/docs/controls/PropertyFieldGrid.md index 65935fd3..5321f0aa 100644 --- a/docs/documentation/docs/controls/PropertyFieldGrid.md +++ b/docs/documentation/docs/controls/PropertyFieldGrid.md @@ -4,7 +4,7 @@ This control generates a Grid Control . **PropertyFieldGrid example usage** -![PropertyFieldGrid example](../assets/propertyFieldGrid.png) +![PropertyFieldGrid example](../assets/PropertyFieldGrid.png) ## How to use this control in your solutions diff --git a/package-lock.json b/package-lock.json index 3d554dc5..e4c61f19 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@pnp/spfx-property-controls", - "version": "3.17.0", + "version": "3.17.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@pnp/spfx-property-controls", - "version": "3.17.0", + "version": "3.17.1", "hasInstallScript": true, "license": "MIT", "dependencies": { diff --git a/package.json b/package.json index 52b05cb8..94a981a1 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "@pnp/spfx-property-controls", "description": "Reusable property pane controls for SharePoint Framework solutions", - "version": "3.17.0", + "version": "3.17.1", "engines": { "node": ">=16.13.0 <17.0.0 || >=18.17.1 <19.0.0" }, diff --git a/src/common/placeholderWithCallout/PlaceholderWithCallout.tsx b/src/common/placeholderWithCallout/PlaceholderWithCallout.tsx index 2773224f..68ca01c2 100644 --- a/src/common/placeholderWithCallout/PlaceholderWithCallout.tsx +++ b/src/common/placeholderWithCallout/PlaceholderWithCallout.tsx @@ -1,8 +1,10 @@ import * as React from 'react'; -import { Callout, DirectionalHint } from '@fluentui/react/lib/components/Callout'; -import { IPlaceholderWithCalloutProps, IPlaceholderWithCalloutState } from './IPlaceholderWithCallout'; +import { Callout, DirectionalHint, getIconClassName } from '@fluentui/react'; +import { + IPlaceholderWithCalloutProps, + IPlaceholderWithCalloutState, +} from './IPlaceholderWithCallout'; import { CalloutTriggers } from '../callout/Callout'; -import { getIconClassName } from '@fluentui/react/lib/Styling'; import styles from './PlaceholderWithCallout.module.scss'; @@ -10,29 +12,49 @@ import styles from './PlaceholderWithCallout.module.scss'; * PlaceholderWithCallout component. * Displays a label and a callout */ -export default class PlaceholderWithCallout extends React.Component { - +export default class PlaceholderWithCallout extends React.Component< + IPlaceholderWithCalloutProps, + IPlaceholderWithCalloutState +> { private _infoIcon: HTMLElement; - public constructor(props: IPlaceholderWithCalloutProps, state: IPlaceholderWithCalloutState) { + public constructor( + props: IPlaceholderWithCalloutProps, + state: IPlaceholderWithCalloutState + ) { super(props, state); this._onCalloutDismiss = this._onCalloutDismiss.bind(this); this.state = { - isCalloutVisible: false + isCalloutVisible: false, }; } public render(): JSX.Element { return (
-
- {this.props.children} -
+
{this.props.children}
- { this._infoIcon = infoIcon; }} - onMouseOver={this.props.calloutTrigger === CalloutTriggers.Hover ? this._onInfoIconMouseOver.bind(this) : null} - onMouseOut={this.props.calloutTrigger === CalloutTriggers.Hover ? this._onInfoIconMouseOut.bind(this) : null} - onClick={this.props.calloutTrigger === CalloutTriggers.Click ? this._onInfoIconClick.bind(this) : null} /> + { + this._infoIcon = infoIcon; + }} + onMouseOver={ + this.props.calloutTrigger === CalloutTriggers.Hover + ? this._onInfoIconMouseOver.bind(this) + : null + } + onMouseOut={ + this.props.calloutTrigger === CalloutTriggers.Hover + ? this._onInfoIconMouseOut.bind(this) + : null + } + onClick={ + this.props.calloutTrigger === CalloutTriggers.Click + ? this._onInfoIconClick.bind(this) + : null + } + />
{this.state.isCalloutVisible && ( + gapSpace={ + this.props.gapSpace !== undefined ? this.props.gapSpace : 5 + } + calloutWidth={this.props.calloutWidth} + > {this.props.calloutContent} - ) - } -
); + )} + + ); } - private _onCalloutDismiss(): void { if (this.state.isCalloutVisible) { this.setState({ - isCalloutVisible: false + isCalloutVisible: false, }); } } @@ -67,7 +91,7 @@ export default class PlaceholderWithCallout extends React.Component { - +export default class PropertyFieldHeader extends React.Component< + IPropertyFieldHeaderProps, + IPropertyFieldHeaderState +> { private _infoIcon: HTMLElement; - public constructor(props: IPropertyFieldHeaderProps, state: IPropertyFieldHeaderState) { + public constructor( + props: IPropertyFieldHeaderProps, + state: IPropertyFieldHeaderState + ) { super(props, state); this._onCalloutDismiss = this._onCalloutDismiss.bind(this); this.state = { - isCalloutVisible: false + isCalloutVisible: false, }; } @@ -29,23 +41,40 @@ export default class PropertyFieldHeader extends React.Component -
- {label} -
+
+
{label}
{calloutContent && ( - { this._infoIcon = infoIcon; }} - onMouseOver={!disabled && calloutTrigger === CalloutTriggers.Hover ? this._onInfoIconMouseOver.bind(this) : null} - onMouseOut={!disabled && calloutTrigger === CalloutTriggers.Hover ? this._onInfoIconMouseOut.bind(this) : null} - onClick={!disabled && calloutTrigger === CalloutTriggers.Click ? this._onInfoIconClick.bind(this) : null} /> + { + this._infoIcon = infoIcon; + }} + onMouseOver={ + !disabled && calloutTrigger === CalloutTriggers.Hover + ? this._onInfoIconMouseOver.bind(this) + : null + } + onMouseOut={ + !disabled && calloutTrigger === CalloutTriggers.Hover + ? this._onInfoIconMouseOut.bind(this) + : null + } + onClick={ + !disabled && calloutTrigger === CalloutTriggers.Click + ? this._onInfoIconClick.bind(this) + : null + } + /> )}
{this.state.isCalloutVisible && ( @@ -57,19 +86,19 @@ export default class PropertyFieldHeader extends React.Component + calloutWidth={calloutWidth} + > {calloutContent} - ) - } -
); + )} + + ); } - private _onCalloutDismiss(): void { if (this.state.isCalloutVisible) { this.setState({ - isCalloutVisible: false + isCalloutVisible: false, }); } } @@ -81,7 +110,7 @@ export default class PropertyFieldHeader extends React.Component void | Promise; // eslint-disable-line @typescript-eslint/no-explicit-any - fValidation: (field: ICustomCollectionField, value: any) => Promise; // eslint-disable-line @typescript-eslint/no-explicit-any - } \ No newline at end of file + field: ICustomCollectionField; + item: any; // eslint-disable-line @typescript-eslint/no-explicit-any + disableEdit: boolean; + + fOnValueChange: (fieldId: string, value: any) => void | Promise; // eslint-disable-line @typescript-eslint/no-explicit-any + fValidation: (field: ICustomCollectionField, value: any) => Promise; // eslint-disable-line @typescript-eslint/no-explicit-any +} diff --git a/src/propertyFields/collectionData/ICustomCollectionField.ts b/src/propertyFields/collectionData/ICustomCollectionField.ts index 978228b9..722af640 100644 --- a/src/propertyFields/collectionData/ICustomCollectionField.ts +++ b/src/propertyFields/collectionData/ICustomCollectionField.ts @@ -1,11 +1,11 @@ -import { IDropdownOption } from '@fluentui/react/lib/Dropdown'; -import { ISelectableOption } from '@fluentui/react/lib/utilities/selectableOption/SelectableOption.types'; -import { IRenderFunction } from '@fluentui/react/lib/Utilities'; +import { + IDropdownOption, + IRenderFunction, + ISelectableOption, +} from '@fluentui/react'; import { CollectionIconFieldRenderMode } from './collectionIconField'; - -export interface ICustomDropdownOption extends Omit -{ +export interface ICustomDropdownOption extends Omit { key: string | number | boolean; } @@ -23,8 +23,8 @@ export interface ICustomCollectionField { */ type: CustomCollectionFieldType; /** - * Conditionally disable a field - */ + * Conditionally disable a field + */ disable?: (item: any) => boolean; // eslint-disable-line @typescript-eslint/no-explicit-any /** * Allows you to specify if a field is disabled for editing @@ -38,7 +38,9 @@ export interface ICustomCollectionField { * Dropdown options. Only nescessary when dropdown type is used. * Options can be either a static array or a function that will calculate the values dynamically and can react to the current item. */ - options?: ICustomDropdownOption[] | ((fieldId: string, item: any) => ICustomDropdownOption[]); // eslint-disable-line @typescript-eslint/no-explicit-any + options?: + | ICustomDropdownOption[] + | ((fieldId: string, item: any) => ICustomDropdownOption[]); // eslint-disable-line @typescript-eslint/no-explicit-any /** * Dropdown custom options render method. */ @@ -62,12 +64,23 @@ export interface ICustomCollectionField { * - If valid, it returns empty string. * - If invalid, the field will show a red border */ - onGetErrorMessage?: (value: any, index: number, currentItem: any) => string | Promise; // eslint-disable-line @typescript-eslint/no-explicit-any + onGetErrorMessage?: ( + value: any, + index: number, + currentItem: any + ) => string | Promise; // eslint-disable-line @typescript-eslint/no-explicit-any /** * Custom field rendering support */ - onCustomRender?: (field: ICustomCollectionField, value: any, onUpdate: (fieldId: string, value: any) => void, item: any, rowUniqueId: string, onCustomFieldValidation: (fieldId: string, errorMessage: string) => void) => JSX.Element; // eslint-disable-line @typescript-eslint/no-explicit-any + onCustomRender?: ( + field: ICustomCollectionField, + value: any, + onUpdate: (fieldId: string, value: any) => void, + item: any, + rowUniqueId: string, + onCustomFieldValidation: (fieldId: string, errorMessage: string) => void + ) => JSX.Element; // eslint-disable-line @typescript-eslint/no-explicit-any /** * Custom field visibility support */ @@ -87,5 +100,5 @@ export enum CustomCollectionFieldType { fabricIcon, url, custom, - color + color, } diff --git a/src/propertyFields/collectionData/IPropertyFieldCollectionData.ts b/src/propertyFields/collectionData/IPropertyFieldCollectionData.ts index 08042c88..2b962486 100644 --- a/src/propertyFields/collectionData/IPropertyFieldCollectionData.ts +++ b/src/propertyFields/collectionData/IPropertyFieldCollectionData.ts @@ -1,7 +1,6 @@ -import { IPropertyPaneCustomFieldProps } from "@microsoft/sp-property-pane"; -import { ICustomCollectionField } from "./ICustomCollectionField"; -import { IPanelProps } from "@fluentui/react/lib/Panel"; - +import { IPropertyPaneCustomFieldProps } from '@microsoft/sp-property-pane'; +import { ICustomCollectionField } from './ICustomCollectionField'; +import { IPanelProps } from '@fluentui/react'; export interface IPropertyFieldCollectionDataProps { /** @@ -74,4 +73,6 @@ export interface IPropertyFieldCollectionDataProps { panelProps?: IPanelProps; } -export interface IPropertyFieldCollectionDataPropsInternal extends IPropertyPaneCustomFieldProps, IPropertyFieldCollectionDataProps {} +export interface IPropertyFieldCollectionDataPropsInternal + extends IPropertyPaneCustomFieldProps, + IPropertyFieldCollectionDataProps {} diff --git a/src/propertyFields/collectionData/PropertyFieldCollectionData.ts b/src/propertyFields/collectionData/PropertyFieldCollectionData.ts index 09abcd39..95cdb270 100644 --- a/src/propertyFields/collectionData/PropertyFieldCollectionData.ts +++ b/src/propertyFields/collectionData/PropertyFieldCollectionData.ts @@ -4,8 +4,8 @@ import { IPropertyPaneField, PropertyPaneFieldType, } from '@microsoft/sp-property-pane'; - -import { PropertyFieldCollectionDataHost, IPropertyFieldCollectionDataPropsInternal, IPropertyFieldCollectionDataProps } from '.'; +import { IPropertyFieldCollectionDataProps, IPropertyFieldCollectionDataPropsInternal } from './IPropertyFieldCollectionData'; +import { PropertyFieldCollectionDataHost } from './PropertyFieldCollectionDataHost'; /** * Property Field Collection Data Builder Class diff --git a/src/propertyFields/collectionData/PropertyFieldCollectionDataHost.tsx b/src/propertyFields/collectionData/PropertyFieldCollectionDataHost.tsx index 4dcb4b48..b75b64da 100644 --- a/src/propertyFields/collectionData/PropertyFieldCollectionDataHost.tsx +++ b/src/propertyFields/collectionData/PropertyFieldCollectionDataHost.tsx @@ -1,15 +1,13 @@ -import * as React from "react"; -import * as telemetry from "../../common/telemetry"; +import * as React from 'react'; +import * as telemetry from '../../common/telemetry'; import { IPropertyFieldCollectionDataHostProps, IPropertyFieldCollectionDataHostState, -} from "./IPropertyFieldCollectionDataHost"; -import { DefaultButton } from "@fluentui/react/lib/components/Button"; -import { Panel, PanelType } from "@fluentui/react/lib/components/Panel"; -import { Label } from "@fluentui/react/lib/components/Label"; -import { CollectionDataViewer } from "./collectionDataViewer"; -import FieldErrorMessage from "../errorMessage/FieldErrorMessage"; -import * as strings from "PropertyControlStrings"; +} from './IPropertyFieldCollectionDataHost'; +import { DefaultButton, Panel, PanelType, Label } from '@fluentui/react'; +import { CollectionDataViewer } from './collectionDataViewer'; +import FieldErrorMessage from '../errorMessage/FieldErrorMessage'; +import * as strings from 'PropertyControlStrings'; export class PropertyFieldCollectionDataHost extends React.Component< IPropertyFieldCollectionDataHostProps, @@ -19,7 +17,7 @@ export class PropertyFieldCollectionDataHost extends React.Component< super(props); this.state = { - panelOpen: false + panelOpen: false, }; telemetry.track('PropertyFieldCollectionData', {}); @@ -30,7 +28,7 @@ export class PropertyFieldCollectionDataHost extends React.Component< */ private openPanel = (): void => { this.setState({ - panelOpen: true + panelOpen: true, }); }; @@ -39,17 +37,18 @@ export class PropertyFieldCollectionDataHost extends React.Component< */ private closePanel = (): void => { this.setState({ - panelOpen: false + panelOpen: false, }); }; /** * On save action */ - private onSave = (items: any[]): void => { // eslint-disable-line @typescript-eslint/no-explicit-any + private onSave = (items: any[]): void => { + // eslint-disable-line @typescript-eslint/no-explicit-any this.props.onChanged(items); this.setState({ - panelOpen: false + panelOpen: false, }); }; @@ -64,7 +63,9 @@ export class PropertyFieldCollectionDataHost extends React.Component< disabled={this.props.fields.length === 0 || this.props.disabled} /> - {this.props.fields.length === 0 && } + {this.props.fields.length === 0 && ( + + )} { /* no-op; */ }} - className={`PropertyFieldCollectionData__panel ${this.props.panelClassName || ""}`} - { - ...this.props.panelProps ?? {} - } + className={`PropertyFieldCollectionData__panel ${ + this.props.panelClassName || '' + }`} + {...(this.props.panelProps ?? {})} > {this.props.panelDescription && ( -

{this.props.panelDescription}

+

+ {this.props.panelDescription} +

)} - +
); diff --git a/src/propertyFields/collectionData/collectionCheckboxField/CollectionCheckboxField.tsx b/src/propertyFields/collectionData/collectionCheckboxField/CollectionCheckboxField.tsx index 66ec9cf6..de6593b0 100644 --- a/src/propertyFields/collectionData/collectionCheckboxField/CollectionCheckboxField.tsx +++ b/src/propertyFields/collectionData/collectionCheckboxField/CollectionCheckboxField.tsx @@ -1,6 +1,6 @@ import * as React from 'react'; import styles from '../PropertyFieldCollectionDataHost.module.scss'; -import { Checkbox } from '@fluentui/react/lib/components/Checkbox'; +import { Checkbox } from '@fluentui/react'; import { IBaseCollectionFieldProps } from '../IBaseCollectionFIeldsProps'; export interface ICollectionCheckboxFieldProps extends IBaseCollectionFieldProps { } diff --git a/src/propertyFields/collectionData/collectionColorField/CollectionColorField.tsx b/src/propertyFields/collectionData/collectionColorField/CollectionColorField.tsx index a2ce37cc..bc7acf91 100644 --- a/src/propertyFields/collectionData/collectionColorField/CollectionColorField.tsx +++ b/src/propertyFields/collectionData/collectionColorField/CollectionColorField.tsx @@ -1,9 +1,7 @@ import * as React from 'react'; import styles from '../PropertyFieldCollectionDataHost.module.scss'; import { ICollectionColorFieldProps } from './ICollectionColorFieldProps'; -import { Async } from '@fluentui/react/lib/Utilities'; -import { Callout, DirectionalHint } from '@fluentui/react/lib/Callout'; -import { ColorPicker } from '@fluentui/react/lib/ColorPicker'; +import { Callout, DirectionalHint, ColorPicker, Async } from '@fluentui/react'; import { ICustomCollectionField } from '../ICustomCollectionField'; interface ICollectionColorFieldState { diff --git a/src/propertyFields/collectionData/collectionColorField/ICollectionColorFieldProps.tsx b/src/propertyFields/collectionData/collectionColorField/ICollectionColorFieldProps.tsx index c9872a9f..953f52e1 100644 --- a/src/propertyFields/collectionData/collectionColorField/ICollectionColorFieldProps.tsx +++ b/src/propertyFields/collectionData/collectionColorField/ICollectionColorFieldProps.tsx @@ -1,3 +1,3 @@ -import { IBaseCollectionFieldProps } from "../IBaseCollectionFIeldsProps"; +import { IBaseCollectionFieldProps } from '../IBaseCollectionFIeldsProps'; -export interface ICollectionColorFieldProps extends IBaseCollectionFieldProps { } +export interface ICollectionColorFieldProps extends IBaseCollectionFieldProps {} diff --git a/src/propertyFields/collectionData/collectionDataItem/CollectionDataItem.tsx b/src/propertyFields/collectionData/collectionDataItem/CollectionDataItem.tsx index 0a9900e8..42cd2625 100644 --- a/src/propertyFields/collectionData/collectionDataItem/CollectionDataItem.tsx +++ b/src/propertyFields/collectionData/collectionDataItem/CollectionDataItem.tsx @@ -1,14 +1,20 @@ import * as React from 'react'; import styles from '../PropertyFieldCollectionDataHost.module.scss'; -import { ICollectionDataItemProps, ICollectionDataItemState } from '.'; -import { TextField } from '@fluentui/react/lib/components/TextField'; -import { Icon } from '@fluentui/react/lib/components/Icon'; -import { Link } from '@fluentui/react/lib/components/Link'; +import { + TextField, + Icon, + Link, + Dropdown, + IDropdownOption, + Callout, + DirectionalHint, +} from '@fluentui/react'; import * as strings from 'PropertyControlStrings'; -import { ICustomCollectionField, CustomCollectionFieldType } from '../ICustomCollectionField'; +import { + ICustomCollectionField, + CustomCollectionFieldType, +} from '../ICustomCollectionField'; import { FieldValidator } from '../FieldValidator'; -import { Dropdown, IDropdownOption } from '@fluentui/react/lib/components/Dropdown'; -import { Callout, DirectionalHint } from '@fluentui/react/lib/components/Callout'; import { CollectionIconField } from '../collectionIconField'; import { clone, findIndex, sortBy } from '@microsoft/sp-lodash-subset'; import { CollectionNumberField } from '../collectionNumberField'; @@ -16,8 +22,13 @@ import { CollectionColorField } from '../collectionColorField'; import { Guid } from '@microsoft/sp-core-library'; import { CollectionDropdownField } from '../collectionDropdownField/CollectionDropdownField'; import { CollectionCheckboxField } from '../collectionCheckboxField/CollectionCheckboxField'; +import { ICollectionDataItemProps } from './ICollectionDataItemProps'; +import { ICollectionDataItemState } from './ICollectionDataItemState'; -export class CollectionDataItem extends React.Component { +export class CollectionDataItem extends React.Component< + ICollectionDataItemProps, + ICollectionDataItemState +> { private validation: FieldValidator = {}; private calloutCellRef: HTMLElement; @@ -28,10 +39,10 @@ export class CollectionDataItem extends React.Component => { // eslint-disable-line @typescript-eslint/no-explicit-any - return new Promise((resolve) => this.setState((prevState: ICollectionDataItemState) => { - const { crntItem } = prevState; - // Update the changed field - crntItem[fieldId] = value; - - // Store this in the current state - return { crntItem }; - }, () => resolve())); - } + private onValueChanged = (fieldId: string, value: any): Promise => { + // eslint-disable-line @typescript-eslint/no-explicit-any + return new Promise((resolve) => + this.setState( + (prevState: ICollectionDataItemState) => { + const { crntItem } = prevState; + // Update the changed field + crntItem[fieldId] = value; + + // Store this in the current state + return { crntItem }; + }, + () => resolve() + ) + ); + }; /** * Perform all required field checks at once @@ -68,7 +85,7 @@ export class CollectionDataItem extends React.Component { const { crntItem } = this.state; - let disableAdd : boolean = null; + let disableAdd: boolean = null; // Check if current item is valid if (this.props.fAddInCreation) { @@ -92,12 +109,17 @@ export class CollectionDataItem extends React.Component f.required); + const requiredFields = this.props.fields.filter((f) => f.required); // Check all the required field values for (const field of requiredFields) { - if (typeof item[field.id] === "undefined" || item[field.id] === null || item[field.id] === "") { + if ( + typeof item[field.id] === 'undefined' || + item[field.id] === null || + item[field.id] === '' + ) { return false; } } @@ -108,10 +130,15 @@ export class CollectionDataItem extends React.Component { // eslint-disable-line @typescript-eslint/no-explicit-any + private async checkAnyFieldCustomErrorMessage(item: any): Promise { + // eslint-disable-line @typescript-eslint/no-explicit-any const { fields, index } = this.props; - - const validations = await Promise.all(fields.filter(f => f.onGetErrorMessage).map(async f => { - const validation = await f.onGetErrorMessage(item[f.id], index, item); - return this.storeFieldValidation(f.id, validation); - })); - return validations.filter(v => v && v.length > 0).length === 0; + const validations = await Promise.all( + fields + .filter((f) => f.onGetErrorMessage) + .map(async (f) => { + const validation = await f.onGetErrorMessage(item[f.id], index, item); + return this.storeFieldValidation(f.id, validation); + }) + ); + + return validations.filter((v) => v && v.length > 0).length === 0; } /** * Check if row is ready for save */ - private async checkRowIsValidForSave(item: any): Promise { // eslint-disable-line @typescript-eslint/no-explicit-any - return this.checkAllRequiredFieldsValid(item) && + private async checkRowIsValidForSave(item: any): Promise { + // eslint-disable-line @typescript-eslint/no-explicit-any + return ( + this.checkAllRequiredFieldsValid(item) && this.checkAnyFieldContainsValue(item) && - await this.checkAnyFieldCustomErrorMessage(item) && - this.checkAllFieldsAreValid(); + (await this.checkAnyFieldCustomErrorMessage(item)) && + this.checkAllFieldsAreValid() + ); } /** @@ -170,11 +205,11 @@ export class CollectionDataItem extends React.Component => { // eslint-disable-line @typescript-eslint/no-explicit-any - let validation = ""; + private fieldValidation = async ( + field: ICustomCollectionField, + value: any + ): Promise => { + // eslint-disable-line @typescript-eslint/no-explicit-any + let validation = ''; // Do the custom validation check if (field.onGetErrorMessage) { // Set initial field validation this.validation[field.id] = false; // Do the validation - validation = await field.onGetErrorMessage(value, this.props.index, this.state.crntItem); + validation = await field.onGetErrorMessage( + value, + this.props.index, + this.state.crntItem + ); } return this.storeFieldValidation(field.id, validation, true); - } + }; /** * Updates callout and validation state */ - private async storeFieldValidation(fieldId: string, validation: string, doAllFieldChecks: boolean = false): Promise { + private async storeFieldValidation( + fieldId: string, + validation: string, + doAllFieldChecks: boolean = false + ): Promise { // Store the field validation - this.validation[fieldId] = validation === ""; + this.validation[fieldId] = validation === ''; // Add message for the error callout this.errorCalloutHandler(fieldId, validation); - if(doAllFieldChecks) { + if (doAllFieldChecks) { await this.doAllFieldChecks(); } return validation; @@ -241,12 +288,15 @@ export class CollectionDataItem extends React.Component => { + private onCustomFieldValidation = async ( + fieldId: string, + errorMsg: string + ): Promise => { console.log(fieldId, errorMsg); if (fieldId) { await this.storeFieldValidation(fieldId, errorMsg, true); } - } + }; /** * URL field validation @@ -255,24 +305,30 @@ export class CollectionDataItem extends React.Component => { // eslint-disable-line @typescript-eslint/no-explicit-any + private urlFieldValidation = async ( + field: ICustomCollectionField, + value: any, + item: any + ): Promise => { + // eslint-disable-line @typescript-eslint/no-explicit-any let isValid = true; - let validation = ""; + let validation = ''; // Check if custom validation is configured if (field.onGetErrorMessage) { // Using the custom validation validation = await field.onGetErrorMessage(value, this.props.index, item); - isValid = validation === ""; + isValid = validation === ''; } else { // Check if entered value is a valid URL - const regEx: RegExp = /(http|https)?:\/\/(www\.)?[-a-zA-Z0-9@:%._+~#=]{2,256}\.[a-z]{2,6}\b([-a-zA-Z0-9@:%_+.~#?&//=]*)/; - isValid = (value === null || value.length === 0 || regEx.test(value)); - validation = isValid ? "" : strings.InvalidUrlError; + const regEx: RegExp = + /(http|https)?:\/\/(www\.)?[-a-zA-Z0-9@:%._+~#=]{2,256}\.[a-z]{2,6}\b([-a-zA-Z0-9@:%_+.~#?&//=]*)/; + isValid = value === null || value.length === 0 || regEx.test(value); + validation = isValid ? '' : strings.InvalidUrlError; } return this.storeFieldValidation(field.id, validation, true); - } + }; /** * Error callout message handler @@ -286,21 +342,24 @@ export class CollectionDataItem extends React.Component f.id === fieldId); + const fieldIdx = findIndex(this.props.fields, (f) => f.id === fieldId); if (fieldIdx === -1) { return; } const field = this.props.fields[fieldIdx]; // Check if there already is a message for the field - const fieldMsgIdx = findIndex(errorMsgs, msg => msg.field === field.title); + const fieldMsgIdx = findIndex( + errorMsgs, + (msg) => msg.field === field.title + ); // Add message let fieldMsg; if (fieldMsgIdx === -1) { fieldMsg = { field: field.title, - message: message + message: message, }; } else { // Update message @@ -312,7 +371,11 @@ export class CollectionDataItem extends React.Component { this.setState((prevState: ICollectionDataItemState) => ({ - showCallout: !prevState.showCallout + showCallout: !prevState.showCallout, })); - } + }; private hideErrorCallout = (): void => { this.setState({ - showCallout: false + showCallout: false, }); - } + }; /** * Render the field @@ -361,50 +424,131 @@ export class CollectionDataItem extends React.Component; + return ( + + ); case CustomCollectionFieldType.dropdown: - return ; + return ( + + ); case CustomCollectionFieldType.number: - return ; + return ( + + ); case CustomCollectionFieldType.fabricIcon: - return ; - case CustomCollectionFieldType.color: - return ; + return ( + + ); + case CustomCollectionFieldType.color: + return ( + + ); case CustomCollectionFieldType.url: - return this.onValueChanged(field.id, value)} - deferredValidationTime={field.deferredValidationTime || field.deferredValidationTime >= 0 ? field.deferredValidationTime : 200} - onGetErrorMessage={async (value: string) => this.urlFieldValidation(field, value, item)} - inputClassName="PropertyFieldCollectionData__panel__url-field" />; + return ( + this.onValueChanged(field.id, value)} + deferredValidationTime={ + field.deferredValidationTime || field.deferredValidationTime >= 0 + ? field.deferredValidationTime + : 200 + } + onGetErrorMessage={async (value: string) => + this.urlFieldValidation(field, value, item) + } + inputClassName='PropertyFieldCollectionData__panel__url-field' + /> + ); case CustomCollectionFieldType.custom: - if (field.onCustomRender) { - return field.onCustomRender(field, item[field.id], (fieldId, value) => { - this.onValueChanged(fieldId, value).then(() => { - this.fieldValidation(field, value).then(() => { /* no-op; */ }).catch(() => { /* no-op; */ }); - }).catch(() => { /* no-op; */ }); - }, item, item.uniqueId, this.onCustomFieldValidation); - } - return null; + if (field.onCustomRender) { + return field.onCustomRender( + field, + item[field.id], + (fieldId, value) => { + this.onValueChanged(fieldId, value) + .then(() => { + this.fieldValidation(field, value) + .then(() => { + /* no-op; */ + }) + .catch(() => { + /* no-op; */ + }); + }) + .catch(() => { + /* no-op; */ + }); + }, + item, + item.uniqueId, + this.onCustomFieldValidation + ); + } + return null; case CustomCollectionFieldType.string: default: - return this.onValueChanged(field.id, value)} - deferredValidationTime={field.deferredValidationTime || field.deferredValidationTime >= 0 ? field.deferredValidationTime : 200} - onGetErrorMessage={async (value: string) => await this.fieldValidation(field, value)} - inputClassName="PropertyFieldCollectionData__panel__string-field" />; + return ( + this.onValueChanged(field.id, value)} + deferredValidationTime={ + field.deferredValidationTime || field.deferredValidationTime >= 0 + ? field.deferredValidationTime + : 200 + } + onGetErrorMessage={async (value: string) => + await this.fieldValidation(field, value) + } + inputClassName='PropertyFieldCollectionData__panel__string-field' + /> + ); } } @@ -417,16 +561,17 @@ export class CollectionDataItem extends React.Component - { - (this.props.sortingEnabled && this.props.totalItems) && ( - - this.props.fOnSorting(this.props.index, opt.key as number) } /> - - ) - } - { - (this.props.sortingEnabled && this.props.totalItems === null) && ( - - ) - } - { - this.props.fields.map(f => ( - {this.renderField(f, crntItem)} - )) - } +
+ {this.props.sortingEnabled && this.props.totalItems && ( + + + this.props.fOnSorting(this.props.index, opt.key as number) + } + /> + + )} + {this.props.sortingEnabled && this.props.totalItems === null && ( + + )} + {this.props.fields.map((f) => ( + + {this.renderField(f, crntItem)} + + ))} - { this.calloutCellRef = ref; }}> - - + { + this.calloutCellRef = ref; + }} + > + + + {this.state.showCallout && ( + + {this.state.errorMsgs && this.state.errorMsgs.length > 0 && ( +
+

{strings.CollectionDataItemFieldIssuesLabel}

+
    + {this.state.errorMsgs.map((msg, idx) => ( +
  • + {msg.field}:{' '} + {msg.message + ? msg.message + : msg.isRequired + ? strings.CollectionDataItemFieldRequiredLabel + : null} +
  • + ))} +
+
+ )} +
+ )} +
+ + { - this.state.showCallout && ( - - { - (this.state.errorMsgs && this.state.errorMsgs.length > 0) && ( -
-

{strings.CollectionDataItemFieldIssuesLabel}

-
    - { - this.state.errorMsgs.map((msg, idx) => ( -
  • {msg.field}: {msg.message ? msg.message : msg.isRequired ? strings.CollectionDataItemFieldRequiredLabel : null}
  • - )) - } -
-
- ) + /* Check add or delete action */ + this.props.index !== null ? ( + + onClick={this.deleteRow} + > + + + ) : ( + await this.addRow()} + > + + ) }
- - - { - /* Check add or delete action */ - this.props.index !== null ? ( - - - - ) : ( - await this.addRow()}> - - - ) - } -
); } diff --git a/src/propertyFields/collectionData/collectionDataItem/ICollectionDataItemProps.ts b/src/propertyFields/collectionData/collectionDataItem/ICollectionDataItemProps.ts index 714e9273..e7dbd6fa 100644 --- a/src/propertyFields/collectionData/collectionDataItem/ICollectionDataItemProps.ts +++ b/src/propertyFields/collectionData/collectionDataItem/ICollectionDataItemProps.ts @@ -1,4 +1,4 @@ -import { ICustomCollectionField } from "../ICustomCollectionField"; +import { ICustomCollectionField } from '../ICustomCollectionField'; export interface ICollectionDataItemProps { fields: ICustomCollectionField[]; diff --git a/src/propertyFields/collectionData/collectionDataItem/ICollectionDataItemState.ts b/src/propertyFields/collectionData/collectionDataItem/ICollectionDataItemState.ts index 1b6725c9..6248f1b3 100644 --- a/src/propertyFields/collectionData/collectionDataItem/ICollectionDataItemState.ts +++ b/src/propertyFields/collectionData/collectionDataItem/ICollectionDataItemState.ts @@ -1,4 +1,4 @@ -import { ErrorMsg } from "./ErrorMsg"; +import { ErrorMsg } from './ErrorMsg'; export interface ICollectionDataItemState { crntItem: any; // eslint-disable-line @typescript-eslint/no-explicit-any diff --git a/src/propertyFields/collectionData/collectionDataViewer/CollectionDataViewer.tsx b/src/propertyFields/collectionData/collectionDataViewer/CollectionDataViewer.tsx index 91f73bb6..c916008e 100644 --- a/src/propertyFields/collectionData/collectionDataViewer/CollectionDataViewer.tsx +++ b/src/propertyFields/collectionData/collectionDataViewer/CollectionDataViewer.tsx @@ -3,13 +3,19 @@ import styles from '../PropertyFieldCollectionDataHost.module.scss'; import { ICollectionDataViewerProps } from './ICollectionDataViewerProps'; import { ICollectionDataViewerState } from './ICollectionDataViewerState'; import { CollectionDataItem } from '../collectionDataItem'; -import { PrimaryButton, DefaultButton } from '@fluentui/react/lib/components/Button'; -import { Icon } from '@fluentui/react/lib/components/Icon'; +import { + PrimaryButton, + DefaultButton, + Icon +} from '@fluentui/react'; import * as strings from 'PropertyControlStrings'; import { cloneDeep, sortBy } from '@microsoft/sp-lodash-subset'; -export class CollectionDataViewer extends React.Component { - private readonly SORT_IDX = "sortIdx"; +export class CollectionDataViewer extends React.Component< + ICollectionDataViewerProps, + ICollectionDataViewerState +> { + private readonly SORT_IDX = 'sortIdx'; constructor(props: ICollectionDataViewerProps) { super(props); @@ -18,7 +24,7 @@ export class CollectionDataViewer extends React.Component { if (!item[this.SORT_IDX]) { item[this.SORT_IDX] = idx + 1; @@ -36,56 +44,64 @@ export class CollectionDataViewer extends React.Component { // eslint-disable-line @typescript-eslint/no-explicit-any - this.setState((prevState: ICollectionDataViewerState): ICollectionDataViewerState => { - let crntItems = [...prevState.crntItems, item]; - crntItems = this.updateSortProperty(crntItems); - return { - crntItems, - inCreationItem: null, - inCreationItemValid: null - }; - }); - } + private addItem = (item: any): void => { + // eslint-disable-line @typescript-eslint/no-explicit-any + this.setState( + (prevState: ICollectionDataViewerState): ICollectionDataViewerState => { + let crntItems = [...prevState.crntItems, item]; + crntItems = this.updateSortProperty(crntItems); + return { + crntItems, + inCreationItem: null, + inCreationItemValid: null, + }; + } + ); + }; /** * Remove an item from the collection */ - private updateItem = (idx: number, item: any): void => { // eslint-disable-line @typescript-eslint/no-explicit-any - this.setState((prevState: ICollectionDataViewerState): ICollectionDataViewerState => { - const { crntItems } = prevState; - // Update the item in the array - crntItems[idx] = item; - return { crntItems }; - }); - } + private updateItem = (idx: number, item: any): void => { + // eslint-disable-line @typescript-eslint/no-explicit-any + this.setState( + (prevState: ICollectionDataViewerState): ICollectionDataViewerState => { + const { crntItems } = prevState; + // Update the item in the array + crntItems[idx] = item; + return { crntItems }; + } + ); + }; /** * Remove an item from the collection */ private deleteItem = (idx: number): void => { - this.setState((prevState: ICollectionDataViewerState): ICollectionDataViewerState => { - let { crntItems } = prevState; - const { validation } = prevState; - crntItems.splice(idx, 1); - delete validation[idx]; + this.setState( + (prevState: ICollectionDataViewerState): ICollectionDataViewerState => { + let { crntItems } = prevState; + const { validation } = prevState; + crntItems.splice(idx, 1); + delete validation[idx]; - // Update the sort propety - crntItems = this.updateSortProperty(crntItems); + // Update the sort propety + crntItems = this.updateSortProperty(crntItems); - return { - crntItems: sortBy(crntItems, this.SORT_IDX), - validation: validation - }; - }); - } + return { + crntItems: sortBy(crntItems, this.SORT_IDX), + validation: validation, + }; + } + ); + }; /** * Validate every item @@ -95,10 +111,10 @@ export class CollectionDataViewer extends React.Component { // eslint-disable-line @typescript-eslint/no-explicit-any + private addInCreation = (item: any, isValid: boolean): void => { + // eslint-disable-line @typescript-eslint/no-explicit-any this.setState({ inCreationItem: item, - inCreationItemValid: isValid + inCreationItemValid: isValid, }); - } + }; /** * Add the item and save the form @@ -138,7 +155,7 @@ export class CollectionDataViewer extends React.Component -1 && newIdx < crntItems.length) { const removedElement = crntItems.splice(oldIdx, 1)[0]; if (removedElement) { @@ -162,7 +180,8 @@ export class CollectionDataViewer extends React.Component { item[this.SORT_IDX] = itemIdx + 1; @@ -182,89 +201,135 @@ export class CollectionDataViewer extends React.Component { this.props.fOnSave(this.state.crntItems); - } + }; /** * Cancel */ private onCancel = (): void => { this.props.fOnClose(); - } + }; /** * Default React render */ public render(): React.ReactElement { - const crntItems = [...this.state.crntItems, this.state.inCreationItem].filter(i => i); - const visibleFields = this.props.fields.filter(f => !f.isVisible || f.isVisible(f, crntItems)); + const crntItems = [ + ...this.state.crntItems, + this.state.inCreationItem, + ].filter((i) => i); + const visibleFields = this.props.fields.filter( + (f) => !f.isVisible || f.isVisible(f, crntItems) + ); return (
-
-
- { - this.props.enableSorting && ( - - ) - } - { - visibleFields.map(f => ( - {f.title} { f.required && } - )) - } - - +
+
+ {this.props.enableSorting && ( + + )} + {visibleFields.map((f) => ( + + {f.title}{' '} + {f.required && ( + + )} + + ))} + +
- { - (this.state.crntItems && this.state.crntItems.length > 0) && ( - this.state.crntItems.map((item, idx, allItems) => ( - - )) - ) - } + {this.state.crntItems && + this.state.crntItems.length > 0 && + this.state.crntItems.map((item, idx, allItems) => ( + + ))} - { - !this.props.disableItemCreation && ( - - ) - } + {!this.props.disableItemCreation && ( + + )}
- { - (!this.state.crntItems || this.state.crntItems.length === 0) && ( -

{strings.CollectionDataEmptyValue}

- ) - } + {(!this.state.crntItems || this.state.crntItems.length === 0) && ( +

+ {strings.CollectionDataEmptyValue} +

+ )} -
- { this.state.inCreationItem && this.state.inCreationItemValid && } - { !(this.state.inCreationItem && this.state.inCreationItemValid) && } - +
+ {this.state.inCreationItem && this.state.inCreationItemValid && ( + + )} + {!(this.state.inCreationItem && this.state.inCreationItemValid) && ( + + )} +
); diff --git a/src/propertyFields/collectionData/collectionDataViewer/ICollectionDataViewerProps.ts b/src/propertyFields/collectionData/collectionDataViewer/ICollectionDataViewerProps.ts index 9f61b7b3..d1d0bf9f 100644 --- a/src/propertyFields/collectionData/collectionDataViewer/ICollectionDataViewerProps.ts +++ b/src/propertyFields/collectionData/collectionDataViewer/ICollectionDataViewerProps.ts @@ -1,6 +1,7 @@ -import { IPropertyFieldCollectionDataHostProps } from "../IPropertyFieldCollectionDataHost"; +import { IPropertyFieldCollectionDataHostProps } from '../IPropertyFieldCollectionDataHost'; -export interface ICollectionDataViewerProps extends IPropertyFieldCollectionDataHostProps { +export interface ICollectionDataViewerProps + extends IPropertyFieldCollectionDataHostProps { fOnSave: (items: any[]) => void; // eslint-disable-line @typescript-eslint/no-explicit-any fOnClose: () => void; } diff --git a/src/propertyFields/collectionData/collectionDataViewer/ICollectionDataViewerState.ts b/src/propertyFields/collectionData/collectionDataViewer/ICollectionDataViewerState.ts index cca207ac..2a0794f9 100644 --- a/src/propertyFields/collectionData/collectionDataViewer/ICollectionDataViewerState.ts +++ b/src/propertyFields/collectionData/collectionDataViewer/ICollectionDataViewerState.ts @@ -1,4 +1,4 @@ -import { FieldValidator } from "../FieldValidator"; +import { FieldValidator } from '../FieldValidator'; export interface ICollectionDataViewerState { crntItems: any[]; // eslint-disable-line @typescript-eslint/no-explicit-any diff --git a/src/propertyFields/collectionData/collectionDropdownField/CollectionDropdownField.tsx b/src/propertyFields/collectionData/collectionDropdownField/CollectionDropdownField.tsx index b7a7c77b..1253af8b 100644 --- a/src/propertyFields/collectionData/collectionDropdownField/CollectionDropdownField.tsx +++ b/src/propertyFields/collectionData/collectionDropdownField/CollectionDropdownField.tsx @@ -1,5 +1,5 @@ -import { Dropdown, IDropdownOption } from '@fluentui/react/lib/Dropdown'; import * as React from 'react'; +import { Dropdown, IDropdownOption } from '@fluentui/react'; import { ICustomDropdownOption } from '../ICustomCollectionField'; import { IBaseCollectionFieldProps } from '../IBaseCollectionFIeldsProps'; import styles from '../PropertyFieldCollectionDataHost.module.scss'; diff --git a/src/propertyFields/collectionData/collectionIconField/CollectionIconField.tsx b/src/propertyFields/collectionData/collectionIconField/CollectionIconField.tsx index ce6f2fef..98e0c103 100644 --- a/src/propertyFields/collectionData/collectionIconField/CollectionIconField.tsx +++ b/src/propertyFields/collectionData/collectionIconField/CollectionIconField.tsx @@ -1,9 +1,7 @@ import * as React from 'react'; import styles from '../PropertyFieldCollectionDataHost.module.scss'; import { ICollectionIconFieldProps } from '.'; -import { TextField } from '@fluentui/react/lib/components/TextField'; -import { Icon } from '@fluentui/react/lib/components/Icon'; -import { ActionButton } from '@fluentui/react/lib/Button'; +import { TextField, Icon, ActionButton } from '@fluentui/react'; import { IconSelector } from '../../../common/iconSelector/IconSelector'; interface ICollectionIconFieldState { diff --git a/src/propertyFields/collectionData/collectionIconField/ICollectionIconFieldProps.tsx b/src/propertyFields/collectionData/collectionIconField/ICollectionIconFieldProps.tsx index 0fef34f7..73435fe0 100644 --- a/src/propertyFields/collectionData/collectionIconField/ICollectionIconFieldProps.tsx +++ b/src/propertyFields/collectionData/collectionIconField/ICollectionIconFieldProps.tsx @@ -1,7 +1,7 @@ -import { IBaseCollectionFieldProps } from "../IBaseCollectionFIeldsProps"; +import { IBaseCollectionFieldProps } from '../IBaseCollectionFIeldsProps'; export type CollectionIconFieldRenderMode = 'textbox' | 'picker'; -export interface ICollectionIconFieldProps extends IBaseCollectionFieldProps { +export interface ICollectionIconFieldProps extends IBaseCollectionFieldProps { renderMode?: CollectionIconFieldRenderMode; } diff --git a/src/propertyFields/collectionData/collectionIconField/index.ts b/src/propertyFields/collectionData/collectionIconField/index.ts index 968ce03a..cc1eee05 100644 --- a/src/propertyFields/collectionData/collectionIconField/index.ts +++ b/src/propertyFields/collectionData/collectionIconField/index.ts @@ -1,2 +1,2 @@ -export * from "./ICollectionIconFieldProps"; -export * from "./CollectionIconField"; +export * from './ICollectionIconFieldProps'; +export * from './CollectionIconField'; diff --git a/src/propertyFields/collectionData/collectionNumberField/CollectionNumberField.tsx b/src/propertyFields/collectionData/collectionNumberField/CollectionNumberField.tsx index 948b4374..f5ca76c8 100644 --- a/src/propertyFields/collectionData/collectionNumberField/CollectionNumberField.tsx +++ b/src/propertyFields/collectionData/collectionNumberField/CollectionNumberField.tsx @@ -1,25 +1,37 @@ import * as React from 'react'; import styles from '../PropertyFieldCollectionDataHost.module.scss'; -import { Async } from '@fluentui/react/lib/Utilities'; +import { Async } from '@fluentui/react'; import { ICollectionNumberFieldProps } from './ICollectionNumberFieldProps'; import { ICollectionNumberFieldState } from './ICollectionNumberFieldState'; import { ICustomCollectionField } from '../ICustomCollectionField'; import { isEqual } from '@microsoft/sp-lodash-subset'; -export class CollectionNumberField extends React.Component { +export class CollectionNumberField extends React.Component< + ICollectionNumberFieldProps, + ICollectionNumberFieldState +> { private async: Async; - private delayedValidate: (field: ICustomCollectionField, inputVal: number) => void; + private delayedValidate: ( + field: ICustomCollectionField, + inputVal: number + ) => void; constructor(props: ICollectionNumberFieldProps) { super(props); this.state = { value: null, - errorMessage: '' + errorMessage: '', }; this.async = new Async(this); - this.delayedValidate = this.async.debounce(this.valueValidation, (this.props.field.deferredValidationTime || this.props.field.deferredValidationTime >= 0) ? this.props.field.deferredValidationTime : 200); + this.delayedValidate = this.async.debounce( + this.valueValidation, + this.props.field.deferredValidationTime || + this.props.field.deferredValidationTime >= 0 + ? this.props.field.deferredValidationTime + : 200 + ); } /** @@ -27,9 +39,15 @@ export class CollectionNumberField extends React.Component { /* no-op; */ }).catch(() => { /* no-op; */ }); + this.valueChange(this.props.field, this.props.item[this.props.field.id]) + .then(() => { + /* no-op; */ + }) + .catch(() => { + /* no-op; */ + }); } /** @@ -38,10 +56,13 @@ export class CollectionNumberField extends React.Component => { - const inputVal = typeof value === "string" ? parseInt(value) : value; + private valueChange = async ( + field: ICustomCollectionField, + value: string | number + ): Promise => { + const inputVal = typeof value === 'string' ? parseInt(value) : value; this.setState({ - value: inputVal + value: inputVal, }); await this.props.fOnValueChange(field.id, value); this.delayedValidate(field, inputVal); - } + }; /** * Delayed field validation */ - private valueValidation = async (field: ICustomCollectionField, value: number): Promise => { + private valueValidation = async ( + field: ICustomCollectionField, + value: number + ): Promise => { // debugger; const validation = await this.props.fValidation(field, value); // Update the error message this.setState({ - errorMessage: validation + errorMessage: validation, }); - } + }; /** * Default React render method */ public render(): React.ReactElement { - const { - errorMessage, - value - } = this.state; + const { errorMessage, value } = this.state; return ( -
- + await this.valueChange(this.props.field, ev.target.value)} - disabled={this.props.disableEdit} /> + value={!value && value !== 0 ? '' : value} + onChange={async (ev) => + await this.valueChange(this.props.field, ev.target.value) + } + disabled={this.props.disableEdit} + />
); } diff --git a/src/propertyFields/collectionData/collectionNumberField/ICollectionNumberFieldProps.ts b/src/propertyFields/collectionData/collectionNumberField/ICollectionNumberFieldProps.ts index 246a37b4..a1845936 100644 --- a/src/propertyFields/collectionData/collectionNumberField/ICollectionNumberFieldProps.ts +++ b/src/propertyFields/collectionData/collectionNumberField/ICollectionNumberFieldProps.ts @@ -1,3 +1,4 @@ -import { IBaseCollectionFieldProps } from "../IBaseCollectionFIeldsProps"; +import { IBaseCollectionFieldProps } from '../IBaseCollectionFIeldsProps'; -export interface ICollectionNumberFieldProps extends IBaseCollectionFieldProps { } +export interface ICollectionNumberFieldProps + extends IBaseCollectionFieldProps {} diff --git a/src/propertyFields/colorPicker/IPropertyFieldColorPicker.ts b/src/propertyFields/colorPicker/IPropertyFieldColorPicker.ts index bbdd0645..ca7849b8 100644 --- a/src/propertyFields/colorPicker/IPropertyFieldColorPicker.ts +++ b/src/propertyFields/colorPicker/IPropertyFieldColorPicker.ts @@ -1,5 +1,5 @@ import { IPropertyPaneCustomFieldProps } from '@microsoft/sp-property-pane'; -import { IColor } from '@fluentui/react/lib/utilities/color'; +import { IColor } from '@fluentui/react'; /** * Enum for specifying how the control should be shown diff --git a/src/propertyFields/colorPicker/PropertyFieldColorPicker.ts b/src/propertyFields/colorPicker/PropertyFieldColorPicker.ts index a80d80a6..c884f814 100644 --- a/src/propertyFields/colorPicker/PropertyFieldColorPicker.ts +++ b/src/propertyFields/colorPicker/PropertyFieldColorPicker.ts @@ -1,5 +1,5 @@ import { IPropertyPaneField, PropertyPaneFieldType } from '@microsoft/sp-property-pane'; -import { getColorFromString, IColor } from '@fluentui/react/lib/utilities/color'; +import { getColorFromString, IColor } from '@fluentui/react'; import * as React from 'react'; import * as ReactDom from 'react-dom'; import { setPropertyValue } from '../../helpers/GeneralHelper'; diff --git a/src/propertyFields/dateTimePicker/HoursComponent.tsx b/src/propertyFields/dateTimePicker/HoursComponent.tsx index b8800706..010e0ed1 100644 --- a/src/propertyFields/dateTimePicker/HoursComponent.tsx +++ b/src/propertyFields/dateTimePicker/HoursComponent.tsx @@ -1,7 +1,7 @@ import * as React from 'react'; import { IHoursComponentProps } from './IPropertyFieldDateTimePickerHost'; import { TimeConvention } from './IPropertyFieldDateTimePicker'; -import { Dropdown, IDropdownOption } from '@fluentui/react/lib/components/Dropdown'; +import { Dropdown, IDropdownOption } from '@fluentui/react'; /** * Hours component, this renders the hours dropdown diff --git a/src/propertyFields/dateTimePicker/IPropertyFieldDateTimePickerHost.ts b/src/propertyFields/dateTimePicker/IPropertyFieldDateTimePickerHost.ts index 7a5cd898..fa8567db 100644 --- a/src/propertyFields/dateTimePicker/IPropertyFieldDateTimePickerHost.ts +++ b/src/propertyFields/dateTimePicker/IPropertyFieldDateTimePickerHost.ts @@ -1,5 +1,5 @@ import { IPropertyFieldDateTimePickerPropsInternal, TimeConvention } from './IPropertyFieldDateTimePicker'; -import { IDropdownOption } from '@fluentui/react/lib/components/Dropdown'; +import { IDropdownOption } from '@fluentui/react'; /** * PropertyFieldDateTimePickerHost properties interface diff --git a/src/propertyFields/dateTimePicker/MinutesComponent.tsx b/src/propertyFields/dateTimePicker/MinutesComponent.tsx index bcd3fe38..71a0f4d4 100644 --- a/src/propertyFields/dateTimePicker/MinutesComponent.tsx +++ b/src/propertyFields/dateTimePicker/MinutesComponent.tsx @@ -1,6 +1,6 @@ import * as React from 'react'; import { ITimeComponentProps } from './IPropertyFieldDateTimePickerHost'; -import { Dropdown, IDropdownOption } from '@fluentui/react/lib/components/Dropdown'; +import { Dropdown, IDropdownOption } from '@fluentui/react'; /** * Minutes component, renders the minutes dropdown diff --git a/src/propertyFields/dateTimePicker/SecondsComponent.tsx b/src/propertyFields/dateTimePicker/SecondsComponent.tsx index c0d8b4eb..59176bcd 100644 --- a/src/propertyFields/dateTimePicker/SecondsComponent.tsx +++ b/src/propertyFields/dateTimePicker/SecondsComponent.tsx @@ -1,6 +1,6 @@ import * as React from 'react'; import { ITimeComponentProps } from './IPropertyFieldDateTimePickerHost'; -import { Dropdown, IDropdownOption } from '@fluentui/react/lib/components/Dropdown'; +import { Dropdown, IDropdownOption } from '@fluentui/react'; /** * Seconds component, renders the seconds dropdown diff --git a/src/propertyFields/dropdownWithCallout/IPropertyFieldDropdownWithCalloutHost.ts b/src/propertyFields/dropdownWithCallout/IPropertyFieldDropdownWithCalloutHost.ts index dd810bb5..8674960e 100644 --- a/src/propertyFields/dropdownWithCallout/IPropertyFieldDropdownWithCalloutHost.ts +++ b/src/propertyFields/dropdownWithCallout/IPropertyFieldDropdownWithCalloutHost.ts @@ -1,5 +1,5 @@ import { IPropertyFieldHeaderCalloutProps } from '../../common/propertyFieldHeader/IPropertyFieldHeader'; -import { IDropdownProps } from '@fluentui/react/lib/components/Dropdown'; +import { IDropdownProps } from '@fluentui/react'; /** * PropertyFieldDropdownWithCalloutHost properties interface diff --git a/src/propertyFields/dropdownWithCallout/PropertyFieldDropdownWithCallout.ts b/src/propertyFields/dropdownWithCallout/PropertyFieldDropdownWithCallout.ts index eda6bc2b..fa865ecd 100644 --- a/src/propertyFields/dropdownWithCallout/PropertyFieldDropdownWithCallout.ts +++ b/src/propertyFields/dropdownWithCallout/PropertyFieldDropdownWithCallout.ts @@ -9,7 +9,7 @@ import { import PropertyFieldDropdownHost from './PropertyFieldDropdownWithCalloutHost'; import omit from 'lodash/omit'; import { IPropertyFieldDropdownWithCalloutPropsInternal, IPropertyFieldDropdownWithCalloutProps } from './IPropertyFieldDropdownWithCallout'; -import { IDropdownOption } from '@fluentui/react/lib/components/Dropdown'; +import { IDropdownOption } from '@fluentui/react'; class PropertyFieldDropdownWithCalloutBuilder implements IPropertyPaneField { public targetProperty: string; diff --git a/src/propertyFields/dropdownWithCallout/PropertyFieldDropdownWithCalloutHost.tsx b/src/propertyFields/dropdownWithCallout/PropertyFieldDropdownWithCalloutHost.tsx index b3c57f8d..701a9785 100644 --- a/src/propertyFields/dropdownWithCallout/PropertyFieldDropdownWithCalloutHost.tsx +++ b/src/propertyFields/dropdownWithCallout/PropertyFieldDropdownWithCalloutHost.tsx @@ -4,39 +4,53 @@ import type { IPropertyFieldHeaderProps } from '../../common/propertyFieldHeader import { IPropertyFieldDropdownWithCalloutHostProps } from './IPropertyFieldDropdownWithCalloutHost'; import * as telemetry from '../../common/telemetry'; -import { Dropdown, IDropdownProps, IDropdownOption } from '@fluentui/react/lib/components/Dropdown'; +import { + Dropdown, + IDropdownProps, + IDropdownOption, + SelectableOptionMenuItemType, +} from '@fluentui/react'; import { IPropertyPaneDropdownOption } from '@microsoft/sp-property-pane'; -import { SelectableOptionMenuItemType } from '@fluentui/react/lib/utilities/selectableOption/SelectableOption.types'; import omit from 'lodash/omit'; -export default class PropertyFieldDropdownHost extends React.Component { - constructor(props: IPropertyFieldDropdownWithCalloutHostProps) { - super(props); +export default class PropertyFieldDropdownHost extends React.Component< + IPropertyFieldDropdownWithCalloutHostProps, + null +> { + constructor(props: IPropertyFieldDropdownWithCalloutHostProps) { + super(props); - telemetry.track('PropertyFieldDropdown', { - disabled: props.disabled - }); - } + telemetry.track('PropertyFieldDropdown', { + disabled: props.disabled, + }); + } - public render(): JSX.Element { - const dropdownProps: IDropdownProps = omit(this.props, ['label']); - dropdownProps.options = this._convertPropPaneOptionsToDropdownOptions(dropdownProps.options); - return ( -
- - -
- ); - } + public render(): JSX.Element { + const dropdownProps: IDropdownProps = omit(this.props, ['label']); + dropdownProps.options = this._convertPropPaneOptionsToDropdownOptions( + dropdownProps.options + ); + return ( +
+ + +
+ ); + } - private _convertPropPaneOptionsToDropdownOptions(propPaneOptions: IPropertyPaneDropdownOption[]): IDropdownOption[] { - return propPaneOptions.map(propPaneOption => { - return { - key: propPaneOption.key, - text: propPaneOption.text, - index: propPaneOption.index, - itemType: SelectableOptionMenuItemType[SelectableOptionMenuItemType[propPaneOption.type]] - }; - }); - } + private _convertPropPaneOptionsToDropdownOptions( + propPaneOptions: IPropertyPaneDropdownOption[] + ): IDropdownOption[] { + return propPaneOptions.map((propPaneOption) => { + return { + key: propPaneOption.key, + text: propPaneOption.text, + index: propPaneOption.index, + itemType: + SelectableOptionMenuItemType[ + SelectableOptionMenuItemType[propPaneOption.type] + ], + }; + }); + } } diff --git a/src/propertyFields/filePicker/PropertyFieldFilePickerHost.tsx b/src/propertyFields/filePicker/PropertyFieldFilePickerHost.tsx index 50afbe27..72e7e665 100644 --- a/src/propertyFields/filePicker/PropertyFieldFilePickerHost.tsx +++ b/src/propertyFields/filePicker/PropertyFieldFilePickerHost.tsx @@ -1,6 +1,6 @@ import * as React from 'react'; -import { IconButton } from "@fluentui/react/lib/components/Button"; +import { IconButton } from '@fluentui/react'; import * as strings from 'PropertyControlStrings'; import { FilePicker, IFilePickerResult } from './filePickerControls'; @@ -10,45 +10,76 @@ import { GeneralHelper, setPropertyValue } from '../../helpers/GeneralHelper'; import * as telemetry from '../../common/telemetry'; /** -* Renders the control for PropertyFieldFilePicker component -*/ + * Renders the control for PropertyFieldFilePicker component + */ export default class PropertyFieldFilePickerHost extends React.Component { - constructor(props: IPropertyFieldFilePickerHostProps) { super(props); telemetry.track('PropertyFieldFilePicker', { - disabled: props.disabled + disabled: props.disabled, }); } public render(): JSX.Element { return (
- {this.props.filePickerResult && this.props.filePickerResult.fileAbsoluteUrl && ( -
- {GeneralHelper.isImage(this.props.filePickerResult.fileName) && - {this.props.filePickerResult.fileName} - } -
- { this.handleFileSave(null).then(() => { /* no-op; */ }).catch(() => { /* no-op; */ }); }} - disabled={this.props.disabled} /> - {this.props.filePickerResult.fileName} + {this.props.filePickerResult && + this.props.filePickerResult.fileAbsoluteUrl && ( +
+ {GeneralHelper.isImage(this.props.filePickerResult.fileName) && ( + {this.props.filePickerResult.fileName} + )} +
+ { + this.handleFileSave(null) + .then(() => { + /* no-op; */ + }) + .catch(() => { + /* no-op; */ + }); + }} + disabled={this.props.disabled} + /> + {this.props.filePickerResult.fileName} +
-
- )} + )} { this.handleFileSave(filePickerResult).then(() => { /* no-op; */ }).catch(() => { /* no-op; */ }); }} - onChanged={(filePickerResult: IFilePickerResult) => { this.handleFileChange(filePickerResult).then(() => { /* no-op; */ }).catch(() => { /* no-op; */ }); }} + buttonIcon={ + this.props.buttonIcon ? this.props.buttonIcon : 'FileImage' + } + onSave={(filePickerResult: IFilePickerResult) => { + this.handleFileSave(filePickerResult) + .then(() => { + /* no-op; */ + }) + .catch(() => { + /* no-op; */ + }); + }} + onChanged={(filePickerResult: IFilePickerResult) => { + this.handleFileChange(filePickerResult) + .then(() => { + /* no-op; */ + }) + .catch(() => { + /* no-op; */ + }); + }} onCancel={this.handleCancel} context={this.props.context} filePickerResult={this.props.filePickerResult} @@ -56,15 +87,51 @@ export default class PropertyFieldFilePickerHost extends React.Component => { - + private handleFileSave = async ( + filePickerResult: IFilePickerResult + ): Promise => { this.props.onSave(filePickerResult); - setPropertyValue(this.props.properties, this.props.targetProperty, filePickerResult); - this.props.onPropertyChange(this.props.targetProperty, this.props.filePickerResult, filePickerResult); + setPropertyValue( + this.props.properties, + this.props.targetProperty, + filePickerResult + ); + this.props.onPropertyChange( + this.props.targetProperty, + this.props.filePickerResult, + filePickerResult + ); - if (typeof this.props.onChange !== 'undefined' && this.props.onChange !== null) { + if ( + typeof this.props.onChange !== 'undefined' && + this.props.onChange !== null + ) { this.props.onChange(this.props.targetProperty, filePickerResult); } - } - - private handleFileChange = async (filePickerResult: IFilePickerResult): Promise => { + }; + private handleFileChange = async ( + filePickerResult: IFilePickerResult + ): Promise => { this.props.onChanged(filePickerResult); - if (typeof this.props.onChange !== 'undefined' && this.props.onChange !== null) { + if ( + typeof this.props.onChange !== 'undefined' && + this.props.onChange !== null + ) { this.props.onChange(this.props.targetProperty, filePickerResult); } - } + }; private handleCancel = (): void => { if (this.props.onCancel) { this.props.onCancel(); } - } - + }; } diff --git a/src/propertyFields/filePicker/filePickerControls/FilePicker.tsx b/src/propertyFields/filePicker/filePickerControls/FilePicker.tsx index 596bbd70..75aa69c3 100644 --- a/src/propertyFields/filePicker/filePickerControls/FilePicker.tsx +++ b/src/propertyFields/filePicker/filePickerControls/FilePicker.tsx @@ -1,12 +1,17 @@ import * as React from 'react'; import { IFilePickerProps } from './IFilePickerProps'; import { IFilePickerState } from './IFilePickerState'; - -import { PrimaryButton, ActionButton } from '@fluentui/react/lib/components/Button'; -import { Panel, PanelType } from '@fluentui/react/lib/components/Panel'; -import { Label } from '@fluentui/react/lib/components/Label'; -import { Nav, INavLink, INavLinkGroup } from '@fluentui/react/lib/Nav'; -import { css } from '@fluentui/react/lib/Utilities'; +import { + Label, + Nav, + INavLink, + INavLinkGroup, + Panel, + PanelType, + PrimaryButton, + ActionButton, + css, +} from '@fluentui/react'; // Localization import * as strings from 'PropertyControlStrings'; @@ -26,7 +31,10 @@ import { FilePickerTabType, IFilePickerResult } from './FilePicker.types'; import { FilesSearchService } from '../../../services/FilesSearchService'; import { StockImages } from './StockImagesTab'; -export class FilePicker extends React.Component { +export class FilePicker extends React.Component< + IFilePickerProps, + IFilePickerState +> { private fileBrowserService: FileBrowserService; private oneDriveService: OneDriveService; private orgAssetsService: OrgAssetsService; @@ -36,16 +44,30 @@ export class FilePicker extends React.Component this._handleClosePanel(), - onSave: (value: IFilePickerResult) => { this._handleSave(value); } + onSave: (value: IFilePickerResult) => { + this._handleSave(value); + }, }; const buttonProps = { text: this.props.buttonLabel, disabled: this.props.disabled, onClick: this._handleOpenPanel, - className: `pnp__file-picker__button ${buttonClassName}` + className: `pnp__file-picker__button ${buttonClassName}`, }; return (
- { - this.props.label && - } - { - this.props.buttonIcon ? - : - - } + {this.props.label && ( + + )} + {this.props.buttonIcon ? ( + + ) : ( + + )} - { return undefined; }} + onRenderNavigation={() => { + return undefined; + }} headerText={strings.FilePickerHeader} isLightDismiss={true} onRenderHeader={() => this._renderHeader()} > -
- { - this.state.selectedTab === FilePickerTabType.LinkUploadTab && + {this.state.selectedTab === FilePickerTabType.LinkUploadTab && ( - } - { - this.state.selectedTab === FilePickerTabType.StockImagesTab && + )} + {this.state.selectedTab === FilePickerTabType.StockImagesTab && ( - } - { - this.state.selectedTab === FilePickerTabType.LocalUploadTab && - - } - { - this.state.selectedTab === FilePickerTabType.SiteFilesTab && + )} + {this.state.selectedTab === FilePickerTabType.LocalUploadTab && ( + + )} + {this.state.selectedTab === FilePickerTabType.SiteFilesTab && ( - } - { - this.state.selectedTab === FilePickerTabType.OrganisationalAssetTab && + )} + {this.state.selectedTab === + FilePickerTabType.OrganisationalAssetTab && ( - } - { - this.state.selectedTab === FilePickerTabType.WebSearchTab && + )} + {this.state.selectedTab === FilePickerTabType.WebSearchTab && ( - } - { - this.state.selectedTab === FilePickerTabType.OneDriveTab && + )} + {this.state.selectedTab === FilePickerTabType.OneDriveTab && ( - } - { - this.state.selectedTab === FilePickerTabType.RecentTab && + )} + {this.state.selectedTab === FilePickerTabType.RecentTab && ( - } - + )}
-
+
); } @@ -188,8 +217,14 @@ export class FilePicker extends React.Component { - return

{strings.FilePickerHeader}

; - } + return ( +
+

+ {strings.FilePickerHeader} +

+
+ ); + }; /** * Open the panel @@ -197,9 +232,11 @@ export class FilePicker extends React.Component { this.setState({ panelOpen: true, - selectedTab: this.props.defaultSelectedTab ? this.props.defaultSelectedTab : FilePickerTabType.RecentTab + selectedTab: this.props.defaultSelectedTab + ? this.props.defaultSelectedTab + : FilePickerTabType.RecentTab, }); - } + }; /** * Closes the panel @@ -207,9 +244,9 @@ export class FilePicker extends React.Component { this.props.onCancel(); this.setState({ - panelOpen: false + panelOpen: false, }); - } + }; /** * On save action @@ -217,16 +254,19 @@ export class FilePicker extends React.Component { this.props.onSave(filePickerResult); this.setState({ - panelOpen: false + panelOpen: false, }); - } + }; /** * Changes the selected tab when a link is selected */ - private _handleLinkClick = (ev?: React.MouseEvent, item?: INavLink): void => { + private _handleLinkClick = ( + ev?: React.MouseEvent, + item?: INavLink + ): void => { this.setState({ selectedTab: item.key }); - } + }; /** * Prepares navigation panel options @@ -259,7 +299,10 @@ export class FilePicker extends React.Component { +export default class LinkFilePickerTab extends React.Component< + ILinkFilePickerTabProps, + ILinkFilePickerTabState +> { constructor(props: ILinkFilePickerTabProps) { super(props); this.state = { isValid: false }; } public render(): React.ReactElement { - const fileUrl = this.state.filePickerResult ? this.state.filePickerResult.fileAbsoluteUrl : null; + const fileUrl = this.state.filePickerResult + ? this.state.filePickerResult.fileAbsoluteUrl + : null; return (
@@ -31,10 +34,20 @@ export default class LinkFilePickerTab extends React.Component this._getErrorMessagePromise(value)} + label={ + this.props.allowExternalLinks + ? strings.ExternalLinkFileInstructions + : strings.LinkFileInstructions + } + ariaLabel={ + this.props.allowExternalLinks + ? strings.ExternalLinkFileInstructions + : strings.LinkFileInstructions + } + defaultValue={'https://'} + onGetErrorMessage={(value: string) => + this._getErrorMessagePromise(value) + } autoAdjustHeight={false} underlined={false} borderless={false} @@ -50,8 +63,17 @@ export default class LinkFilePickerTab extends React.Component this._handleSave()} className={styles.actionButton}>{strings.OpenButtonLabel} - this._handleClose()} className={styles.actionButton}>{strings.CancelButtonLabel} + onClick={() => this._handleSave()} + className={styles.actionButton} + > + {strings.OpenButtonLabel} + + this._handleClose()} + className={styles.actionButton} + > + {strings.CancelButtonLabel} +
@@ -62,16 +84,25 @@ export default class LinkFilePickerTab extends React.Component { - const filePickerResult: IFilePickerResult = fileUrl && this._isUrl(fileUrl) ? { - fileAbsoluteUrl: fileUrl, - fileName: GeneralHelper.getFileNameFromUrl(fileUrl), - fileNameWithoutExtension: GeneralHelper.getFileNameWithoutExtension(fileUrl), - downloadFileContent: () => { return this.props.fileSearchService.downloadBingContent(fileUrl, GeneralHelper.getFileNameFromUrl(fileUrl)); } - } : null; + const filePickerResult: IFilePickerResult = + fileUrl && this._isUrl(fileUrl) + ? { + fileAbsoluteUrl: fileUrl, + fileName: GeneralHelper.getFileNameFromUrl(fileUrl), + fileNameWithoutExtension: + GeneralHelper.getFileNameWithoutExtension(fileUrl), + downloadFileContent: () => { + return this.props.fileSearchService.downloadBingContent( + fileUrl, + GeneralHelper.getFileNameFromUrl(fileUrl) + ); + }, + } + : null; this.setState({ - filePickerResult + filePickerResult, }); - } + }; /** * Verifies the url that was typed in @@ -96,31 +127,33 @@ export default class LinkFilePickerTab extends React.Component { this.props.onSave(this.state.filePickerResult); - } + }; /** * HAndles when user closes without saving */ private _handleClose = (): void => { this.props.onClose(); - } + }; /** * Is this a URL ? @@ -133,11 +166,13 @@ export default class LinkFilePickerTab extends React.Component { const siteUrl: string = this.props.context.pageContext.web.absoluteUrl; - return GeneralHelper.getAbsoluteDomainUrl(siteUrl) === GeneralHelper.getAbsoluteDomainUrl(fileUrl); - } + return ( + GeneralHelper.getAbsoluteDomainUrl(siteUrl) === + GeneralHelper.getAbsoluteDomainUrl(fileUrl) + ); + }; } - diff --git a/src/propertyFields/filePicker/filePickerControls/RecentFilesTab/RecentFilesTab.tsx b/src/propertyFields/filePicker/filePickerControls/RecentFilesTab/RecentFilesTab.tsx index f00b13c7..808b7d81 100644 --- a/src/propertyFields/filePicker/filePickerControls/RecentFilesTab/RecentFilesTab.tsx +++ b/src/propertyFields/filePicker/filePickerControls/RecentFilesTab/RecentFilesTab.tsx @@ -1,14 +1,20 @@ import * as React from 'react'; -import { PrimaryButton, DefaultButton } from '@fluentui/react/lib/components/Button'; -import { Spinner } from '@fluentui/react/lib/Spinner'; -import { FocusZone } from '@fluentui/react/lib/FocusZone'; -import { List } from '@fluentui/react/lib/List'; -import { IRectangle } from '@fluentui/react/lib/Utilities'; -import { css } from '@fluentui/react/lib/Utilities'; -import { Selection, SelectionMode, SelectionZone } from '@fluentui/react/lib/Selection'; -import { Image, ImageFit } from '@fluentui/react/lib/Image'; -import { Check } from '@fluentui/react/lib/Check'; +import { + PrimaryButton, + DefaultButton, + Spinner, + FocusZone, + List, + IRectangle, + css, + Selection, + SelectionMode, + SelectionZone, + Image, + ImageFit, + Check, +} from '@fluentui/react'; import { Placeholder } from '../../placeHolderControl'; import { IRecentFile } from '../../../../services/FilesSearchService.types'; import { IFilePickerResult } from '../FilePicker.types'; @@ -29,7 +35,10 @@ const ROWS_PER_PAGE = 3; */ const MAX_ROW_HEIGHT = 175; -export default class RecentFilesTab extends React.Component { +export default class RecentFilesTab extends React.Component< + IRecentFilesTabProps, + IRecentFilesTabState +> { private _columnCount: number; private _columnWidth: number; private _rowHeight: number; @@ -41,14 +50,13 @@ export default class RecentFilesTab extends React.Component { - const recentFilesResult = await this.props.fileSearchService.executeRecentSearch(this.props.accepts); + const recentFilesResult = + await this.props.fileSearchService.executeRecentSearch( + this.props.accepts + ); this._selection.setItems(recentFilesResult, true); this.setState({ isLoading: false, - results: recentFilesResult + results: recentFilesResult, }); } @@ -69,18 +80,18 @@ export default class RecentFilesTab extends React.Component { - const { results, - isLoading } = this.state; + const { results, isLoading } = this.state; return (

{strings.RecentDocumentsHeader}

- {isLoading ? - this._renderSpinner() : - results === undefined || results.length < 1 ? this._renderPlaceholder() : this._renderGridList() - } + {isLoading + ? this._renderSpinner() + : results === undefined || results.length < 1 + ? this._renderPlaceholder() + : this._renderGridList()}
@@ -88,8 +99,15 @@ export default class RecentFilesTab extends React.Component this._handleSave()} className={styles.actionButton} - >{strings.OpenButtonLabel} - this._handleClose()} className={styles.actionButton}>{strings.CancelButtonLabel} + > + {strings.OpenButtonLabel} + + this._handleClose()} + className={styles.actionButton} + > + {strings.CancelButtonLabel} +
@@ -105,30 +123,40 @@ export default class RecentFilesTab extends React.Component { return this.props.fileSearchService.downloadSPFileContent(selectedKey.fileUrl, GeneralHelper.getFileNameFromUrl(selectedKey.fileUrl)); } + fileNameWithoutExtension: GeneralHelper.getFileNameWithoutExtension( + selectedKey.fileUrl + ), + downloadFileContent: () => { + return this.props.fileSearchService.downloadSPFileContent( + selectedKey.fileUrl, + GeneralHelper.getFileNameFromUrl(selectedKey.fileUrl) + ); + }, }; // Save the selected file this.setState({ - filePickerResult + filePickerResult, }); } else { // Remove any selected file this.setState({ - filePickerResult: undefined + filePickerResult: undefined, }); } if (this._listElem) { // Force the list to update to show the selection check this._listElem.forceUpdate(); } - } + }; /** - * Calculates how many items there should be in the page - */ - private _getItemCountForPage = (itemIndex: number, surfaceRect: IRectangle): number => { + * Calculates how many items there should be in the page + */ + private _getItemCountForPage = ( + itemIndex: number, + surfaceRect: IRectangle + ): number => { if (itemIndex === 0 && surfaceRect.width > 0) { this._columnCount = Math.ceil(surfaceRect.width / MAX_ROW_HEIGHT); this._columnWidth = Math.floor(surfaceRect.width / this._columnCount); @@ -136,56 +164,65 @@ export default class RecentFilesTab extends React.Component { return this._rowHeight * ROWS_PER_PAGE; - } - + }; /** * Renders a "please wait" spinner while we're loading */ private _renderSpinner = (): JSX.Element => { return ; - } + }; /** * Renders a message saying that there are no recent files */ private _renderPlaceholder = (): JSX.Element => { - return ; - } + return ( + + ); + }; /** * Renders a grid list containing results */ private _renderGridList = (): JSX.Element => { - return - - this._handleItemInvoked(item)}> - - - - ; - } + return ( + + + this._handleItemInvoked(item)} + > + + + + + ); + }; /** * Renders each result in its own cell */ - private _onRenderCell = (item: IRecentFile, index: number | undefined): JSX.Element => { + private _onRenderCell = ( + item: IRecentFile, + index: number | undefined + ): JSX.Element => { let isSelected: boolean = false; if (this._selection && index !== undefined) { @@ -193,21 +230,25 @@ export default class RecentFilesTab extends React.Component +
@@ -215,19 +256,31 @@ export default class RecentFilesTab extends React.Component
{/*
*/} - + {/*
*/}
-
+ data-item-index={index} + data-selection-toggle={true} + data-automationid='CheckCircle' + >
{item.name}
- {strings.EditedByNamePlate}{item.editedBy} + + {strings.EditedByNamePlate} + {item.editedBy} +
@@ -236,28 +289,28 @@ export default class RecentFilesTab extends React.Component
); - } + }; /** * Gets called what a file is selected. */ private _handleItemInvoked = (item: IRecentFile): void => { this._selection.setKeySelected(item.key, true, true); - } + }; /** * Gets called when it is time to save the currently selected item */ private _handleSave = (): void => { this.props.onSave(this.state.filePickerResult); - } + }; /** * Gets called when it is time to close (without saving) */ private _handleClose = (): void => { this.props.onClose(); - } + }; /** * Creates a ref to the list @@ -275,5 +328,5 @@ export default class RecentFilesTab extends React.Component { +export default class SiteFilePickerTab extends React.Component< + ISiteFilePickerTabProps, + ISiteFilePickerTabState +> { constructor(props: ISiteFilePickerTabProps) { super(props); // Add current site to the breadcrumb or the provided node - const breadcrumbSiteNode: FilePickerBreadcrumbItem = this.props.breadcrumbFirstNode ? this.props.breadcrumbFirstNode : { - isCurrentItem: true, - text: props.context.pageContext.web.title, - key: props.context.pageContext.web.id.toString() + const breadcrumbSiteNode: FilePickerBreadcrumbItem = this.props + .breadcrumbFirstNode + ? this.props.breadcrumbFirstNode + : { + isCurrentItem: true, + text: props.context.pageContext.web.title, + key: props.context.pageContext.web.id.toString(), + }; + breadcrumbSiteNode.onClick = () => { + this.onBreadcrumpItemClick(breadcrumbSiteNode); }; - breadcrumbSiteNode.onClick = () => { this.onBreadcrumpItemClick(breadcrumbSiteNode); }; this.state = { filePickerResult: null, @@ -31,7 +47,7 @@ export default class SiteFilePickerTab extends React.Component
- +
- {this.state.libraryAbsolutePath === undefined && + {this.state.libraryAbsolutePath === undefined && (
this._handleOpenLibrary(selectedLibrary, true)} - includePageLibraries={this.props.includePageLibraries} /> + onOpenLibrary={(selectedLibrary: ILibrary) => + this._handleOpenLibrary(selectedLibrary, true) + } + includePageLibraries={this.props.includePageLibraries} + /> -
} - {this.state.libraryAbsolutePath !== undefined && +
+ )} + {this.state.libraryAbsolutePath !== undefined && ( this._handleSelectionChange(filePickerResult)} - onOpenFolder={(folder: IFile) => this._handleOpenFolder(folder, true)} + onChange={(filePickerResult: IFilePickerResult) => + this._handleSelectionChange(filePickerResult) + } + onOpenFolder={(folder: IFile) => + this._handleOpenFolder(folder, true) + } fileBrowserService={this.props.fileBrowserService} libraryName={this.state.libraryTitle} libraryId={this.state.libraryId} folderPath={this.state.libraryPath} accepts={this.props.accepts} context={this.props.context} - />} + /> + )}
this._handleSave()} className={styles.actionButton}>{strings.OpenButtonLabel} - this._handleClose()} className={styles.actionButton}>{strings.CancelButtonLabel} + onClick={() => this._handleSave()} + className={styles.actionButton} + > + {strings.OpenButtonLabel} + + this._handleClose()} + className={styles.actionButton} + > + {strings.CancelButtonLabel} +
@@ -77,9 +116,16 @@ export default class SiteFilePickerTab extends React.Component { return ( - {item.text} + + {item.text} + ); - } + }; /** * Handles breadcrump item click @@ -92,20 +138,27 @@ export default class SiteFilePickerTab extends React.Component item.folderData && item.folderData.absoluteUrl === node.key); + breadcrumbClickedItemIndx = findIndex( + breadcrumbItems, + (item) => item.folderData && item.folderData.absoluteUrl === node.key + ); } // Check if it is library node else if (node.libraryData) { this._handleOpenLibrary(node.libraryData, false); // select which node has been clicked - breadcrumbClickedItemIndx = findIndex(breadcrumbItems, item => item.libraryData && item.libraryData.serverRelativeUrl === node.key); + breadcrumbClickedItemIndx = findIndex( + breadcrumbItems, + (item) => + item.libraryData && item.libraryData.serverRelativeUrl === node.key + ); } // Trim nodes array breadcrumbItems = breadcrumbItems.slice(0, breadcrumbClickedItemIndx + 1); @@ -114,52 +167,66 @@ export default class SiteFilePickerTab extends React.Component { + private _handleSelectionChange = ( + filePickerResult: IFilePickerResult + ): void => { if (filePickerResult) { - filePickerResult.downloadFileContent = () => { return this.props.fileBrowserService.downloadSPFileContent(filePickerResult.fileAbsoluteUrl, filePickerResult.fileName); }; + filePickerResult.downloadFileContent = () => { + return this.props.fileBrowserService.downloadSPFileContent( + filePickerResult.fileAbsoluteUrl, + filePickerResult.fileName + ); + }; } // this.props.fileBrowserService this.setState({ - filePickerResult + filePickerResult, }); - } + }; /** * Called when user saves */ private _handleSave = (): void => { this.props.onSave(this.state.filePickerResult); - } + }; /** * Called when user closes tab */ private _handleClose = (): void => { this.props.onClose(); - } + }; /** * Triggered when user opens a file folder */ - private _handleOpenFolder = (folder: IFile, addBreadcrumbNode: boolean): void => { + private _handleOpenFolder = ( + folder: IFile, + addBreadcrumbNode: boolean + ): void => { const { breadcrumbItems } = this.state; if (addBreadcrumbNode) { - breadcrumbItems.map(item => { item.isCurrentItem = false; }); + breadcrumbItems.map((item) => { + item.isCurrentItem = false; + }); const breadcrumbNode: FilePickerBreadcrumbItem = { folderData: folder, isCurrentItem: true, text: folder.name, - key: folder.absoluteUrl + key: folder.absoluteUrl, + }; + breadcrumbNode.onClick = () => { + this.onBreadcrumpItemClick(breadcrumbNode); }; - breadcrumbNode.onClick = () => { this.onBreadcrumpItemClick(breadcrumbNode); }; breadcrumbItems.push(breadcrumbNode); } @@ -168,24 +235,31 @@ export default class SiteFilePickerTab extends React.Component { + private _handleOpenLibrary = ( + library: ILibrary, + addBreadcrumbNode: boolean + ): void => { const { breadcrumbItems } = this.state; if (addBreadcrumbNode) { - breadcrumbItems.map(item => { item.isCurrentItem = false; }); + breadcrumbItems.map((item) => { + item.isCurrentItem = false; + }); const breadcrumbNode: FilePickerBreadcrumbItem = { libraryData: library, isCurrentItem: true, text: library.title, - key: library.serverRelativeUrl + key: library.serverRelativeUrl, + }; + breadcrumbNode.onClick = () => { + this.onBreadcrumpItemClick(breadcrumbNode); }; - breadcrumbNode.onClick = () => { this.onBreadcrumpItemClick(breadcrumbNode); }; breadcrumbItems.push(breadcrumbNode); } this.setState({ @@ -193,7 +267,7 @@ export default class SiteFilePickerTab extends React.Component { constructor(props: IUploadFilePickerTabProps) { diff --git a/src/propertyFields/filePicker/filePickerControls/WebSearchTab/WebSearchTab.tsx b/src/propertyFields/filePicker/filePickerControls/WebSearchTab/WebSearchTab.tsx index 276c9ac1..a97ab888 100644 --- a/src/propertyFields/filePicker/filePickerControls/WebSearchTab/WebSearchTab.tsx +++ b/src/propertyFields/filePicker/filePickerControls/WebSearchTab/WebSearchTab.tsx @@ -2,23 +2,42 @@ import * as React from 'react'; import { IWebSearchTabProps } from './IWebSearchTabProps'; import { IWebSearchTabState } from './IWebSearchTabState'; -import { ISearchSuggestion, ImageSize, ImageAspect, ImageLicense, DEFAULT_SUGGESTIONS, MAX_ROW_HEIGHT, ROWS_PER_PAGE } from './WebSearchTab.types'; -import { PrimaryButton, DefaultButton } from '@fluentui/react/lib/components/Button'; -import { Label } from '@fluentui/react/lib/Label'; -import { SearchBox } from '@fluentui/react/lib/SearchBox'; -import { Check } from '@fluentui/react/lib/Check'; -import { Dropdown, IDropdownProps, IDropdownOption } from '@fluentui/react/lib/Dropdown'; -import { Image, ImageFit } from '@fluentui/react/lib/Image'; -import { Link } from '@fluentui/react/lib/Link'; -import { FocusZone } from '@fluentui/react/lib/FocusZone'; -import { List } from '@fluentui/react/lib/List'; -import { IRectangle } from '@fluentui/react/lib/Utilities'; -import { Selection, SelectionMode, SelectionZone } from '@fluentui/react/lib/Selection'; -import { MessageBar } from '@fluentui/react/lib/MessageBar'; -import { css } from '@fluentui/react/lib/Utilities'; +import { + ISearchSuggestion, + ImageSize, + ImageAspect, + ImageLicense, + DEFAULT_SUGGESTIONS, + MAX_ROW_HEIGHT, + ROWS_PER_PAGE, +} from './WebSearchTab.types'; +import { + PrimaryButton, + DefaultButton, + Label, + SearchBox, + Check, + Dropdown, + IDropdownProps, + IDropdownOption, + Image, + ImageFit, + Link, + FocusZone, + List, + IRectangle, + Selection, + SelectionMode, + SelectionZone, + MessageBar, + css, +} from '@fluentui/react'; import { IFilePickerResult } from '../FilePicker.types'; import { GeneralHelper } from '../../../../helpers/GeneralHelper'; -import { ISearchResult, BingQuerySearchParams } from '../../../../services/FilesSearchService.types'; +import { + ISearchResult, + BingQuerySearchParams, +} from '../../../../services/FilesSearchService.types'; import styles from './WebSearchTab.module.scss'; import * as strings from 'PropertyControlStrings'; @@ -26,7 +45,10 @@ import * as strings from 'PropertyControlStrings'; /** * Renders search suggestions and performs seach queries */ -export default class WebSearchTab extends React.Component { +export default class WebSearchTab extends React.Component< + IWebSearchTabProps, + IWebSearchTabState +> { private _columnCount: number; private _columnWidth: number; private _rowHeight: number; @@ -38,13 +60,13 @@ export default class WebSearchTab extends React.Component
- { - this.state.results && this.state.license === 'Any' && - - {strings.CreativeCommonsMessage} - } + {this.state.results && this.state.license === 'Any' && ( + {strings.CreativeCommonsMessage} + )}
@@ -80,8 +102,15 @@ export default class WebSearchTab extends React.Component this._handleSave()} - >{strings.OpenButtonLabel} - this._handleClose()} className={styles.actionButton}>{strings.CancelButtonLabel} + > + {strings.OpenButtonLabel} + + this._handleClose()} + className={styles.actionButton} + > + {strings.CancelButtonLabel} +
@@ -100,30 +129,43 @@ export default class WebSearchTab extends React.Component { return this.props.bingSearchService.downloadBingContent(selectedUrl, GeneralHelper.getFileNameFromUrl(selectedUrl)); } + fileNameWithoutExtension: + GeneralHelper.getFileNameWithoutExtension(selectedUrl), + downloadFileContent: () => { + return this.props.bingSearchService.downloadBingContent( + selectedUrl, + GeneralHelper.getFileNameFromUrl(selectedUrl) + ); + }, }; } // If clicked on already selected file -> deselect it - if (filePickerResult && selectedFileResult && filePickerResult.fileAbsoluteUrl === selectedFileResult.fileAbsoluteUrl) { + if ( + filePickerResult && + selectedFileResult && + filePickerResult.fileAbsoluteUrl === selectedFileResult.fileAbsoluteUrl + ) { this._selection.setAllSelected(false); selectedFileResult = null; } // Save the selected file this.setState({ - filePickerResult: selectedFileResult + filePickerResult: selectedFileResult, }); if (this._listElem) { // Force the list to update to show the selection check this._listElem.forceUpdate(); } - } + }; /** * Renders the returned search results @@ -133,13 +175,20 @@ export default class WebSearchTab extends React.Component{strings.NoResultsBadEnglish}; + return ( + + ); } return ( - this._selection.setKeySelected(item.key, true, true)} + + this._selection.setKeySelected(item.key, true, true) + } > ); - } + }; /** * Show an individual search result item */ - private _onRenderSearchResultsCell = (item: ISearchResult, index: number | undefined): JSX.Element => { + private _onRenderSearchResultsCell = ( + item: ISearchResult, + index: number | undefined + ): JSX.Element => { const { query } = this.state; let isSelected: boolean = false; @@ -179,30 +231,47 @@ export default class WebSearchTab extends React.Component
+ height: `${thumbnailHeight}px`, + }} + >
- {searchResultAltText} + {searchResultAltText}
-
+ data-item-index={index} + data-selection-toggle={true} + data-automationid='CheckCircle' + >
@@ -210,18 +279,24 @@ export default class WebSearchTab extends React.Component{item.displayUrl} + > + {item.displayUrl} +
-
); - } +
+ ); + }; /** * Renders suggestions when there aren't any queries */ private _renderSearchSuggestions = (): JSX.Element => { - const suggestions: ISearchSuggestion[] = this.props.suggestions !== undefined ? this.props.suggestions : DEFAULT_SUGGESTIONS; + const suggestions: ISearchSuggestion[] = + this.props.suggestions !== undefined + ? this.props.suggestions + : DEFAULT_SUGGESTIONS; return ( @@ -235,7 +310,7 @@ export default class WebSearchTab extends React.Component ); - } + }; /** * Gets search results from Bing @@ -249,16 +324,18 @@ export default class WebSearchTab extends React.Component { + private _getItemCountForPage = ( + itemIndex: number, + surfaceRect: IRectangle + ): number => { if (itemIndex === 0) { this._columnCount = Math.ceil(surfaceRect.width / MAX_ROW_HEIGHT); this._columnWidth = Math.floor(surfaceRect.width / this._columnCount); @@ -284,36 +364,48 @@ export default class WebSearchTab extends React.Component { return this._rowHeight * ROWS_PER_PAGE; - } + }; /** * Renders a cell for search suggestions */ - private _onRenderSuggestionCell = (item: ISearchSuggestion, index: number | undefined): JSX.Element => { + private _onRenderSuggestionCell = ( + item: ISearchSuggestion, + index: number | undefined + ): JSX.Element => { return (
- - this._handleSearch(item.topic)}>{item.topic} + + this._handleSearch(item.topic)} + > + {item.topic} +
); - } + }; /** * Renders the search box @@ -330,30 +422,35 @@ export default class WebSearchTab extends React.Component this._handleSearch(newQuery)} + onSearch={(newQuery) => this._handleSearch(newQuery)} /> - { - hasQuery && + {hasQuery && (
this._renderFilterPlaceholder(props)} + onRenderPlaceHolder={(props: IDropdownProps) => + this._renderFilterPlaceholder(props) + } selectedKey={this.state.size} options={[ { key: 'All', text: strings.SizeOptionAll }, { key: 'Small', text: strings.SizeOptionSmall }, { key: 'Medium', text: strings.SizeOptionMedium }, { key: 'Large', text: strings.SizeOptionLarge }, - { key: 'Wallpaper', text: strings.SizeOptionExtraLarge } + { key: 'Wallpaper', text: strings.SizeOptionExtraLarge }, ]} - onChanged={(option: IDropdownOption, index?: number) => this._handleChangeSize(option)} + onChanged={(option: IDropdownOption, index?: number) => + this._handleChangeSize(option) + } /> this._renderFilterPlaceholder(props)} + onRenderPlaceHolder={(props: IDropdownProps) => + this._renderFilterPlaceholder(props) + } selectedKey={this.state.aspect} options={[ { key: 'All', text: strings.LayoutOptionAll }, @@ -361,52 +458,68 @@ export default class WebSearchTab extends React.Component this._handleChangeLayout(option)} + onChanged={(option: IDropdownOption, index?: number) => + this._handleChangeLayout(option) + } /> this._renderFilterPlaceholder(props)} + onRenderPlaceHolder={(props: IDropdownProps) => + this._renderFilterPlaceholder(props) + } selectedKey={license} options={[ { key: 'All', text: strings.LicenseOptionAll }, - { key: 'Any', text: strings.LicenseOptionAny } + { key: 'Any', text: strings.LicenseOptionAny }, ]} - onChanged={(option: IDropdownOption, index?: number) => this._handleChangeLicense(option)} + onChanged={(option: IDropdownOption, index?: number) => + this._handleChangeLicense(option) + } />
- } - ); - } + )} + + ); + }; /** * Handles when a user changes the size drop down. * Resubmits search query */ private _handleChangeSize = (option: IDropdownOption): void => { - this.setState({ - size: option.key as ImageSize - }, () => this._getSearchResults()); - } + this.setState( + { + size: option.key as ImageSize, + }, + () => this._getSearchResults() + ); + }; /** * Handles when user selects a new layout from the drop down. * Resubmits search query. */ private _handleChangeLayout = (option: IDropdownOption): void => { - this.setState({ - aspect: option.key as ImageAspect - }, () => this._getSearchResults()); - } + this.setState( + { + aspect: option.key as ImageAspect, + }, + () => this._getSearchResults() + ); + }; /** * Handles when a user changes the license from the drop down * Resubits search query */ private _handleChangeLicense = (option: IDropdownOption): void => { - this.setState({ - license: option.key as ImageLicense - }, () => this._getSearchResults()); - } + this.setState( + { + license: option.key as ImageLicense, + }, + () => this._getSearchResults() + ); + }; /** * Renders the drop down placeholders @@ -414,23 +527,26 @@ export default class WebSearchTab extends React.Component { // return {props.placeholder}; return Pick the value; - } + }; /** * Handles when user triggers search query */ private _handleSearch = (newQuery?: string): void => { - this.setState({ - query: newQuery - }, () => this._getSearchResults()); - } + this.setState( + { + query: newQuery, + }, + () => this._getSearchResults() + ); + }; /** * Handles when user closes search pane */ private _handleClose = (): void => { this.props.onClose(); - } + }; /** * Handes when user saves selection @@ -438,12 +554,12 @@ export default class WebSearchTab extends React.Component { this.props.onSave(this.state.filePickerResult); - } + }; /** * Creates a reference to the list */ private _linkElement = (e: List): void => { this._listElem = e; - } + }; } diff --git a/src/propertyFields/filePicker/placeHolderControl/PlaceholderComponent.tsx b/src/propertyFields/filePicker/placeHolderControl/PlaceholderComponent.tsx index fdf7052d..bca3ce7a 100644 --- a/src/propertyFields/filePicker/placeHolderControl/PlaceholderComponent.tsx +++ b/src/propertyFields/filePicker/placeHolderControl/PlaceholderComponent.tsx @@ -1,8 +1,7 @@ import * as React from 'react'; import { IPlaceholderProps, IPlaceholderState } from './IPlaceholderComponent'; -import { PrimaryButton } from '@fluentui/react/lib/Button'; import styles from './PlaceholderComponent.module.scss'; -import { Icon } from '@fluentui/react/lib/components/Icon'; +import { Icon, PrimaryButton } from '@fluentui/react'; /** * Placeholder component diff --git a/src/propertyFields/labelWithCallout/IPropertyFieldLabelWithCalloutHost.ts b/src/propertyFields/labelWithCallout/IPropertyFieldLabelWithCalloutHost.ts index 5f075ee9..f50b7acb 100644 --- a/src/propertyFields/labelWithCallout/IPropertyFieldLabelWithCalloutHost.ts +++ b/src/propertyFields/labelWithCallout/IPropertyFieldLabelWithCalloutHost.ts @@ -1,5 +1,5 @@ import { IPlaceholderWithCalloutProps } from '../../common/placeholderWithCallout/IPlaceholderWithCallout'; -import { ILabelProps } from '@fluentui/react/lib/components/Label'; +import { ILabelProps } from '@fluentui/react'; /** * PropertyFieldLabelWithCalloutHost properties interface diff --git a/src/propertyFields/labelWithCallout/PropertyFieldLabelWithCalloutHost.tsx b/src/propertyFields/labelWithCallout/PropertyFieldLabelWithCalloutHost.tsx index 525fd6d2..e64409b6 100644 --- a/src/propertyFields/labelWithCallout/PropertyFieldLabelWithCalloutHost.tsx +++ b/src/propertyFields/labelWithCallout/PropertyFieldLabelWithCalloutHost.tsx @@ -4,7 +4,7 @@ import PlaceholderWithCallout from '../../common/placeholderWithCallout/Placehol import { IPropertyFieldLabelWithCalloutHostProps } from './IPropertyFieldLabelWithCalloutHost'; import * as telemetry from '../../common/telemetry'; -import { Label } from '@fluentui/react/lib/components/Label'; +import { Label } from '@fluentui/react'; /** * Renders the control for PropertyFieldLabelWithCallout component diff --git a/src/propertyFields/linkWithCallout/IPropertyFieldLinkWithCalloutHost.ts b/src/propertyFields/linkWithCallout/IPropertyFieldLinkWithCalloutHost.ts index 77fa198c..d8dab0c0 100644 --- a/src/propertyFields/linkWithCallout/IPropertyFieldLinkWithCalloutHost.ts +++ b/src/propertyFields/linkWithCallout/IPropertyFieldLinkWithCalloutHost.ts @@ -1,6 +1,6 @@ import { IPlaceholderWithCalloutProps } from '../../common/placeholderWithCallout/IPlaceholderWithCallout'; import { IPopupWindowProps } from '@microsoft/sp-property-pane'; -import { ILinkProps } from '@fluentui/react/lib/components/Link'; +import { ILinkProps } from '@fluentui/react'; /** * PropertyFieldLinkWithCalloutHost properties interface diff --git a/src/propertyFields/linkWithCallout/PropertyFieldLinkWithCalloutHost.tsx b/src/propertyFields/linkWithCallout/PropertyFieldLinkWithCalloutHost.tsx index af3e59e4..554d5619 100644 --- a/src/propertyFields/linkWithCallout/PropertyFieldLinkWithCalloutHost.tsx +++ b/src/propertyFields/linkWithCallout/PropertyFieldLinkWithCalloutHost.tsx @@ -5,7 +5,7 @@ import type { IPlaceholderWithCalloutProps } from '../../common/placeholderWithC import { IPropertyFieldLinkWithCalloutHostProps } from './IPropertyFieldLinkWithCalloutHost'; import * as telemetry from '../../common/telemetry'; -import { Link } from '@fluentui/react/lib/components/Link'; +import { Link } from '@fluentui/react'; /** * Renders the control for PropertyFieldLinkWithCallout component diff --git a/src/propertyFields/monacoEditor/monacoEditorControl/Error.tsx b/src/propertyFields/monacoEditor/monacoEditorControl/Error.tsx index 411ff906..b5656a81 100644 --- a/src/propertyFields/monacoEditor/monacoEditorControl/Error.tsx +++ b/src/propertyFields/monacoEditor/monacoEditorControl/Error.tsx @@ -1,19 +1,19 @@ - -import { Stack } from "@fluentui/react/lib/components/Stack"; -import { MessageBarType , MessageBar} from "@fluentui/react/lib/MessageBar"; -import * as React from "react"; +import { Stack, MessageBarType, MessageBar } from '@fluentui/react'; +import * as React from 'react'; export interface IErrorProps { error: Error; show: boolean; } -export const Error: React.FunctionComponent = (props: React.PropsWithChildren) => { +export const Error: React.FunctionComponent = ( + props: React.PropsWithChildren +) => { const { error } = props; return ( <> (show && error) ? - + {error.message} diff --git a/src/propertyFields/multiSelect/IPropertyFieldMultiSelectHost.ts b/src/propertyFields/multiSelect/IPropertyFieldMultiSelectHost.ts index 8b5771cf..171da077 100644 --- a/src/propertyFields/multiSelect/IPropertyFieldMultiSelectHost.ts +++ b/src/propertyFields/multiSelect/IPropertyFieldMultiSelectHost.ts @@ -1,4 +1,4 @@ -import { IDropdownProps } from '@fluentui/react/lib/components/Dropdown'; +import { IDropdownProps } from '@fluentui/react'; /** * PropertyFieldMultiSelectHost properties interface diff --git a/src/propertyFields/multiSelect/PropertyFieldMultiSelect.ts b/src/propertyFields/multiSelect/PropertyFieldMultiSelect.ts index ba3b466f..c98ba69a 100644 --- a/src/propertyFields/multiSelect/PropertyFieldMultiSelect.ts +++ b/src/propertyFields/multiSelect/PropertyFieldMultiSelect.ts @@ -1,4 +1,4 @@ -import { IDropdownOption } from '@fluentui/react/lib/components/Dropdown'; +import { IDropdownOption } from '@fluentui/react'; import * as React from 'react'; import * as ReactDOM from 'react-dom'; import { diff --git a/src/propertyFields/multiSelect/PropertyFieldMultiSelectHost.tsx b/src/propertyFields/multiSelect/PropertyFieldMultiSelectHost.tsx index d4fc7676..139a710a 100644 --- a/src/propertyFields/multiSelect/PropertyFieldMultiSelectHost.tsx +++ b/src/propertyFields/multiSelect/PropertyFieldMultiSelectHost.tsx @@ -1,6 +1,6 @@ import * as strings from 'PropertyControlStrings'; import * as React from 'react'; -import { Dropdown } from '@fluentui/react/lib/components/Dropdown'; +import { Dropdown } from '@fluentui/react'; import { IPropertyFieldMultiSelectHostProps } from './IPropertyFieldMultiSelectHost'; import * as telemetry from '../../common/telemetry'; diff --git a/src/propertyFields/sliderWithCallout/IPropertyFieldSliderWithCalloutHost.ts b/src/propertyFields/sliderWithCallout/IPropertyFieldSliderWithCalloutHost.ts index 05b611c8..6b8584ab 100644 --- a/src/propertyFields/sliderWithCallout/IPropertyFieldSliderWithCalloutHost.ts +++ b/src/propertyFields/sliderWithCallout/IPropertyFieldSliderWithCalloutHost.ts @@ -1,5 +1,5 @@ import { IPropertyFieldHeaderCalloutProps } from '../../common/propertyFieldHeader/IPropertyFieldHeader'; -import { ISliderProps } from '@fluentui/react/lib/components/Slider'; +import { ISliderProps } from '@fluentui/react'; /** * PropertyFieldSliderWithCalloutHost properties interface diff --git a/src/propertyFields/sliderWithCallout/PropertyFieldSliderWithCalloutHost.tsx b/src/propertyFields/sliderWithCallout/PropertyFieldSliderWithCalloutHost.tsx index 485c0ed1..d91b288b 100644 --- a/src/propertyFields/sliderWithCallout/PropertyFieldSliderWithCalloutHost.tsx +++ b/src/propertyFields/sliderWithCallout/PropertyFieldSliderWithCalloutHost.tsx @@ -4,7 +4,7 @@ import PropertyFieldHeader from '../../common/propertyFieldHeader/PropertyFieldH import { IPropertyFieldSliderWithCalloutHostProps } from './IPropertyFieldSliderWithCalloutHost'; import * as telemetry from '../../common/telemetry'; -import { Slider } from '@fluentui/react/lib/components/Slider'; +import { Slider } from '@fluentui/react'; import omit from 'lodash/omit'; diff --git a/src/propertyFields/spinButton/PropertyFieldSpinButtonHost.tsx b/src/propertyFields/spinButton/PropertyFieldSpinButtonHost.tsx index b1874c9d..3df1e63b 100644 --- a/src/propertyFields/spinButton/PropertyFieldSpinButtonHost.tsx +++ b/src/propertyFields/spinButton/PropertyFieldSpinButtonHost.tsx @@ -1,40 +1,45 @@ import * as React from 'react'; -import { SpinButton } from '@fluentui/react/lib/SpinButton'; -import { Position } from '@fluentui/react/lib/utilities/positioning'; +import { SpinButton, Position } from '@fluentui/react'; import { - IPropertyFieldSpinButtonHostProps, - IPropertyFieldSpinButtonHostState + IPropertyFieldSpinButtonHostProps, + IPropertyFieldSpinButtonHostState, } from './IPropertyFieldSpinButtonHost'; import * as telemetry from '../../common/telemetry'; -export default class PropertyFieldSpinButtonHost extends React.Component { +export default class PropertyFieldSpinButtonHost extends React.Component< + IPropertyFieldSpinButtonHostProps, + IPropertyFieldSpinButtonHostState +> { + constructor( + props: IPropertyFieldSpinButtonHostProps, + state: IPropertyFieldSpinButtonHostState + ) { + super(props); - constructor(props: IPropertyFieldSpinButtonHostProps, state: IPropertyFieldSpinButtonHostState) { - super(props); + telemetry.track('PropertyFieldSpinButton', { + disabled: props.disabled, + }); - telemetry.track('PropertyFieldSpinButton', { - disabled: props.disabled - }); + this.state = { + errorMessage: undefined, + }; + } - this.state = { - errorMessage: undefined - }; - } - - public render(): JSX.Element { - return ( -
- -
- ); - } + public render(): JSX.Element { + return ( +
+ +
+ ); + } } diff --git a/src/propertyFields/swatchColorPicker/IPropertyFieldSwatchColorPicker.ts b/src/propertyFields/swatchColorPicker/IPropertyFieldSwatchColorPicker.ts index 27096c84..42d550c4 100644 --- a/src/propertyFields/swatchColorPicker/IPropertyFieldSwatchColorPicker.ts +++ b/src/propertyFields/swatchColorPicker/IPropertyFieldSwatchColorPicker.ts @@ -1,5 +1,5 @@ import { IPropertyPaneCustomFieldProps } from '@microsoft/sp-property-pane'; -import { IColor } from '@fluentui/react/lib/utilities/color/colors'; +import { IColor } from '@fluentui/react'; /** * Enum for specifying how the control should be shown diff --git a/src/propertyFields/swatchColorPicker/PropertyFieldSwatchColorPicker.ts b/src/propertyFields/swatchColorPicker/PropertyFieldSwatchColorPicker.ts index 3a39afbd..3a377a29 100644 --- a/src/propertyFields/swatchColorPicker/PropertyFieldSwatchColorPicker.ts +++ b/src/propertyFields/swatchColorPicker/PropertyFieldSwatchColorPicker.ts @@ -1,5 +1,5 @@ import { IPropertyPaneField, PropertyPaneFieldType } from '@microsoft/sp-property-pane'; -import { getColorFromString, IColor } from '@fluentui/react/lib/utilities/color/colors'; +import { getColorFromString, IColor } from '@fluentui/react'; import * as React from 'react'; import * as ReactDom from 'react-dom'; import { setPropertyValue } from '../../helpers/GeneralHelper'; diff --git a/src/propertyFields/textWithCallout/IPropertyFieldTextWithCalloutHost.ts b/src/propertyFields/textWithCallout/IPropertyFieldTextWithCalloutHost.ts index 0ee1cac8..c989c1ea 100644 --- a/src/propertyFields/textWithCallout/IPropertyFieldTextWithCalloutHost.ts +++ b/src/propertyFields/textWithCallout/IPropertyFieldTextWithCalloutHost.ts @@ -1,5 +1,5 @@ import { IPropertyFieldHeaderCalloutProps } from '../../common/propertyFieldHeader/IPropertyFieldHeader'; -import { ITextFieldProps } from '@fluentui/react/lib/components/TextField'; +import { ITextFieldProps } from '@fluentui/react'; /** * PropertyFieldTextWithCalloutHost properties interface diff --git a/src/propertyFields/textWithCallout/PropertyFieldTextWithCalloutHost.tsx b/src/propertyFields/textWithCallout/PropertyFieldTextWithCalloutHost.tsx index af238397..5f94902e 100644 --- a/src/propertyFields/textWithCallout/PropertyFieldTextWithCalloutHost.tsx +++ b/src/propertyFields/textWithCallout/PropertyFieldTextWithCalloutHost.tsx @@ -4,7 +4,7 @@ import PropertyFieldHeader from '../../common/propertyFieldHeader/PropertyFieldH import { IPropertyFieldTextWithCalloutHostProps } from './IPropertyFieldTextWithCalloutHost'; import * as telemetry from '../../common/telemetry'; -import { TextField } from '@fluentui/react/lib/components/TextField'; +import { TextField } from '@fluentui/react'; import omit from 'lodash/omit'; export default class PropertyFieldTextWithCalloutHost extends React.Component { diff --git a/src/propertyFields/toggleWithCallout/IPropertyFieldToggleWithCalloutHost.ts b/src/propertyFields/toggleWithCallout/IPropertyFieldToggleWithCalloutHost.ts index 05161b35..be3a5c09 100644 --- a/src/propertyFields/toggleWithCallout/IPropertyFieldToggleWithCalloutHost.ts +++ b/src/propertyFields/toggleWithCallout/IPropertyFieldToggleWithCalloutHost.ts @@ -1,5 +1,5 @@ import { IPropertyFieldHeaderCalloutProps } from '../../common/propertyFieldHeader/IPropertyFieldHeader'; -import { IToggleProps } from '@fluentui/react/lib/components/Toggle'; +import { IToggleProps } from '@fluentui/react'; /** * PropertyFieldToggleWithCalloutHost properties interface diff --git a/src/propertyFields/toggleWithCallout/PropertyFieldToggleWithCalloutHost.tsx b/src/propertyFields/toggleWithCallout/PropertyFieldToggleWithCalloutHost.tsx index a9fa496a..646ea464 100644 --- a/src/propertyFields/toggleWithCallout/PropertyFieldToggleWithCalloutHost.tsx +++ b/src/propertyFields/toggleWithCallout/PropertyFieldToggleWithCalloutHost.tsx @@ -5,16 +5,19 @@ import type { IPropertyFieldHeaderProps } from '../../common/propertyFieldHeader import { IPropertyFieldToggleWithCalloutHostProps } from './IPropertyFieldToggleWithCalloutHost'; import * as telemetry from '../../common/telemetry'; -import { Toggle } from '@fluentui/react/lib/components/Toggle'; +import { Toggle } from '@fluentui/react'; import omit from 'lodash/omit'; -export default class PropertyFieldToggleWithCalloutHost extends React.Component { +export default class PropertyFieldToggleWithCalloutHost extends React.Component< + IPropertyFieldToggleWithCalloutHostProps, + null +> { constructor(props: IPropertyFieldToggleWithCalloutHostProps) { super(props); telemetry.track('PropertyFieldToggleWithCallout', { - disabled: props.disabled + disabled: props.disabled, }); } @@ -23,7 +26,8 @@ export default class PropertyFieldToggleWithCalloutHost extends React.Component<
+ label={this.props.label.toString()} + />
); diff --git a/src/webparts/propertyControlsTest/IPropertyControlsTestWebPartProps.ts b/src/webparts/propertyControlsTest/IPropertyControlsTestWebPartProps.ts index fbd56a87..cc6c9aa9 100644 --- a/src/webparts/propertyControlsTest/IPropertyControlsTestWebPartProps.ts +++ b/src/webparts/propertyControlsTest/IPropertyControlsTestWebPartProps.ts @@ -1,4 +1,4 @@ -import { IColor } from '@fluentui/react/lib/utilities/color'; +import { IColor } from '@fluentui/react'; import { IDateTimeFieldValue } from '../../PropertyFieldDateTimePicker'; import { IFilePickerResult } from '../../PropertyFieldFilePicker'; diff --git a/src/webparts/propertyControlsTest/components/IPropertyControlsTestProps.ts b/src/webparts/propertyControlsTest/components/IPropertyControlsTestProps.ts index da47527f..3140b70c 100644 --- a/src/webparts/propertyControlsTest/components/IPropertyControlsTestProps.ts +++ b/src/webparts/propertyControlsTest/components/IPropertyControlsTestProps.ts @@ -1,4 +1,4 @@ -import { IColor } from '@fluentui/react/lib/utilities/color'; +import { IColor } from '@fluentui/react'; import { BaseComponentContext } from '@microsoft/sp-component-base'; import { IDateTimeFieldValue } from '../../../PropertyFieldDateTimePicker';