From f8f99b2a853d9f55cada1872097dc8ca8306065f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Mendes?= Date: Tue, 6 Oct 2020 23:41:55 +0100 Subject: [PATCH 1/8] new Property Control TeamPicker --- src/PropertyFieldTeamPicker.ts | 1 + .../teamPicker/IPropertyFieldTeamPicker.ts | 84 +++++++++++ .../IPropertyFieldTeamPickerHost.ts | 15 ++ .../teamPicker/PropertyFieldTeamPicker.ts | 111 ++++++++++++++ .../PropertyFieldTeamPickerHost.module.scss | 8 + .../PropertyFieldTeamPickerHost.tsx | 142 ++++++++++++++++++ .../IPropertyFieldSitePickerListItem.ts | 7 + .../PropertyFieldSitePickerListItem.tsx | 19 +++ ...ropertyFieldTeamPickerListItem.module.scss | 15 ++ src/propertyFields/teamPicker/index.ts | 4 + 10 files changed, 406 insertions(+) create mode 100644 src/PropertyFieldTeamPicker.ts create mode 100644 src/propertyFields/teamPicker/IPropertyFieldTeamPicker.ts create mode 100644 src/propertyFields/teamPicker/IPropertyFieldTeamPickerHost.ts create mode 100644 src/propertyFields/teamPicker/PropertyFieldTeamPicker.ts create mode 100644 src/propertyFields/teamPicker/PropertyFieldTeamPickerHost.module.scss create mode 100644 src/propertyFields/teamPicker/PropertyFieldTeamPickerHost.tsx create mode 100644 src/propertyFields/teamPicker/PropertyFieldTeamPickerListItem/IPropertyFieldSitePickerListItem.ts create mode 100644 src/propertyFields/teamPicker/PropertyFieldTeamPickerListItem/PropertyFieldSitePickerListItem.tsx create mode 100644 src/propertyFields/teamPicker/PropertyFieldTeamPickerListItem/PropertyFieldTeamPickerListItem.module.scss create mode 100644 src/propertyFields/teamPicker/index.ts diff --git a/src/PropertyFieldTeamPicker.ts b/src/PropertyFieldTeamPicker.ts new file mode 100644 index 00000000..ec2704a8 --- /dev/null +++ b/src/PropertyFieldTeamPicker.ts @@ -0,0 +1 @@ +export * from './propertyFields/teamPicker/index'; \ No newline at end of file diff --git a/src/propertyFields/teamPicker/IPropertyFieldTeamPicker.ts b/src/propertyFields/teamPicker/IPropertyFieldTeamPicker.ts new file mode 100644 index 00000000..8f6cc71f --- /dev/null +++ b/src/propertyFields/teamPicker/IPropertyFieldTeamPicker.ts @@ -0,0 +1,84 @@ +import { IWebPartContext } from '@microsoft/sp-webpart-base'; + +export interface IPropertyFieldTeam { + /** + * ID of the site + */ + id?: string; + /** + * Title + */ + title?: string; + /** + * Base URL + */ + url?: string; +} + +export interface IPropertyFieldTeamPickerProps { + /** + * Property field label + */ + label: string; + /** + * An UNIQUE key indicates the identity of this control + */ + key?: string; + /** + * Specify if the control needs to be disabled + */ + disabled?: boolean; + /** + * Web Part context + */ + context: IWebPartContext; + /** + * Intial data to load in the 'Selected sites' area (optional) + */ + initialSites: IPropertyFieldTeam[]; + /** + * Define if you want to allow multi site selection. True by default. + */ + multiSelect?: boolean; + /** + * Defines a onPropertyChange function to raise when the selected value changed. + * Normally this function must be always defined with the 'this.onPropertyChange' + * method of the web part object. + */ + onPropertyChange(propertyPath: string, oldValue: any, newValue: any): void; + /** + * Parent Web Part properties + */ + properties: any; + /** + * The method is used to get the validation error message and determine whether the input value is valid or not. + * + * When it returns string: + * - If valid, it returns empty string. + * - If invalid, it returns the error message string and the text field will + * show a red border and show an error message below the text field. + * + * When it returns Promise: + * - The resolved value is display as error message. + * - The rejected, the value is thrown away. + * + */ + onGetErrorMessage?: (value: IPropertyFieldTeam[]) => string | Promise; + /** + * Custom Field will start to validate after users stop typing for `deferredValidationTime` milliseconds. + * Default value is 200. + */ + deferredValidationTime?: number; +} +/** + * Private properties of the PropertyFielSitePicker custom field. + * We separate public & private properties to include onRender & onDispose method waited + * by the PropertyFieldCustom, witout asking to the developer to add it when he's using + * the PropertyFieldTeamPicker. + * + */ +export interface IPropertyFieldTeamPickerPropsInternal extends IPropertyFieldTeamPickerProps { + targetProperty: string; + onRender(elem: HTMLElement): void; + onDispose(elem: HTMLElement): void; +} \ No newline at end of file diff --git a/src/propertyFields/teamPicker/IPropertyFieldTeamPickerHost.ts b/src/propertyFields/teamPicker/IPropertyFieldTeamPickerHost.ts new file mode 100644 index 00000000..d94f86e7 --- /dev/null +++ b/src/propertyFields/teamPicker/IPropertyFieldTeamPickerHost.ts @@ -0,0 +1,15 @@ +import { IPropertyFieldTeamPickerPropsInternal, IPropertyFieldTeam} from './IPropertyFieldTeamPicker'; + +/** + * PropertyFieldTeamPickerHost properties interface + */ +export interface IPropertyFieldTeamPickerHostProps extends IPropertyFieldTeamPickerPropsInternal { + onChange: (targetProperty?: string, newValue?: any) => void; +} + +export interface ITeamPickerState { + siteSearchResults?: Array; + selectedSites?: Array; + isLoading: boolean; + errorMessage?: string; +} \ No newline at end of file diff --git a/src/propertyFields/teamPicker/PropertyFieldTeamPicker.ts b/src/propertyFields/teamPicker/PropertyFieldTeamPicker.ts new file mode 100644 index 00000000..9a778032 --- /dev/null +++ b/src/propertyFields/teamPicker/PropertyFieldTeamPicker.ts @@ -0,0 +1,111 @@ +import * as React from 'react'; +import * as ReactDom from 'react-dom'; +import { + IPropertyPaneField, + PropertyPaneFieldType, + IWebPartContext +} from '@microsoft/sp-webpart-base'; +import { IPropertyFieldTeamPickerPropsInternal, IPropertyFieldTeam, IPropertyFieldTeamPickerProps } from './IPropertyFieldTeamPicker'; +import { IPropertyFieldTeamPickerHostProps } from './IPropertyFieldTeamPickerHost'; +import PropertyFieldTeamPickerHost from './PropertyFieldTeamPickerHost'; + +/** + * Represents a PropertyFieldTeamPicker object + */ + +class PropertyFieldTeamPickerBuilder implements IPropertyPaneField { + + // Properties defined by IPropertyPaneField + public type: PropertyPaneFieldType = PropertyPaneFieldType.Custom; + public targetProperty: string; + public properties: IPropertyFieldTeamPickerPropsInternal; + + // Custom properties + private label: string; + private disabled: boolean = false; + private context: IWebPartContext; + private initialSites: IPropertyFieldTeam[]; + private multiSelect: boolean = false; + private onPropertyChange: (propertyPath: string, oldValue: any, newValue: any) => void; + private customProperties: any; + private key: string; + private onGetErrorMessage: (value: IPropertyFieldTeam[]) => string | Promise; + private deferredValidationTime: number = 200; + + /** + * Constructor method + */ + public constructor(_targetProperty: string, _properties: IPropertyFieldTeamPickerPropsInternal) { + this.render = this.render.bind(this); + this.label = _properties.label; + this.targetProperty = _properties.targetProperty; + this.properties = _properties; + this.properties.onDispose = this.dispose; + this.properties.onRender = this.render; + this.onPropertyChange = _properties.onPropertyChange; + this.context = _properties.context; + this.initialSites = _properties.initialSites; + this.customProperties = _properties.properties; + this.key = _properties.key; + this.onGetErrorMessage = _properties.onGetErrorMessage; + + if (typeof _properties.disabled !== 'undefined') { + this.disabled = _properties.disabled; + } + + if (_properties.deferredValidationTime) { + this.deferredValidationTime = _properties.deferredValidationTime; + } + + if (typeof _properties.multiSelect !== "undefined") { + this.multiSelect = _properties.multiSelect; + } + } + + /** + * Renders the PeoplePicker field content + */ + private render(elem: HTMLElement, ctx?: any, changeCallback?: (targetProperty?: string, newValue?: any) => void): void { + // Construct the JSX properties + const element: React.ReactElement = React.createElement(PropertyFieldTeamPickerHost, { + label: this.label, + disabled: this.disabled, + targetProperty: this.targetProperty, + initialSites: this.initialSites, + multiSelect: this.multiSelect, + onDispose: this.dispose, + onRender: this.render, + onChange: changeCallback, + onPropertyChange: this.onPropertyChange, + context: this.context, + properties: this.customProperties, + key: this.key, + onGetErrorMessage: this.onGetErrorMessage, + deferredValidationTime: this.deferredValidationTime + }); + + // Calls the REACT content generator + ReactDom.render(element, elem); + } + + /** + * Disposes the current object + */ + private dispose(elem: HTMLElement): void { } +} + +/** + * Helper method to create a Site Picker on the PropertyPane. + * @param targetProperty - Target property the site picker is associated to. + * @param properties - Strongly typed site Picker properties. + */ +export function PropertyFieldTeamPicker(targetProperty: string, properties: IPropertyFieldTeamPickerProps): IPropertyPaneField { + // Calls the PropertyFieldTeamPicker builder object + // This object will simulate a PropertyFieldCustom to manage his rendering process + return new PropertyFieldTeamPickerBuilder(targetProperty, { + ...properties, + targetProperty: targetProperty, + onDispose: null, + onRender: null + }); +} \ No newline at end of file diff --git a/src/propertyFields/teamPicker/PropertyFieldTeamPickerHost.module.scss b/src/propertyFields/teamPicker/PropertyFieldTeamPickerHost.module.scss new file mode 100644 index 00000000..09af8998 --- /dev/null +++ b/src/propertyFields/teamPicker/PropertyFieldTeamPickerHost.module.scss @@ -0,0 +1,8 @@ +.siteList { + list-style: none; + padding-left: 5px; +} + +.bold { + font-weight: bold; +} \ No newline at end of file diff --git a/src/propertyFields/teamPicker/PropertyFieldTeamPickerHost.tsx b/src/propertyFields/teamPicker/PropertyFieldTeamPickerHost.tsx new file mode 100644 index 00000000..bee46ade --- /dev/null +++ b/src/propertyFields/teamPicker/PropertyFieldTeamPickerHost.tsx @@ -0,0 +1,142 @@ +import * as React from 'react'; +import { IPropertyFieldTeamPickerHostProps, ITeamPickerState } from './IPropertyFieldTeamPickerHost'; +import TeamsSearchService from '../../services/TeamsSearchService'; +import FieldErrorMessage from '../errorMessage/FieldErrorMessage'; +import * as telemetry from '../../common/telemetry'; +import { Label } from 'office-ui-fabric-react/lib/Label'; +import { SearchBox } from 'office-ui-fabric-react/lib/SearchBox'; +import * as strings from 'PropertyControlStrings'; +import { Spinner, SpinnerSize } from 'office-ui-fabric-react/lib/Spinner'; +import { IPropertyFieldTeam } from './IPropertyFieldTeamPicker'; +import { PropertyFieldTeamPickerListItem } from './PropertyFieldTeamPickerListItem/PropertyFieldSitePickerListItem'; +import styles from './PropertyFieldTeamPickerHost.module.scss'; +import { initializeIcons } from '@uifabric/icons'; +import { Async } from '@uifabric/utilities/lib'; + +export default class PropertyFieldTeamPickerHost extends React.Component { + private teamsService: TeamsSearchService; + private async: Async; + + constructor(props: IPropertyFieldTeamPickerHostProps) { + super(props); + initializeIcons(); + + telemetry.track('PropertyFieldTeamPicker', { + disabled: props.disabled + }); + + this.state = { + isLoading: false, + selectedSites: props.initialSites || [], + siteSearchResults: [], + errorMessage: null + }; + + this.async = new Async(this); + + this.teamsService = new TeamsSearchService(); + } + + private onSearchFieldChange = async (newValue?: string): Promise => { + if (newValue && newValue.length > 2) { + this.setState({ isLoading: true }); + try { + const sites = await this.teamsService.searchTeams(this.props.context, newValue); + this.setState({ siteSearchResults: sites }); + } catch (error) { + this.setState({ errorMessage: error.message }); + } finally { + this.setState({ isLoading: false }); + } + } else { + this.setState({ siteSearchResults: [] }); + } + } + + private handleCheckboxChange = (site: IPropertyFieldTeam, checked: boolean): void => { + let selectedSites = [...this.state.selectedSites]; + if (checked) { + if (this.props.multiSelect) { + selectedSites.push(site); + } else { + selectedSites = [site]; + } + } else { + if (this.props.multiSelect) { + selectedSites.splice(selectedSites.indexOf(site), 1); + } else { + selectedSites = []; + } + } + + this.props.onPropertyChange(this.props.targetProperty, this.state.selectedSites, selectedSites); + // Trigger the apply button + if (typeof this.props.onChange !== 'undefined' && this.props.onChange !== null) { + this.props.onChange(this.props.targetProperty, selectedSites); + } + + this.setState({ selectedSites }); + } + + public render(): JSX.Element { + const { isLoading, siteSearchResults, selectedSites } = this.state; + + return ( +
+ {this.props.label && } + + { + isLoading && + + } + { + !isLoading && siteSearchResults && +
+ { + siteSearchResults.length > 0 && +
    + { + siteSearchResults.map((site: IPropertyFieldTeam): JSX.Element => + s.id === site.id).length > 0} + handleCheckboxChange={this.handleCheckboxChange} + site={site} + /> + ) + } +
+ } + { + siteSearchResults.length === 0 && + + } +
+ } + { + selectedSites && selectedSites.length > 0 && +
+ +
    + { + selectedSites.map((site: IPropertyFieldTeam): JSX.Element => + s.id === site.id).length > 0} + handleCheckboxChange={this.handleCheckboxChange} + site={site} + /> + ) + } +
+
+ } + + +
+ ); + } +} diff --git a/src/propertyFields/teamPicker/PropertyFieldTeamPickerListItem/IPropertyFieldSitePickerListItem.ts b/src/propertyFields/teamPicker/PropertyFieldTeamPickerListItem/IPropertyFieldSitePickerListItem.ts new file mode 100644 index 00000000..69e3e4ab --- /dev/null +++ b/src/propertyFields/teamPicker/PropertyFieldTeamPickerListItem/IPropertyFieldSitePickerListItem.ts @@ -0,0 +1,7 @@ +import { IPropertyFieldTeam } from '../IPropertyFieldTeamPicker'; + +export interface IPropertyFieldTeamPickerListItemProps { + site: IPropertyFieldTeam; + checked: boolean; + handleCheckboxChange(site: IPropertyFieldTeam, checked: boolean): void; +} \ No newline at end of file diff --git a/src/propertyFields/teamPicker/PropertyFieldTeamPickerListItem/PropertyFieldSitePickerListItem.tsx b/src/propertyFields/teamPicker/PropertyFieldTeamPickerListItem/PropertyFieldSitePickerListItem.tsx new file mode 100644 index 00000000..00e2ddd5 --- /dev/null +++ b/src/propertyFields/teamPicker/PropertyFieldTeamPickerListItem/PropertyFieldSitePickerListItem.tsx @@ -0,0 +1,19 @@ +import * as React from 'react'; +import { IPropertyFieldTeamPickerListItemProps } from './IPropertyFieldSitePickerListItem'; +import { Checkbox } from 'office-ui-fabric-react/lib/Checkbox'; +import styles from './PropertyFieldTeamPickerListItem.module.scss'; + +export const PropertyFieldTeamPickerListItem = (props: IPropertyFieldTeamPickerListItemProps): JSX.Element => { + const { site, checked } = props; + + return ( +
  • + , nowChecked?: boolean): void => props.handleCheckboxChange(site, nowChecked)} + /> + {site.title} +
  • + ); +}; \ No newline at end of file diff --git a/src/propertyFields/teamPicker/PropertyFieldTeamPickerListItem/PropertyFieldTeamPickerListItem.module.scss b/src/propertyFields/teamPicker/PropertyFieldTeamPickerListItem/PropertyFieldTeamPickerListItem.module.scss new file mode 100644 index 00000000..fa09d227 --- /dev/null +++ b/src/propertyFields/teamPicker/PropertyFieldTeamPickerListItem/PropertyFieldTeamPickerListItem.module.scss @@ -0,0 +1,15 @@ +.teamListItem { + display: flex; + white-space: nowrap; + + .checkbox { + display: inline-block !important; + margin-right: 10px; + } + + .title { + line-height: 28px; + overflow: hidden; + text-overflow: ellipsis; + } +} \ No newline at end of file diff --git a/src/propertyFields/teamPicker/index.ts b/src/propertyFields/teamPicker/index.ts new file mode 100644 index 00000000..ca013b5f --- /dev/null +++ b/src/propertyFields/teamPicker/index.ts @@ -0,0 +1,4 @@ +export * from './PropertyFieldTeamPicker'; +export * from './IPropertyFieldTeamPicker'; +export * from './PropertyFieldTeamPickerHost'; +export * from './IPropertyFieldTeamPickerHost'; From 97386d363de4ed3aa8994542fcc28671e5715444 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Mendes?= Date: Wed, 7 Oct 2020 12:04:18 +0100 Subject: [PATCH 2/8] update TeamPicker --- src/services/ITeamsSearchService.ts | 13 +++++ src/services/TeamsSearchService.ts | 73 +++++++++++++++++++++++++++++ 2 files changed, 86 insertions(+) create mode 100644 src/services/ITeamsSearchService.ts create mode 100644 src/services/TeamsSearchService.ts diff --git a/src/services/ITeamsSearchService.ts b/src/services/ITeamsSearchService.ts new file mode 100644 index 00000000..6b062efd --- /dev/null +++ b/src/services/ITeamsSearchService.ts @@ -0,0 +1,13 @@ +import { IWebPartContext } from '@microsoft/sp-webpart-base'; +import { IPropertyFieldTeam} from '../propertyFields/teamPicker/IPropertyFieldTeamPicker'; + +/** + * Service interface definition + */ + +export interface ITeamsSearchService { + /** + * Search Site from a query + */ + searchTeams(ctx: IWebPartContext, query: string): Promise>; +} \ No newline at end of file diff --git a/src/services/TeamsSearchService.ts b/src/services/TeamsSearchService.ts new file mode 100644 index 00000000..5a534dcd --- /dev/null +++ b/src/services/TeamsSearchService.ts @@ -0,0 +1,73 @@ +import { Environment, EnvironmentType } from '@microsoft/sp-core-library'; +import SPPeoplePickerMockHttpClient from './SPPeopleSearchMockService'; +import { WebPartContext, IWebPartContext } from "@microsoft/sp-webpart-base"; +import { ITeamsSearchService } from './ITeamsSearchService'; +import { IPropertyFieldTeam } from '../propertyFields/teamPicker/IPropertyFieldTeamPicker'; +import { GraphHttpClient, HttpClientResponse } from '@microsoft/sp-http'; +import { getCtxCallback } from '@pnp/common'; +import { CheckboxVisibility } from 'office-ui-fabric-react/lib/DetailsList'; +import { dateAdd, PnPClientStorage } from "@pnp/common"; +/** + * Service implementation to search sites in SharePoint + */ +export default class TeamsSearchService implements ITeamsSearchService { + /** + * Search sites from the SharePoint + */ + private storage = new PnPClientStorage(); + public async searchTeams(ctx: any, query: string): Promise { + if (Environment.type === EnvironmentType.Local) { + // If the running environment is local, load the data from the mock + return this.searchSitesFromMock(ctx, query); + } else { + + const _msGraphClient = await ctx.msGraphClientFactory.getClient(); + const _listOfTeamsResults: any = await _msGraphClient + .api(`/groups?$filter=startswith(displayName,'${query}') AND resourceProvisioningOptions/Any(x:x eq 'Team')`) + .version("beta") + .get(); + + const _listOfTeams: any[] = _listOfTeamsResults.value; + + let _res: IPropertyFieldTeam[] = []; + if (_listOfTeams && _listOfTeams.length > 0) { + for (const _team of _listOfTeams) { + const _webUrl = await this.getGroupUrl(ctx,_team.id); + _res.push({ id: _team.id, title: _team.displayName, url: _webUrl}); + } + } + return _res; + } + } + + private async getGroupUrl(ctx:any, groupId:string):Promise{ + const cachedGroupUrl:string = this.storage.local.get(`${groupId}WebUrl`); + if (!cachedGroupUrl){ + const _msGraphClient = await ctx.msGraphClientFactory.getClient(); + const _groupInfo: any = await _msGraphClient + .api(`/groups/${groupId}/drive/root/webUrl`) + .version("beta") + .get(); + + let _webUrl:string = _groupInfo.value; + const _lastSlash = _webUrl.lastIndexOf('/'); + _webUrl = _webUrl.substring(0, _lastSlash); + this.storage.local.put(`${groupId}WebUrl`, _webUrl, dateAdd(new Date(), "day", 5)); + return _webUrl; + }else{ + return cachedGroupUrl; + } + } + + /** + * Returns fake sites results for the Mock mode + */ + private searchSitesFromMock(ctx: IWebPartContext, query: string): Promise> { + return SPPeoplePickerMockHttpClient.searchPeople(ctx.pageContext.web.absoluteUrl).then(() => { + const results: IPropertyFieldTeam[] = [ + { title: 'Contoso Team', id: '611453e1-5b5d-45ec-94aa-a180a02df897', url: ctx.pageContext.web.absoluteUrl } + ]; + return results; + }) as Promise>; + } +} From c7c09a8822a170dc43b89a7753d9ae0b41bdfa29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Mendes?= Date: Wed, 7 Oct 2020 15:02:31 +0100 Subject: [PATCH 3/8] update strings --- src/loc/en-us.js | 7 +++- src/loc/fr-fr.js | 3 +- src/loc/mystrings.d.ts | 7 +++- src/loc/nl-nl.js | 3 +- src/loc/no.js | 3 +- src/loc/ru-ru.js | 3 +- src/loc/zh-cn.js | 3 +- .../PropertyFieldTeamPickerHost.tsx | 39 ++++++++++++------- src/services/TeamsSearchService.ts | 25 +++++++----- 9 files changed, 62 insertions(+), 31 deletions(-) diff --git a/src/loc/en-us.js b/src/loc/en-us.js index 2a34809d..6471ac1d 100644 --- a/src/loc/en-us.js +++ b/src/loc/en-us.js @@ -79,6 +79,9 @@ define([], function () { SitePickerSearchBoxPlaceholder: "Search...", SitePickerNoResults: "No search results", SitePickerSitesChosen: "Website(s) selected", + TeamPickerSearchBoxPlaceholder: "Search...", + TeamPickerNoResults: "No search results", + TeamPickerSitesChosen: "Teams(s) selected", AddFileButtonLabel: "Add file", AddImageButtonLabel: "Add image", @@ -222,7 +225,7 @@ define([], function () { NewFolderNamePlaceholder: "Enter your folder name", FolderFilterBoxPlaceholder: "Filter folders by name", FolderExplorerLoading: "Loading folders...", - FolderExplorerNoItems: "This folder doesn't have any subfolders." - + FolderExplorerNoItems: "This folder doesn't have any subfolders.", + } }); diff --git a/src/loc/fr-fr.js b/src/loc/fr-fr.js index 936a8855..5832f10d 100644 --- a/src/loc/fr-fr.js +++ b/src/loc/fr-fr.js @@ -74,6 +74,7 @@ define([], function() { InvalidUrlError: "L'URL fournie n'est pas valide", DescriptionLabel: "La description", MoreInfoLabel: "Plus d'informations", - AboutGroupLabel: "Sur" + AboutGroupLabel: "Sur" , + } }); diff --git a/src/loc/mystrings.d.ts b/src/loc/mystrings.d.ts index bf214b36..bd755eb8 100644 --- a/src/loc/mystrings.d.ts +++ b/src/loc/mystrings.d.ts @@ -88,7 +88,7 @@ declare interface IPropertyControlStrings { CollectionDataItemFieldRequiredLabel: string; InvalidUrlError: string; - // Property Editor + // Property Editor ApplyButtonLabel: string; ImportButtonLabel: string; ExportButtonLabel: string; @@ -100,6 +100,11 @@ declare interface IPropertyControlStrings { SitePickerNoResults: string; SitePickerSitesChosen: string; + // team Picker labels + TeamPickerSearchBoxPlaceholder: string; + TeamPickerNoResults: string; + TeamPickerSitesChosen: string; + //FilePicker // File picker AddFileButtonLabel: string; diff --git a/src/loc/nl-nl.js b/src/loc/nl-nl.js index 458843d2..96c498cb 100644 --- a/src/loc/nl-nl.js +++ b/src/loc/nl-nl.js @@ -74,6 +74,7 @@ define([], function () { InvalidUrlError: "De huidige URL is niet geldig", DescriptionLabel: "Beschrijving", MoreInfoLabel: "Meer info", - AboutGroupLabel: "Over" + AboutGroupLabel: "Over" , + } }); diff --git a/src/loc/no.js b/src/loc/no.js index b5caa67d..42aa2e72 100644 --- a/src/loc/no.js +++ b/src/loc/no.js @@ -74,6 +74,7 @@ define([], function() { InvalidUrlError: "Den angitte nettadressen er ikke gyldig", DescriptionLabel: "Beskrivelse", MoreInfoLabel: "Mer informasjon", - AboutGroupLabel: "Om" + AboutGroupLabel: "Om", + } }); diff --git a/src/loc/ru-ru.js b/src/loc/ru-ru.js index f6a363a1..3457f215 100644 --- a/src/loc/ru-ru.js +++ b/src/loc/ru-ru.js @@ -74,6 +74,7 @@ define([], function() { InvalidUrlError: "Заданное значение не является корректной ссылкой", DescriptionLabel: "Описание", MoreInfoLabel: "Подробнее", - AboutGroupLabel: "Справка" + AboutGroupLabel: "Справка", + } }); diff --git a/src/loc/zh-cn.js b/src/loc/zh-cn.js index dd9ddeb4..4be79d3a 100644 --- a/src/loc/zh-cn.js +++ b/src/loc/zh-cn.js @@ -74,6 +74,7 @@ define([], function () { InvalidUrlError: "链接地址不正确", DescriptionLabel: "简介", MoreInfoLabel: "更多信息", - AboutGroupLabel: "关于" + AboutGroupLabel: "关于", + } }); diff --git a/src/propertyFields/teamPicker/PropertyFieldTeamPickerHost.tsx b/src/propertyFields/teamPicker/PropertyFieldTeamPickerHost.tsx index bee46ade..5efabb5f 100644 --- a/src/propertyFields/teamPicker/PropertyFieldTeamPickerHost.tsx +++ b/src/propertyFields/teamPicker/PropertyFieldTeamPickerHost.tsx @@ -1,17 +1,28 @@ -import * as React from 'react'; -import { IPropertyFieldTeamPickerHostProps, ITeamPickerState } from './IPropertyFieldTeamPickerHost'; -import TeamsSearchService from '../../services/TeamsSearchService'; -import FieldErrorMessage from '../errorMessage/FieldErrorMessage'; -import * as telemetry from '../../common/telemetry'; -import { Label } from 'office-ui-fabric-react/lib/Label'; -import { SearchBox } from 'office-ui-fabric-react/lib/SearchBox'; -import * as strings from 'PropertyControlStrings'; -import { Spinner, SpinnerSize } from 'office-ui-fabric-react/lib/Spinner'; -import { IPropertyFieldTeam } from './IPropertyFieldTeamPicker'; -import { PropertyFieldTeamPickerListItem } from './PropertyFieldTeamPickerListItem/PropertyFieldSitePickerListItem'; -import styles from './PropertyFieldTeamPickerHost.module.scss'; -import { initializeIcons } from '@uifabric/icons'; -import { Async } from '@uifabric/utilities/lib'; +import * as React from "react"; + +import { Label } from "office-ui-fabric-react/lib/Label"; +import { SearchBox } from "office-ui-fabric-react/lib/SearchBox"; +import { + Spinner, + SpinnerSize +} from "office-ui-fabric-react/lib/Spinner"; +import * as strings from "PropertyControlStrings"; + +import { initializeIcons } from "@uifabric/icons"; +import { Async } from "@uifabric/utilities/lib"; + +import * as telemetry from "../../common/telemetry"; +import TeamsSearchService from "../../services/TeamsSearchService"; +import FieldErrorMessage from "../errorMessage/FieldErrorMessage"; +import { IPropertyFieldTeam } from "./IPropertyFieldTeamPicker"; +import { + IPropertyFieldTeamPickerHostProps, + ITeamPickerState +} from "./IPropertyFieldTeamPickerHost"; +import styles from "./PropertyFieldTeamPickerHost.module.scss"; +import { + PropertyFieldTeamPickerListItem +} from "./PropertyFieldTeamPickerListItem/PropertyFieldSitePickerListItem"; export default class PropertyFieldTeamPickerHost extends React.Component { private teamsService: TeamsSearchService; diff --git a/src/services/TeamsSearchService.ts b/src/services/TeamsSearchService.ts index 5a534dcd..0f35051b 100644 --- a/src/services/TeamsSearchService.ts +++ b/src/services/TeamsSearchService.ts @@ -1,12 +1,19 @@ -import { Environment, EnvironmentType } from '@microsoft/sp-core-library'; -import SPPeoplePickerMockHttpClient from './SPPeopleSearchMockService'; -import { WebPartContext, IWebPartContext } from "@microsoft/sp-webpart-base"; -import { ITeamsSearchService } from './ITeamsSearchService'; -import { IPropertyFieldTeam } from '../propertyFields/teamPicker/IPropertyFieldTeamPicker'; -import { GraphHttpClient, HttpClientResponse } from '@microsoft/sp-http'; -import { getCtxCallback } from '@pnp/common'; -import { CheckboxVisibility } from 'office-ui-fabric-react/lib/DetailsList'; -import { dateAdd, PnPClientStorage } from "@pnp/common"; +import { + Environment, + EnvironmentType +} from "@microsoft/sp-core-library"; +import { IWebPartContext } from "@microsoft/sp-webpart-base"; +import { + dateAdd, + PnPClientStorage +} from "@pnp/common"; + +import { + IPropertyFieldTeam +} from "../propertyFields/teamPicker/IPropertyFieldTeamPicker"; +import { ITeamsSearchService } from "./ITeamsSearchService"; +import SPPeoplePickerMockHttpClient from "./SPPeopleSearchMockService"; + /** * Service implementation to search sites in SharePoint */ From 674f622253ae10cf6b30578b161cda8123878d45 Mon Sep 17 00:00:00 2001 From: Alex Terentiev Date: Wed, 28 Oct 2020 17:13:44 -0700 Subject: [PATCH 4/8] chinese loc fix --- src/loc/zh-cn.js | 80 ------------------------------------------------ 1 file changed, 80 deletions(-) diff --git a/src/loc/zh-cn.js b/src/loc/zh-cn.js index b70a388a..bbfcd223 100644 --- a/src/loc/zh-cn.js +++ b/src/loc/zh-cn.js @@ -1,6 +1,5 @@ define([], () => { return { -<<<<<<< HEAD "ApplyButtonLabel": "应用", "ImportButtonLabel": "导入", "ExportButtonLabel": "导出", @@ -222,83 +221,4 @@ define([], () => { "FolderExplorerLoading": "正在加载文件夹...", "FolderExplorerNoItems": "此文件夹没有任何子文件夹。" }; -======= - ApplyButtonLabel: "应用", - ImportButtonLabel: "导入", - ExportButtonLabel: "导出", - JsonFileRequiredMessage: "请上传Json文件", - SaveButtonLabel: "保存", - CancelButtonLabel: "取消", - PeoplePickerSuggestedContacts: "匹配的人员", - PeoplePickerSuggestedGroups: "匹配的组", - PeoplePickerSuggestedCombined: "匹配的组和人员", - PeoplePickerNoResults: "没有找到", - PeoplePickerLoading: "加载中 ...", - DatePickerMonthLongJanuary: "一月", - DatePickerMonthShortJanuary: "一月", - DatePickerMonthLongFebruary: "二月", - DatePickerMonthShortFebruary: "二月", - DatePickerMonthLongMarch: "三月", - DatePickerMonthShortMarch: "三月", - DatePickerMonthLongApril: "四月", - DatePickerMonthShortApril: "四月", - DatePickerMonthLongMay: "五月", - DatePickerMonthShortMay: "五月", - DatePickerMonthLongJune: "六月", - DatePickerMonthShortJune: "六月", - DatePickerMonthLongJuly: "七月", - DatePickerMonthShortJuly: "七月", - DatePickerMonthLongAugust: "八月", - DatePickerMonthShortAugust: "八月", - DatePickerMonthLongSeptember: "九月", - DatePickerMonthShortSeptember: "九月", - DatePickerMonthLongOctober: "十月", - DatePickerMonthShortOctober: "十月", - DatePickerMonthLongNovember: "十一月", - DatePickerMonthShortNovember: "十一月", - DatePickerMonthLongDecember: "十二月", - DatePickerMonthShortDecember: "十二月", - DatePickerDayLongSunday: "星期天", - DatePickerDayShortSunday: "周天", - DatePickerDayLongMonday: "星期一", - DatePickerDayShortMonday: "周一", - DatePickerDayLongTuesday: "星期二", - DatePickerDayShortTuesday: "周二", - DatePickerDayLongWednesday: "星期三", - DatePickerDayShortWednesday: "周三", - DatePickerDayLongThursday: "星期四", - DatePickerDayShortThursday: "周四", - DatePickerDayLongFriday: "星期五", - DatePickerDayShortFriday: "周五", - DatePickerDayLongSaturday: "星期六", - DatePickerDayShortSaturday: "周六", - DatepickerGoToToday: "今天", - DateTimePickerDate: "日期", - DateTimePickerTime: "时间", - ColorPickerButtonTitle: "选择颜色", - NotNumberValidationMessage: "值必须为数字, 实际是:", - MinimumNumberValidationMessage: "值应该大于:", - MaximumNumberValidationMessage: "值应该小于:", - TermPickerNoTerms: "术语集中不包含任何术语", - TermPickerExpandTitle: "展开此术语集", - TermPickerExpandNode: "展开节点", - TermPickerMenuTermSet: "术语集菜单", - TermPickerMenuGroup: "术语集菜单", - TermPickerInLabel: "在", - TermPickerTermSetLabel: "一组术语", - propertyFieldMultiSelectNoOptions: "没有可供选择的项", - CollectionDataEmptyFields: "集合中没有字段信息.", - CollectionDataEmptyValue: "集合中没有数据", - CollectionAddRowButtonLabel: "添加数据到集合", - CollectionDeleteRowButtonLabel: "删除当前项", - CollectionSaveAndAddButtonLabel: "添加并保存", - CollectionDataItemShowErrorsLabel: "显示数据项错误信息", - CollectionDataItemFieldRequiredLabel: "必填项", - InvalidUrlError: "链接地址不正确", - DescriptionLabel: "简介", - MoreInfoLabel: "更多信息", - AboutGroupLabel: "关于", - - } ->>>>>>> c7c09a8822a170dc43b89a7753d9ae0b41bdfa29 }); From 26b303c04b505e9fb0d68a8178bd504811aab781 Mon Sep 17 00:00:00 2001 From: Alex Terentiev Date: Wed, 28 Oct 2020 17:19:50 -0700 Subject: [PATCH 5/8] translations --- src/loc/bg-bg.js | 10 ++++++++-- src/loc/ca-es.js | 10 ++++++++-- src/loc/da-dk.js | 10 ++++++++-- src/loc/de-de.js | 10 ++++++++-- src/loc/el-gr.js | 10 ++++++++-- src/loc/es-es.js | 10 ++++++++-- src/loc/et-ee.js | 10 ++++++++-- src/loc/fi-fi.js | 10 ++++++++-- src/loc/fr-fr.js | 10 ++++++++-- src/loc/it-it.js | 10 ++++++++-- src/loc/ja-jp.js | 10 ++++++++-- src/loc/lt-lt.js | 10 ++++++++-- src/loc/lv-lv.js | 10 ++++++++-- src/loc/nb-no.js | 10 ++++++++-- src/loc/nl-nl.js | 10 ++++++++-- src/loc/pl-pl.js | 10 ++++++++-- src/loc/pt-pt.js | 10 ++++++++-- src/loc/ro-ro.js | 10 ++++++++-- src/loc/ru-ru.js | 10 ++++++++-- src/loc/sk-sk.js | 10 ++++++++-- src/loc/sr-latn-rs.js | 10 ++++++++-- src/loc/sv-se.js | 10 ++++++++-- src/loc/tr-tr.js | 10 ++++++++-- src/loc/vi-vn.js | 10 ++++++++-- src/loc/zh-cn.js | 10 ++++++++-- src/loc/zh-tw.js | 10 ++++++++-- 26 files changed, 208 insertions(+), 52 deletions(-) diff --git a/src/loc/bg-bg.js b/src/loc/bg-bg.js index cfb2390d..8107fde7 100644 --- a/src/loc/bg-bg.js +++ b/src/loc/bg-bg.js @@ -79,6 +79,9 @@ define([], () => { "SitePickerSearchBoxPlaceholder": "Търсене...", "SitePickerNoResults": "Няма резултати от търсенето", "SitePickerSitesChosen": "Избран(и) уебсайт(и)", + "TeamPickerSearchBoxPlaceholder": "Търсене...", + "TeamPickerNoResults": "Няма резултати от търсенето", + "TeamPickerSitesChosen": "Избрани екипи", "AddFileButtonLabel": "Добавяне на файл", "AddImageButtonLabel": "Добавяне на изображение", "AriaCellValue": "{0} колона {1}", @@ -190,6 +193,8 @@ define([], () => { "UploadLinkLabel": "Качите", "WebSearchLinkLabel": "Търсене в уеб", "Yes": "Да", + "StockImagesLinkLabel": "Изображения на склад", + "StockImagesHeader": "Изображения на склад", "DateTime": { "L_RelativeDateTime_AFewSecondsFuture": "След няколко секунди", "L_RelativeDateTime_AFewSeconds": "Преди няколко секунди", @@ -219,6 +224,7 @@ define([], () => { "NewFolderNamePlaceholder": "Въведете името на вашата папка", "FolderFilterBoxPlaceholder": "Филтриране на папки по име", "FolderExplorerLoading": "Зареждане на папки...", - "FolderExplorerNoItems": "Тази папка няма никакви подпапки." + "FolderExplorerNoItems": "Тази папка няма никакви подпапки.", + "IncorrectGuidValidationMessage": "Въведете валиден GUID" }; -}); +}); \ No newline at end of file diff --git a/src/loc/ca-es.js b/src/loc/ca-es.js index ee7c93e6..ce4e992e 100644 --- a/src/loc/ca-es.js +++ b/src/loc/ca-es.js @@ -79,6 +79,9 @@ define([], () => { "SitePickerSearchBoxPlaceholder": "Cerca...", "SitePickerNoResults": "Sense resultats de cerca", "SitePickerSitesChosen": "Llocs web seleccionats", + "TeamPickerSearchBoxPlaceholder": "Cerca...", + "TeamPickerNoResults": "Sense resultats de cerca", + "TeamPickerSitesChosen": "Equips seleccionats", "AddFileButtonLabel": "Afegeix un fitxer", "AddImageButtonLabel": "Afegeix una imatge", "AriaCellValue": "{0} columna, {1}", @@ -190,6 +193,8 @@ define([], () => { "UploadLinkLabel": "Carregar", "WebSearchLinkLabel": "Cerca web", "Yes": "Sí", + "StockImagesLinkLabel": "Imatges d'estoc", + "StockImagesHeader": "Imatges d'estoc", "DateTime": { "L_RelativeDateTime_AFewSecondsFuture": "En pocs segons", "L_RelativeDateTime_AFewSeconds": "Fa uns segons", @@ -219,6 +224,7 @@ define([], () => { "NewFolderNamePlaceholder": "Introduïu el nom de la carpeta", "FolderFilterBoxPlaceholder": "Filtra les carpetes pel seu nom", "FolderExplorerLoading": "S'estan carregant les carpetes...", - "FolderExplorerNoItems": "Aquesta carpeta no té subcarpetes." + "FolderExplorerNoItems": "Aquesta carpeta no té subcarpetes.", + "IncorrectGuidValidationMessage": "Introduïu un GUID vàlid" }; -}); +}); \ No newline at end of file diff --git a/src/loc/da-dk.js b/src/loc/da-dk.js index f51a36ac..4d64d071 100644 --- a/src/loc/da-dk.js +++ b/src/loc/da-dk.js @@ -79,6 +79,9 @@ define([], () => { "SitePickerSearchBoxPlaceholder": "Søg...", "SitePickerNoResults": "Ingen søgeresultater", "SitePickerSitesChosen": "Hjemmeside(er) valgt", + "TeamPickerSearchBoxPlaceholder": "Søg...", + "TeamPickerNoResults": "Ingen søgeresultater", + "TeamPickerSitesChosen": "Hold valgt", "AddFileButtonLabel": "Tilføj fil", "AddImageButtonLabel": "Tilføj billede", "AriaCellValue": "{0} kolonne, {1}", @@ -190,6 +193,8 @@ define([], () => { "UploadLinkLabel": "Uploade", "WebSearchLinkLabel": "Søgning på internettet", "Yes": "Ja", + "StockImagesLinkLabel": "Stock billeder", + "StockImagesHeader": "Stock billeder", "DateTime": { "L_RelativeDateTime_AFewSecondsFuture": "På få sekunder", "L_RelativeDateTime_AFewSeconds": "For et par sekunder siden", @@ -219,6 +224,7 @@ define([], () => { "NewFolderNamePlaceholder": "Angiv navnet på din mappe", "FolderFilterBoxPlaceholder": "Filtrere mapper efter navn", "FolderExplorerLoading": "Indlæser mapper...", - "FolderExplorerNoItems": "Denne mappe har ingen undermapper." + "FolderExplorerNoItems": "Denne mappe har ingen undermapper.", + "IncorrectGuidValidationMessage": "Angiv et gyldigt GUID" }; -}); +}); \ No newline at end of file diff --git a/src/loc/de-de.js b/src/loc/de-de.js index 101060b1..9042cda0 100644 --- a/src/loc/de-de.js +++ b/src/loc/de-de.js @@ -79,6 +79,9 @@ define([], () => { "SitePickerSearchBoxPlaceholder": "Suche...", "SitePickerNoResults": "Keine Suchergebnisse", "SitePickerSitesChosen": "Website(n) ausgewählt", + "TeamPickerSearchBoxPlaceholder": "Suche...", + "TeamPickerNoResults": "Keine Suchergebnisse", + "TeamPickerSitesChosen": "Teams(e) ausgewählt", "AddFileButtonLabel": "Datei hinzufügen", "AddImageButtonLabel": "Hinzufügen von Bildern", "AriaCellValue": "{0} Spalte, {1}", @@ -190,6 +193,8 @@ define([], () => { "UploadLinkLabel": "Hochladen", "WebSearchLinkLabel": "Websuche", "Yes": "Ja", + "StockImagesLinkLabel": "Stockbilder", + "StockImagesHeader": "Stock Bilder", "DateTime": { "L_RelativeDateTime_AFewSecondsFuture": "In wenigen Sekunden", "L_RelativeDateTime_AFewSeconds": "vor ein paar Sekunden", @@ -219,6 +224,7 @@ define([], () => { "NewFolderNamePlaceholder": "Geben Sie Ihren Ordnernamen ein", "FolderFilterBoxPlaceholder": "Filtern von Ordnern nach Namen", "FolderExplorerLoading": "Ordner werden geladen...", - "FolderExplorerNoItems": "Dieser Ordner hat keine Unterordner." + "FolderExplorerNoItems": "Dieser Ordner hat keine Unterordner.", + "IncorrectGuidValidationMessage": "Bitte geben Sie eine gültige GUID ein" }; -}); +}); \ No newline at end of file diff --git a/src/loc/el-gr.js b/src/loc/el-gr.js index 0b7931f6..f0596f13 100644 --- a/src/loc/el-gr.js +++ b/src/loc/el-gr.js @@ -79,6 +79,9 @@ define([], () => { "SitePickerSearchBoxPlaceholder": "Αναζήτηση...", "SitePickerNoResults": "Δεν υπάρχουν αποτελέσματα αναζήτησης", "SitePickerSitesChosen": "Επιλεγμένοι ιστότοποι", + "TeamPickerSearchBoxPlaceholder": "Αναζήτηση...", + "TeamPickerNoResults": "Δεν υπάρχουν αποτελέσματα αναζήτησης", + "TeamPickerSitesChosen": "Επιλεγμένες ομάδες", "AddFileButtonLabel": "Προσθήκη αρχείου", "AddImageButtonLabel": "Προσθήκη εικόνας", "AriaCellValue": "{0} στήλη, {1}", @@ -190,6 +193,8 @@ define([], () => { "UploadLinkLabel": "Φορτώσετε", "WebSearchLinkLabel": "Αναζήτηση στο Web", "Yes": "Ναι", + "StockImagesLinkLabel": "Στοκ εικόνες", + "StockImagesHeader": "Στοκ Εικόνες", "DateTime": { "L_RelativeDateTime_AFewSecondsFuture": "Σε λίγα δευτερόλεπτα.", "L_RelativeDateTime_AFewSeconds": "Πριν από λίγα δευτερόλεπτα.", @@ -219,6 +224,7 @@ define([], () => { "NewFolderNamePlaceholder": "Πληκτρολογήστε το όνομα του φακέλου σας", "FolderFilterBoxPlaceholder": "Φιλτράρισμα φακέλων με βάση το όνομα", "FolderExplorerLoading": "Φόρτωση φακέλων...", - "FolderExplorerNoItems": "Αυτός ο φάκελος δεν έχει υποφακέλους." + "FolderExplorerNoItems": "Αυτός ο φάκελος δεν έχει υποφακέλους.", + "IncorrectGuidValidationMessage": "Πληκτρολογήστε ένα έγκυρο GUID" }; -}); +}); \ No newline at end of file diff --git a/src/loc/es-es.js b/src/loc/es-es.js index 918979f6..6ae1823a 100644 --- a/src/loc/es-es.js +++ b/src/loc/es-es.js @@ -79,6 +79,9 @@ define([], () => { "SitePickerSearchBoxPlaceholder": "Búsqueda...", "SitePickerNoResults": "Sin resultados de búsqueda", "SitePickerSitesChosen": "Sitio(s) web(s) seleccionado(s)", + "TeamPickerSearchBoxPlaceholder": "Búsqueda...", + "TeamPickerNoResults": "Sin resultados de búsqueda", + "TeamPickerSitesChosen": "Equipos seleccionados", "AddFileButtonLabel": "Añadir archivo", "AddImageButtonLabel": "Añadir imagen", "AriaCellValue": "{0} columna, {1}", @@ -190,6 +193,8 @@ define([], () => { "UploadLinkLabel": "Subir", "WebSearchLinkLabel": "Búsqueda web", "Yes": "Sí", + "StockImagesLinkLabel": "Imágenes de stock", + "StockImagesHeader": "Imágenes de stock", "DateTime": { "L_RelativeDateTime_AFewSecondsFuture": "En pocos segundos", "L_RelativeDateTime_AFewSeconds": "Hace unos segundos", @@ -219,6 +224,7 @@ define([], () => { "NewFolderNamePlaceholder": "Introduzca el nombre de la carpeta", "FolderFilterBoxPlaceholder": "Filtrar carpetas por nombre", "FolderExplorerLoading": "Cargando carpetas...", - "FolderExplorerNoItems": "Esta carpeta no tiene subcarpetas." + "FolderExplorerNoItems": "Esta carpeta no tiene subcarpetas.", + "IncorrectGuidValidationMessage": "Introduzca un GUID válido" }; -}); +}); \ No newline at end of file diff --git a/src/loc/et-ee.js b/src/loc/et-ee.js index 94c6816c..eff42fe9 100644 --- a/src/loc/et-ee.js +++ b/src/loc/et-ee.js @@ -79,6 +79,9 @@ define([], () => { "SitePickerSearchBoxPlaceholder": "Otsing...", "SitePickerNoResults": "Otsingutulemeid pole", "SitePickerSitesChosen": "Valitud veebisait (veebisaidid)", + "TeamPickerSearchBoxPlaceholder": "Otsing...", + "TeamPickerNoResults": "Otsingutulemeid pole", + "TeamPickerSitesChosen": "Valitud meeskonnad", "AddFileButtonLabel": "Lisa fail", "AddImageButtonLabel": "Lisa pilt", "AriaCellValue": "{0} veerg, {1}", @@ -190,6 +193,8 @@ define([], () => { "UploadLinkLabel": "Laadida", "WebSearchLinkLabel": "Veebiotsing", "Yes": "Jah", + "StockImagesLinkLabel": "Laospildid", + "StockImagesHeader": "Laos pildid", "DateTime": { "L_RelativeDateTime_AFewSecondsFuture": "Mõne sekundi pärast", "L_RelativeDateTime_AFewSeconds": "Paar sekundit tagasi", @@ -219,6 +224,7 @@ define([], () => { "NewFolderNamePlaceholder": "Sisestage oma kausta nimi", "FolderFilterBoxPlaceholder": "Filtreeri kaustad nime järgi", "FolderExplorerLoading": "Kaustade laadimine...", - "FolderExplorerNoItems": "Sellel kaustal pole ühtegi alamkausta." + "FolderExplorerNoItems": "Sellel kaustal pole ühtegi alamkausta.", + "IncorrectGuidValidationMessage": "Sisestage sobiv GUID" }; -}); +}); \ No newline at end of file diff --git a/src/loc/fi-fi.js b/src/loc/fi-fi.js index a2da6e57..26a70918 100644 --- a/src/loc/fi-fi.js +++ b/src/loc/fi-fi.js @@ -79,6 +79,9 @@ define([], () => { "SitePickerSearchBoxPlaceholder": "Etsi...", "SitePickerNoResults": "Ei hakutuloksia", "SitePickerSitesChosen": "Valitut verkkosivustot", + "TeamPickerSearchBoxPlaceholder": "Etsi...", + "TeamPickerNoResults": "Ei hakutuloksia", + "TeamPickerSitesChosen": "Valitut ryhmät", "AddFileButtonLabel": "Lisää tiedosto", "AddImageButtonLabel": "Lisää kuva", "AriaCellValue": "{0} sarake, {1}", @@ -190,6 +193,8 @@ define([], () => { "UploadLinkLabel": "Ladata", "WebSearchLinkLabel": "Web-haku", "Yes": "Kyllä", + "StockImagesLinkLabel": "Arkistokuvat", + "StockImagesHeader": "Arkistokuvat", "DateTime": { "L_RelativeDateTime_AFewSecondsFuture": "Muutamassa sekunnissa", "L_RelativeDateTime_AFewSeconds": "Muutama sekunti sitten.", @@ -219,6 +224,7 @@ define([], () => { "NewFolderNamePlaceholder": "Kirjoita kansion nimi", "FolderFilterBoxPlaceholder": "Kansioiden suodattaminen nimen mukaan", "FolderExplorerLoading": "Ladataan kansioita...", - "FolderExplorerNoItems": "Tässä kansiossa ei ole alikansioita." + "FolderExplorerNoItems": "Tässä kansiossa ei ole alikansioita.", + "IncorrectGuidValidationMessage": "Anna kelvollinen GUID-tunnus" }; -}); +}); \ No newline at end of file diff --git a/src/loc/fr-fr.js b/src/loc/fr-fr.js index 7b7485ef..e7e01cec 100644 --- a/src/loc/fr-fr.js +++ b/src/loc/fr-fr.js @@ -79,6 +79,9 @@ define([], () => { "SitePickerSearchBoxPlaceholder": "rechercher...", "SitePickerNoResults": "Aucun résultat de recherche", "SitePickerSitesChosen": "Site(s) website(s) sélectionné(s)", + "TeamPickerSearchBoxPlaceholder": "rechercher...", + "TeamPickerNoResults": "Aucun résultat de recherche", + "TeamPickerSitesChosen": "Équipes sélectionnées", "AddFileButtonLabel": "Ajouter un fichier", "AddImageButtonLabel": "Ajouter une image", "AriaCellValue": "{0} colonne, {1}", @@ -190,6 +193,8 @@ define([], () => { "UploadLinkLabel": "Télécharger", "WebSearchLinkLabel": "Recherche web", "Yes": "Oui", + "StockImagesLinkLabel": "Images stock", + "StockImagesHeader": "Stock Images", "DateTime": { "L_RelativeDateTime_AFewSecondsFuture": "En quelques secondes", "L_RelativeDateTime_AFewSeconds": "Il y a quelques secondes", @@ -219,6 +224,7 @@ define([], () => { "NewFolderNamePlaceholder": "Entrez le nom de votre dossier", "FolderFilterBoxPlaceholder": "Filtrer les dossiers par nom", "FolderExplorerLoading": "Chargement de dossiers...", - "FolderExplorerNoItems": "Ce dossier n’a pas de sous-dossiers." + "FolderExplorerNoItems": "Ce dossier n’a pas de sous-dossiers.", + "IncorrectGuidValidationMessage": "Veuillez entrer un GUID valide" }; -}); +}); \ No newline at end of file diff --git a/src/loc/it-it.js b/src/loc/it-it.js index bce3c6a0..b63c52f1 100644 --- a/src/loc/it-it.js +++ b/src/loc/it-it.js @@ -79,6 +79,9 @@ define([], () => { "SitePickerSearchBoxPlaceholder": "Ricerca...", "SitePickerNoResults": "Nessun risultato di ricerca", "SitePickerSitesChosen": "Siti web selezionati", + "TeamPickerSearchBoxPlaceholder": "Ricerca...", + "TeamPickerNoResults": "Nessun risultato di ricerca", + "TeamPickerSitesChosen": "Team selezionati", "AddFileButtonLabel": "Aggiungi file", "AddImageButtonLabel": "Aggiungi immagine", "AriaCellValue": "{0} colonna, {1}", @@ -190,6 +193,8 @@ define([], () => { "UploadLinkLabel": "Caricare", "WebSearchLinkLabel": "Ricerca sul Web", "Yes": "Sì", + "StockImagesLinkLabel": "Immagini stock", + "StockImagesHeader": "Immagini stock", "DateTime": { "L_RelativeDateTime_AFewSecondsFuture": "In pochi secondi", "L_RelativeDateTime_AFewSeconds": "Pochi secondi fa", @@ -219,6 +224,7 @@ define([], () => { "NewFolderNamePlaceholder": "Immettere il nome della cartella", "FolderFilterBoxPlaceholder": "Filtrare le cartelle per nome", "FolderExplorerLoading": "Caricamento delle cartelle in corso...", - "FolderExplorerNoItems": "Questa cartella non contiene sottocartelle." + "FolderExplorerNoItems": "Questa cartella non contiene sottocartelle.", + "IncorrectGuidValidationMessage": "Immettere un GUID valido" }; -}); +}); \ No newline at end of file diff --git a/src/loc/ja-jp.js b/src/loc/ja-jp.js index c0972e60..9dec0335 100644 --- a/src/loc/ja-jp.js +++ b/src/loc/ja-jp.js @@ -79,6 +79,9 @@ define([], () => { "SitePickerSearchBoxPlaceholder": "検索。。。", "SitePickerNoResults": "検索結果なし", "SitePickerSitesChosen": "選択したウェブサイト", + "TeamPickerSearchBoxPlaceholder": "検索。。。", + "TeamPickerNoResults": "検索結果なし", + "TeamPickerSitesChosen": "選択されたチーム", "AddFileButtonLabel": "ファイルの追加", "AddImageButtonLabel": "画像を追加する", "AriaCellValue": "{0}列、{1}", @@ -190,6 +193,8 @@ define([], () => { "UploadLinkLabel": "アップロード", "WebSearchLinkLabel": "ウェブ検索", "Yes": "はい", + "StockImagesLinkLabel": "ストック画像", + "StockImagesHeader": "ストック画像", "DateTime": { "L_RelativeDateTime_AFewSecondsFuture": "秒単位", "L_RelativeDateTime_AFewSeconds": "数秒前", @@ -219,6 +224,7 @@ define([], () => { "NewFolderNamePlaceholder": "フォルダ名を入力してください", "FolderFilterBoxPlaceholder": "フォルダを名前でフィルタする", "FolderExplorerLoading": "フォルダーを読み込んでいます。", - "FolderExplorerNoItems": "このフォルダにはサブフォルダがありません。" + "FolderExplorerNoItems": "このフォルダにはサブフォルダがありません。", + "IncorrectGuidValidationMessage": "有効な GUID を入力してください" }; -}); +}); \ No newline at end of file diff --git a/src/loc/lt-lt.js b/src/loc/lt-lt.js index bc2a8b8a..581f4b89 100644 --- a/src/loc/lt-lt.js +++ b/src/loc/lt-lt.js @@ -79,6 +79,9 @@ define([], () => { "SitePickerSearchBoxPlaceholder": "Paieškos...", "SitePickerNoResults": "Nėra ieškos rezultatų", "SitePickerSitesChosen": "Pasirinkta (-os) interneto svetainė (-ės)", + "TeamPickerSearchBoxPlaceholder": "Paieškos...", + "TeamPickerNoResults": "Nėra ieškos rezultatų", + "TeamPickerSitesChosen": "Atrinktos (-os) komandos (-os)", "AddFileButtonLabel": "Pridėti failą", "AddImageButtonLabel": "Pridėti vaizdą", "AriaCellValue": "{0} stulpelis {1}", @@ -190,6 +193,8 @@ define([], () => { "UploadLinkLabel": "Įkelti", "WebSearchLinkLabel": "Žiniatinklio ieška", "Yes": "taip", + "StockImagesLinkLabel": "Išteklių vaizdai", + "StockImagesHeader": "Ištekliai Vaizdai", "DateTime": { "L_RelativeDateTime_AFewSecondsFuture": "Per kelias sekundes", "L_RelativeDateTime_AFewSeconds": "Prieš kelias sekundes", @@ -219,6 +224,7 @@ define([], () => { "NewFolderNamePlaceholder": "Įveskite aplanko pavadinimą", "FolderFilterBoxPlaceholder": "Filtruokite aplankus pagal pavadinimą", "FolderExplorerLoading": "Įkeliami aplankai...", - "FolderExplorerNoItems": "Šiame aplanke nėra poaplankių." + "FolderExplorerNoItems": "Šiame aplanke nėra poaplankių.", + "IncorrectGuidValidationMessage": "Įveskite tinkamą GUID" }; -}); +}); \ No newline at end of file diff --git a/src/loc/lv-lv.js b/src/loc/lv-lv.js index bf39ac4a..7b190afc 100644 --- a/src/loc/lv-lv.js +++ b/src/loc/lv-lv.js @@ -79,6 +79,9 @@ define([], () => { "SitePickerSearchBoxPlaceholder": "Meklēšanas...", "SitePickerNoResults": "Nav meklēšanas rezultātu", "SitePickerSitesChosen": "Atlasītā(-ās) tīmekļa vietne(-as)", + "TeamPickerSearchBoxPlaceholder": "Meklēšanas...", + "TeamPickerNoResults": "Nav meklēšanas rezultātu", + "TeamPickerSitesChosen": "Atlasītās komandas", "AddFileButtonLabel": "Pievienot failu", "AddImageButtonLabel": "Pievienot attēlu", "AriaCellValue": "{0} kolonna, {1}", @@ -190,6 +193,8 @@ define([], () => { "UploadLinkLabel": "Augšupielādēt", "WebSearchLinkLabel": "Meklēšana tīmeklī", "Yes": "jā", + "StockImagesLinkLabel": "Akciju attēli", + "StockImagesHeader": "Akciju attēli", "DateTime": { "L_RelativeDateTime_AFewSecondsFuture": "Sekundēs", "L_RelativeDateTime_AFewSeconds": "1hour ago", @@ -219,6 +224,7 @@ define([], () => { "NewFolderNamePlaceholder": "Ievadiet mapes nosaukumu", "FolderFilterBoxPlaceholder": "Filtrēt mapes pēc nosaukuma", "FolderExplorerLoading": "Notiek mapju ielāde...", - "FolderExplorerNoItems": "Šai mapei nav apakšmapes." + "FolderExplorerNoItems": "Šai mapei nav apakšmapes.", + "IncorrectGuidValidationMessage": "Lūdzu , ievadiet derīgu GUID" }; -}); +}); \ No newline at end of file diff --git a/src/loc/nb-no.js b/src/loc/nb-no.js index 212addbe..452e3b72 100644 --- a/src/loc/nb-no.js +++ b/src/loc/nb-no.js @@ -79,6 +79,9 @@ define([], () => { "SitePickerSearchBoxPlaceholder": "Søk...", "SitePickerNoResults": "Ingen søkeresultater", "SitePickerSitesChosen": "Nettsted(er) valgt", + "TeamPickerSearchBoxPlaceholder": "Søk...", + "TeamPickerNoResults": "Ingen søkeresultater", + "TeamPickerSitesChosen": "Lag(er) valgt", "AddFileButtonLabel": "Legg til fil", "AddImageButtonLabel": "Legg til bilde", "AriaCellValue": "{0} kolonne, {1}", @@ -190,6 +193,8 @@ define([], () => { "UploadLinkLabel": "Laste opp", "WebSearchLinkLabel": "Nettsøk", "Yes": "ja", + "StockImagesLinkLabel": "Arkivbilder", + "StockImagesHeader": "Arkivbilder", "DateTime": { "L_RelativeDateTime_AFewSecondsFuture": "I løpet av sekunder", "L_RelativeDateTime_AFewSeconds": "For noen sekunder siden", @@ -219,6 +224,7 @@ define([], () => { "NewFolderNamePlaceholder": "Skriv inn mappenavnet ditt", "FolderFilterBoxPlaceholder": "Filtrere mapper etter navn", "FolderExplorerLoading": "Laster inn mapper...", - "FolderExplorerNoItems": "Denne mappen har ingen undermapper." + "FolderExplorerNoItems": "Denne mappen har ingen undermapper.", + "IncorrectGuidValidationMessage": "Angi en gyldig GUID" }; -}); +}); \ No newline at end of file diff --git a/src/loc/nl-nl.js b/src/loc/nl-nl.js index 80c1bb8a..a15932d5 100644 --- a/src/loc/nl-nl.js +++ b/src/loc/nl-nl.js @@ -79,6 +79,9 @@ define([], () => { "SitePickerSearchBoxPlaceholder": "Zoek...", "SitePickerNoResults": "Geen zoekresultaten", "SitePickerSitesChosen": "Website(s) geselecteerd", + "TeamPickerSearchBoxPlaceholder": "Zoek...", + "TeamPickerNoResults": "Geen zoekresultaten", + "TeamPickerSitesChosen": "Teams(en) geselecteerd", "AddFileButtonLabel": "Bestand toevoegen", "AddImageButtonLabel": "Afbeelding toevoegen", "AriaCellValue": "{0} column, {1}", @@ -190,6 +193,8 @@ define([], () => { "UploadLinkLabel": "Uploaden", "WebSearchLinkLabel": "Zoeken op het web", "Yes": "Ja", + "StockImagesLinkLabel": "Stockafbeeldingen", + "StockImagesHeader": "Stockafbeeldingen", "DateTime": { "L_RelativeDateTime_AFewSecondsFuture": "In enkele seconden", "L_RelativeDateTime_AFewSeconds": "Een paar seconden geleden", @@ -219,6 +224,7 @@ define([], () => { "NewFolderNamePlaceholder": "Voer de naam van uw map in", "FolderFilterBoxPlaceholder": "Mappen filteren op naam", "FolderExplorerLoading": "Mappen laden...", - "FolderExplorerNoItems": "Deze map heeft geen submappen." + "FolderExplorerNoItems": "Deze map heeft geen submappen.", + "IncorrectGuidValidationMessage": "Voer een geldige GUID in" }; -}); +}); \ No newline at end of file diff --git a/src/loc/pl-pl.js b/src/loc/pl-pl.js index d721eb82..d4f34057 100644 --- a/src/loc/pl-pl.js +++ b/src/loc/pl-pl.js @@ -79,6 +79,9 @@ define([], () => { "SitePickerSearchBoxPlaceholder": "Szukaj...", "SitePickerNoResults": "Brak wyników wyszukiwania", "SitePickerSitesChosen": "Wybrane strony internetowe", + "TeamPickerSearchBoxPlaceholder": "Szukaj...", + "TeamPickerNoResults": "Brak wyników wyszukiwania", + "TeamPickerSitesChosen": "Wybrane zespoły", "AddFileButtonLabel": "Dodaj plik", "AddImageButtonLabel": "Dodawanie obrazu", "AriaCellValue": "kolumna {0}, {1}", @@ -190,6 +193,8 @@ define([], () => { "UploadLinkLabel": "Przesłać", "WebSearchLinkLabel": "Wyszukiwanie w internecie", "Yes": "Tak", + "StockImagesLinkLabel": "Obrazów", + "StockImagesHeader": "Obrazów", "DateTime": { "L_RelativeDateTime_AFewSecondsFuture": "W kilka sekund", "L_RelativeDateTime_AFewSeconds": "Kilka sekund temu", @@ -219,6 +224,7 @@ define([], () => { "NewFolderNamePlaceholder": "Wprowadź nazwę folderu", "FolderFilterBoxPlaceholder": "Filtrowanie folderów według nazwy", "FolderExplorerLoading": "Trwa ładowanie folderów...", - "FolderExplorerNoItems": "Ten folder nie ma żadnych podfolderów." + "FolderExplorerNoItems": "Ten folder nie ma żadnych podfolderów.", + "IncorrectGuidValidationMessage": "Wprowadź prawidłowy identyfikator GUID" }; -}); +}); \ No newline at end of file diff --git a/src/loc/pt-pt.js b/src/loc/pt-pt.js index 79a4e98f..f7f13543 100644 --- a/src/loc/pt-pt.js +++ b/src/loc/pt-pt.js @@ -79,6 +79,9 @@ define([], () => { "SitePickerSearchBoxPlaceholder": "Procurar...", "SitePickerNoResults": "Sem resultados de pesquisa", "SitePickerSitesChosen": "Website(s) selecionado", + "TeamPickerSearchBoxPlaceholder": "Procurar...", + "TeamPickerNoResults": "Sem resultados de pesquisa", + "TeamPickerSitesChosen": "Equipas selecionadas", "AddFileButtonLabel": "Adicionar ficheiro", "AddImageButtonLabel": "Adicionar imagem", "AriaCellValue": "{0} coluna, {1}", @@ -190,6 +193,8 @@ define([], () => { "UploadLinkLabel": "Upload", "WebSearchLinkLabel": "Pesquisa na Web", "Yes": "Sim, é o seu", + "StockImagesLinkLabel": "Imagens de stock", + "StockImagesHeader": "Imagens de Stock", "DateTime": { "L_RelativeDateTime_AFewSecondsFuture": "Em segundos", "L_RelativeDateTime_AFewSeconds": "Há alguns segundos.", @@ -219,6 +224,7 @@ define([], () => { "NewFolderNamePlaceholder": "Insira o nome da sua pasta", "FolderFilterBoxPlaceholder": "Pastas de filtro pelo nome", "FolderExplorerLoading": "Pastas de carregamento...", - "FolderExplorerNoItems": "Esta pasta não tem sub-dobradores." + "FolderExplorerNoItems": "Esta pasta não tem sub-dobradores.", + "IncorrectGuidValidationMessage": "Introduza um GUID válido" }; -}); +}); \ No newline at end of file diff --git a/src/loc/ro-ro.js b/src/loc/ro-ro.js index 5252d59c..1708da04 100644 --- a/src/loc/ro-ro.js +++ b/src/loc/ro-ro.js @@ -79,6 +79,9 @@ define([], () => { "SitePickerSearchBoxPlaceholder": "Căutaţi...", "SitePickerNoResults": "Fără rezultate ale căutării", "SitePickerSitesChosen": "Site-uri web selectate", + "TeamPickerSearchBoxPlaceholder": "Căutaţi...", + "TeamPickerNoResults": "Fără rezultate ale căutării", + "TeamPickerSitesChosen": "Echipe selectate", "AddFileButtonLabel": "Adăugare fișier", "AddImageButtonLabel": "Adăugare imagine", "AriaCellValue": "coloana {0}, {1}", @@ -190,6 +193,8 @@ define([], () => { "UploadLinkLabel": "Încărcaţi", "WebSearchLinkLabel": "Căutare pe Web", "Yes": "da", + "StockImagesLinkLabel": "Imagini de stoc", + "StockImagesHeader": "Imagini stoc", "DateTime": { "L_RelativeDateTime_AFewSecondsFuture": "În câteva secunde", "L_RelativeDateTime_AFewSeconds": "Acum câteva secunde.", @@ -219,6 +224,7 @@ define([], () => { "NewFolderNamePlaceholder": "Introduceți numele folderului", "FolderFilterBoxPlaceholder": "Filtrarea folderelor după nume", "FolderExplorerLoading": "Se încarcă folderele...", - "FolderExplorerNoItems": "Acest folder nu are subfoldere." + "FolderExplorerNoItems": "Acest folder nu are subfoldere.", + "IncorrectGuidValidationMessage": "Introduceți un GUID valid" }; -}); +}); \ No newline at end of file diff --git a/src/loc/ru-ru.js b/src/loc/ru-ru.js index 151b0b45..c4ca3ec6 100644 --- a/src/loc/ru-ru.js +++ b/src/loc/ru-ru.js @@ -79,6 +79,9 @@ define([], () => { "SitePickerSearchBoxPlaceholder": "Поиск...", "SitePickerNoResults": "Нет результатов поиска", "SitePickerSitesChosen": "Выбранный веб-сайт (ы)", + "TeamPickerSearchBoxPlaceholder": "Поиск...", + "TeamPickerNoResults": "Нет результатов поиска", + "TeamPickerSitesChosen": "Выбранные команды (ы)", "AddFileButtonLabel": "Добавить файл", "AddImageButtonLabel": "Добавить изображение", "AriaCellValue": "{0} колонка, {1}", @@ -190,6 +193,8 @@ define([], () => { "UploadLinkLabel": "Загрузить", "WebSearchLinkLabel": "Веб-поиск", "Yes": "Да", + "StockImagesLinkLabel": "Сток изображения", + "StockImagesHeader": "Сток изображения", "DateTime": { "L_RelativeDateTime_AFewSecondsFuture": "В считанные секунды", "L_RelativeDateTime_AFewSeconds": "Несколько секунд назад", @@ -219,6 +224,7 @@ define([], () => { "NewFolderNamePlaceholder": "Введите имя папки", "FolderFilterBoxPlaceholder": "Фильтр папки по имени", "FolderExplorerLoading": "Загрузка папок...", - "FolderExplorerNoItems": "Эта папка не имеет субфолдеров." + "FolderExplorerNoItems": "Эта папка не имеет субфолдеров.", + "IncorrectGuidValidationMessage": "Пожалуйста, введите действительный GUID" }; -}); +}); \ No newline at end of file diff --git a/src/loc/sk-sk.js b/src/loc/sk-sk.js index 11258419..52c4f4c5 100644 --- a/src/loc/sk-sk.js +++ b/src/loc/sk-sk.js @@ -79,6 +79,9 @@ define([], () => { "SitePickerSearchBoxPlaceholder": "Hľadať...", "SitePickerNoResults": "Žiadne výsledky vyhľadávania", "SitePickerSitesChosen": "Vybraná webová stránka (webové stránky)", + "TeamPickerSearchBoxPlaceholder": "Hľadať...", + "TeamPickerNoResults": "Žiadne výsledky vyhľadávania", + "TeamPickerSitesChosen": "Vybrané tímy", "AddFileButtonLabel": "Pridať súbor", "AddImageButtonLabel": "Pridať obrázok", "AriaCellValue": "{0} stĺpec, {1}", @@ -190,6 +193,8 @@ define([], () => { "UploadLinkLabel": "Nahrať", "WebSearchLinkLabel": "Vyhľadávanie na webe", "Yes": "áno", + "StockImagesLinkLabel": "Obrázky akcií", + "StockImagesHeader": "Sklad Obrázky", "DateTime": { "L_RelativeDateTime_AFewSecondsFuture": "V priebehu niekoľkých sekúnd", "L_RelativeDateTime_AFewSeconds": "Pred niekoľkými sekundami", @@ -219,6 +224,7 @@ define([], () => { "NewFolderNamePlaceholder": "Zadajte názov priečinka", "FolderFilterBoxPlaceholder": "Filtrovanie priečinkov podľa názvu", "FolderExplorerLoading": "Načítavajú sa priečinky...", - "FolderExplorerNoItems": "Tento priečinok nemá žiadne podpriečinky." + "FolderExplorerNoItems": "Tento priečinok nemá žiadne podpriečinky.", + "IncorrectGuidValidationMessage": "Zadajte platný identifikátor GUID" }; -}); +}); \ No newline at end of file diff --git a/src/loc/sr-latn-rs.js b/src/loc/sr-latn-rs.js index b37f3aa8..82bbbf56 100644 --- a/src/loc/sr-latn-rs.js +++ b/src/loc/sr-latn-rs.js @@ -79,6 +79,9 @@ define([], () => { "SitePickerSearchBoxPlaceholder": "Pretrage...", "SitePickerNoResults": "Nema rezultata pretrage", "SitePickerSitesChosen": "Web lokacije izabrane", + "TeamPickerSearchBoxPlaceholder": "Pretrage...", + "TeamPickerNoResults": "Nema rezultata pretrage", + "TeamPickerSitesChosen": "Odabrani timovi", "AddFileButtonLabel": "Dodaj datoteku", "AddImageButtonLabel": "Dodaj sliku", "AriaCellValue": "{0}, {1}", @@ -190,6 +193,8 @@ define([], () => { "UploadLinkLabel": "Otpremanje", "WebSearchLinkLabel": "Web pretraga", "Yes": "Da", + "StockImagesLinkLabel": "Berzanske slike", + "StockImagesHeader": "Slike akcija", "DateTime": { "L_RelativeDateTime_AFewSecondsFuture": "Za nekoliko sekundi", "L_RelativeDateTime_AFewSeconds": "Pre par sekundi", @@ -219,6 +224,7 @@ define([], () => { "NewFolderNamePlaceholder": "Unesite ime fascikle", "FolderFilterBoxPlaceholder": "Filtriranje fascikli po imenu", "FolderExplorerLoading": "Učitavanje fascikli...", - "FolderExplorerNoItems": "Ova fascikla nema potfascikle." + "FolderExplorerNoItems": "Ova fascikla nema potfascikle.", + "IncorrectGuidValidationMessage": "Unesite važeći GUID" }; -}); +}); \ No newline at end of file diff --git a/src/loc/sv-se.js b/src/loc/sv-se.js index 411f6d31..4f0cb407 100644 --- a/src/loc/sv-se.js +++ b/src/loc/sv-se.js @@ -79,6 +79,9 @@ define([], () => { "SitePickerSearchBoxPlaceholder": "Sök...", "SitePickerNoResults": "Inga sökresultat", "SitePickerSitesChosen": "Webbplats(er) vald", + "TeamPickerSearchBoxPlaceholder": "Sök...", + "TeamPickerNoResults": "Inga sökresultat", + "TeamPickerSitesChosen": "Lag(er) utvalda", "AddFileButtonLabel": "Lägg till fil", "AddImageButtonLabel": "Lägg till bild", "AriaCellValue": "{0}, {1}", @@ -190,6 +193,8 @@ define([], () => { "UploadLinkLabel": "Uppladdning", "WebSearchLinkLabel": "Webbsökning", "Yes": "Ja", + "StockImagesLinkLabel": "Arkivbilder", + "StockImagesHeader": "Lager Bilder", "DateTime": { "L_RelativeDateTime_AFewSecondsFuture": "På några sekunder", "L_RelativeDateTime_AFewSeconds": "För några sekunder sedan", @@ -219,6 +224,7 @@ define([], () => { "NewFolderNamePlaceholder": "Ange ditt mappnamn", "FolderFilterBoxPlaceholder": "Filtrera mappar efter namn", "FolderExplorerLoading": "Läser in mappar...", - "FolderExplorerNoItems": "Den här mappen har inga undermappar." + "FolderExplorerNoItems": "Den här mappen har inga undermappar.", + "IncorrectGuidValidationMessage": "Ange ett giltigt GUID" }; -}); +}); \ No newline at end of file diff --git a/src/loc/tr-tr.js b/src/loc/tr-tr.js index 96707d88..27a4a36c 100644 --- a/src/loc/tr-tr.js +++ b/src/loc/tr-tr.js @@ -79,6 +79,9 @@ define([], () => { "SitePickerSearchBoxPlaceholder": "Arama...", "SitePickerNoResults": "Arama sonucu yok", "SitePickerSitesChosen": "Web sitesi(ler) seçildi", + "TeamPickerSearchBoxPlaceholder": "Arama...", + "TeamPickerNoResults": "Arama sonucu yok", + "TeamPickerSitesChosen": "Takımlar(lar) seçildi", "AddFileButtonLabel": "Dosya ekleme", "AddImageButtonLabel": "Resim ekleme", "AriaCellValue": "{0} sütun, {1}", @@ -190,6 +193,8 @@ define([], () => { "UploadLinkLabel": "Yüklemek", "WebSearchLinkLabel": "Web arama", "Yes": "Evet", + "StockImagesLinkLabel": "Stok görüntüleri", + "StockImagesHeader": "Stok Görselleri", "DateTime": { "L_RelativeDateTime_AFewSecondsFuture": "Saniyeler içinde", "L_RelativeDateTime_AFewSeconds": "Birkaç saniye önce", @@ -219,6 +224,7 @@ define([], () => { "NewFolderNamePlaceholder": "Klasör adınızı girin", "FolderFilterBoxPlaceholder": "Klasörleri ada göre filtreleme", "FolderExplorerLoading": "Klasörleri yükleme...", - "FolderExplorerNoItems": "Bu klasörde alt klasör yok." + "FolderExplorerNoItems": "Bu klasörde alt klasör yok.", + "IncorrectGuidValidationMessage": "Lütfen geçerli bir GUID girin" }; -}); +}); \ No newline at end of file diff --git a/src/loc/vi-vn.js b/src/loc/vi-vn.js index 44db4163..4c0ff2bb 100644 --- a/src/loc/vi-vn.js +++ b/src/loc/vi-vn.js @@ -79,6 +79,9 @@ define([], () => { "SitePickerSearchBoxPlaceholder": "Tìm...", "SitePickerNoResults": "Không có kết quả tìm kiếm", "SitePickerSitesChosen": "(Các) trang web được chọn", + "TeamPickerSearchBoxPlaceholder": "Tìm...", + "TeamPickerNoResults": "Không có kết quả tìm kiếm", + "TeamPickerSitesChosen": "(Các) đội được chọn", "AddFileButtonLabel": "Thêm tệp", "AddImageButtonLabel": "Thêm ảnh", "AriaCellValue": "{0}, {1}", @@ -190,6 +193,8 @@ define([], () => { "UploadLinkLabel": "Tải lên", "WebSearchLinkLabel": "Tìm kiếm trên web", "Yes": "Có", + "StockImagesLinkLabel": "Hình ảnh chứng khoán", + "StockImagesHeader": "Hình ảnh chứng khoán", "DateTime": { "L_RelativeDateTime_AFewSecondsFuture": "Chỉ trong vài giây", "L_RelativeDateTime_AFewSeconds": "Một vài giây trước", @@ -219,6 +224,7 @@ define([], () => { "NewFolderNamePlaceholder": "Nhập tên thư mục của bạn", "FolderFilterBoxPlaceholder": "Lọc thư mục theo tên", "FolderExplorerLoading": "Đang nạp cặp...", - "FolderExplorerNoItems": "Cặp này không có bất kỳ cặp con nào." + "FolderExplorerNoItems": "Cặp này không có bất kỳ cặp con nào.", + "IncorrectGuidValidationMessage": "Vui lòng nhập GUID hợp lệ" }; -}); +}); \ No newline at end of file diff --git a/src/loc/zh-cn.js b/src/loc/zh-cn.js index bbfcd223..db6c29a6 100644 --- a/src/loc/zh-cn.js +++ b/src/loc/zh-cn.js @@ -79,6 +79,9 @@ define([], () => { "SitePickerSearchBoxPlaceholder": "搜索。。。", "SitePickerNoResults": "无搜索结果", "SitePickerSitesChosen": "已选择网站", + "TeamPickerSearchBoxPlaceholder": "搜索。。。", + "TeamPickerNoResults": "无搜索结果", + "TeamPickerSitesChosen": "所选团队", "AddFileButtonLabel": "添加文件", "AddImageButtonLabel": "添加图像", "AriaCellValue": "{0}列, {1}", @@ -190,6 +193,8 @@ define([], () => { "UploadLinkLabel": "上传", "WebSearchLinkLabel": "网络搜索", "Yes": "是的", + "StockImagesLinkLabel": "库存图像", + "StockImagesHeader": "库存图片", "DateTime": { "L_RelativeDateTime_AFewSecondsFuture": "在几秒钟内", "L_RelativeDateTime_AFewSeconds": "几秒钟前", @@ -219,6 +224,7 @@ define([], () => { "NewFolderNamePlaceholder": "输入文件夹名称", "FolderFilterBoxPlaceholder": "按名称筛选文件夹", "FolderExplorerLoading": "正在加载文件夹...", - "FolderExplorerNoItems": "此文件夹没有任何子文件夹。" + "FolderExplorerNoItems": "此文件夹没有任何子文件夹。", + "IncorrectGuidValidationMessage": "请输入有效的 GUID" }; -}); +}); \ No newline at end of file diff --git a/src/loc/zh-tw.js b/src/loc/zh-tw.js index 0f61849d..2c2c53ae 100644 --- a/src/loc/zh-tw.js +++ b/src/loc/zh-tw.js @@ -79,6 +79,9 @@ define([], () => { "SitePickerSearchBoxPlaceholder": "搜索。。。", "SitePickerNoResults": "無搜尋結果。", "SitePickerSitesChosen": "已選擇網站。", + "TeamPickerSearchBoxPlaceholder": "搜索。。。", + "TeamPickerNoResults": "無搜尋結果", + "TeamPickerSitesChosen": "所選團隊", "AddFileButtonLabel": "添加檔。", "AddImageButtonLabel": "添加圖像。", "AriaCellValue": "{0}列, {1}", @@ -190,6 +193,8 @@ define([], () => { "UploadLinkLabel": "上傳。", "WebSearchLinkLabel": "網路搜索。", "Yes": "是的。", + "StockImagesLinkLabel": "庫存圖像", + "StockImagesHeader": "庫存圖片", "DateTime": { "L_RelativeDateTime_AFewSecondsFuture": "在幾秒鐘內。", "L_RelativeDateTime_AFewSeconds": "幾秒鐘前。", @@ -219,6 +224,7 @@ define([], () => { "NewFolderNamePlaceholder": "輸入資料夾名稱。", "FolderFilterBoxPlaceholder": "按名稱篩選資料夾。", "FolderExplorerLoading": "載入資料夾中...", - "FolderExplorerNoItems": "此文件無子資料夾。" + "FolderExplorerNoItems": "此文件無子資料夾。", + "IncorrectGuidValidationMessage": "請輸入有效的 GUID" }; -}); +}); \ No newline at end of file From 3bbbbc3048ac2db8cd187e7d7cfe41a692f5bf8b Mon Sep 17 00:00:00 2001 From: Alex Terentiev Date: Wed, 28 Oct 2020 18:48:44 -0700 Subject: [PATCH 6/8] documentation for the control, renaming site to team across the control, changing ms graph requests to include batching and v1.0 instead of beta --- config/package-solution.json | 10 +- .../docs/assets/teampicker-selected.png | Bin 0 -> 47723 bytes docs/documentation/docs/assets/teampicker.png | Bin 0 -> 27072 bytes .../docs/controls/PropertyFieldSitePicker.md | 6 +- .../docs/controls/PropertyFieldTeamPicker.md | 88 ++++++++++++++++++ docs/documentation/docs/index.md | 1 + docs/documentation/mkdocs.yml | 1 + src/helpers/GraphHelper.ts | 51 ++++++++++ .../teamPicker/IPropertyFieldTeamPicker.ts | 10 +- .../IPropertyFieldTeamPickerHost.ts | 6 +- .../teamPicker/PropertyFieldTeamPicker.ts | 18 ++-- .../PropertyFieldTeamPickerHost.tsx | 58 ++++++------ ...ts => IPropertyFieldTeamPickerListItem.ts} | 6 +- ...sx => PropertyFieldTeamPickerListItem.tsx} | 12 +-- src/services/TeamsSearchService.ts | 68 ++++++-------- .../IPropertyControlsTestWebPartProps.ts | 2 + .../PropertyControlsTestWebPart.ts | 16 +++- 17 files changed, 253 insertions(+), 100 deletions(-) create mode 100644 docs/documentation/docs/assets/teampicker-selected.png create mode 100644 docs/documentation/docs/assets/teampicker.png create mode 100644 docs/documentation/docs/controls/PropertyFieldTeamPicker.md create mode 100644 src/helpers/GraphHelper.ts rename src/propertyFields/teamPicker/PropertyFieldTeamPickerListItem/{IPropertyFieldSitePickerListItem.ts => IPropertyFieldTeamPickerListItem.ts} (62%) rename src/propertyFields/teamPicker/PropertyFieldTeamPickerListItem/{PropertyFieldSitePickerListItem.tsx => PropertyFieldTeamPickerListItem.tsx} (74%) diff --git a/config/package-solution.json b/config/package-solution.json index d23f0619..c2316025 100644 --- a/config/package-solution.json +++ b/config/package-solution.json @@ -6,7 +6,15 @@ "version": "1.0.0.0", "skipFeatureDeployment": true, "isDomainIsolated": false, - "includeClientSideAssets": true + "includeClientSideAssets": true, + "webApiPermissionRequests": [ + { + "resource": "Microsoft Graph", + "scope": "Team.ReadBasic.All" + }, { + "resource": "Microsoft Graph", + "scope": "Files.Read" + }] }, "paths": { "zippedPackage": "solution/sp-dev-fx-property-controls.sppkg" diff --git a/docs/documentation/docs/assets/teampicker-selected.png b/docs/documentation/docs/assets/teampicker-selected.png new file mode 100644 index 0000000000000000000000000000000000000000..77c873cd1b126681b39eeddea56db7f33e134d53 GIT binary patch literal 47723 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 literal 0 HcmV?d00001 diff --git a/docs/documentation/docs/assets/teampicker.png b/docs/documentation/docs/assets/teampicker.png new file mode 100644 index 0000000000000000000000000000000000000000..a6c3e0b291148f68c0ee64da5bda7a1d0c7c908a GIT binary patch literal 27072 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 TnCA}o**OInRp~;>hkpMCn}coK literal 0 HcmV?d00001 diff --git a/docs/documentation/docs/controls/PropertyFieldSitePicker.md b/docs/documentation/docs/controls/PropertyFieldSitePicker.md index e1b038a6..67a94534 100644 --- a/docs/documentation/docs/controls/PropertyFieldSitePicker.md +++ b/docs/documentation/docs/controls/PropertyFieldSitePicker.md @@ -53,9 +53,9 @@ The `PropertyFieldSitePicker` control can be configured with the following prope | label | string | yes | Property field label displayed on top. | | disabled | boolean | no | Specify if the control needs to be disabled. | | context | WebPartContext | yes | Context of the current web part. | -| initialSites | IPropertyFieldGroupOrPerson[] | no | Intial sites to load in the site picker (optional). | -| multiSelect | boolean | no | Define if you want to allow multi sites selection. (optional, false by default). | -| onPropertyChange | function | yes | Defines a onPropertyChange function to raise when the sites get changed. | +| initialSites | IPropertyFieldSite[] | no | Intial sites to load in the site picker (optional). | +| multiSelect | boolean | no | Define if you want to allow multiple sites selection. (optional, false by default). | +| onPropertyChange | function | yes | Defines a `onPropertyChange` function to raise when the sites get changed. | | properties | any | yes | Parent web part properties, this object is use to update the property value. | | key | string | yes | An unique key that indicates the identity of this control. | | onGetErrorMessage | function | no | The method is used to get the validation error message and determine whether the input value is valid or not. See [this documentation](https://dev.office.com/sharepoint/docs/spfx/web-parts/guidance/validate-web-part-property-values) to learn how to use it. | diff --git a/docs/documentation/docs/controls/PropertyFieldTeamPicker.md b/docs/documentation/docs/controls/PropertyFieldTeamPicker.md new file mode 100644 index 00000000..848cad71 --- /dev/null +++ b/docs/documentation/docs/controls/PropertyFieldTeamPicker.md @@ -0,0 +1,88 @@ +# PropertyFieldTeamPicker control +This control generates a team picker that can be used in the property pane of your SharePoint Framework web parts. + +**Searching for teams** + +![Site picker](../assets/teampicker.png) + +**Selected teams** + +![Site picker](../assets/teampicker-selected.png) + +## How to use this control in your solutions + +1. Check that you installed the `@pnp/spfx-property-controls` dependency. Check out The [getting started](../../#getting-started) page for more information about installing the dependency. +2. Request Microsoft Graph permissions in `config/package-solution.json`: +```json +{ + "solution": { + "webApiPermissionRequests": [ + { + "resource": "Microsoft Graph", + "scope": "Team.ReadBasic.All" + }, { + "resource": "Microsoft Graph", + "scope": "Files.Read" + }] + } +} +``` +!!! Note + `Team.ReadBasic.All` and `Files.Read` is a minimum set of permissions needed for the component. For other options please see [List Joined Teams](https://docs.microsoft.com/en-us/graph/api/user-list-joinedteams?view=graph-rest-1.0&tabs=http) and [Get Drive](https://docs.microsoft.com/en-us/graph/api/drive-get?view=graph-rest-1.0&tabs=http) documentation. + +3. Import the following modules to your component: + +```TypeScript +import { PropertyFieldSitePicker } from '@pnp/spfx-property-controls/lib/PropertyFieldSitePicker'; +``` + +4. Create a new property for your web part, for example: + +```TypeScript +import { IPropertyFieldTeam } from '../../PropertyFieldTeamPicker'; + +export interface IPropertyControlsTestWebPartProps { + teams: IPropertyFieldTeam[]; +} +``` + +5. Add the custom property control to the `groupFields` of the web part property pane configuration: + +```TypeScript +PropertyFieldTeamPicker('teams', { + key: 'teamsPicker', + context: this.context, + label: 'Select teams', + onPropertyChange: this.onPropertyPaneFieldChanged, + properties: this.properties, + initialTeams: this.properties.teams, + multiSelect: true +}) +``` + +## Implementation + +The `PropertyFieldTeamPicker` control can be configured with the following properties: + +| Property | Type | Required | Description | +| ---- | ---- | ---- | ---- | +| label | string | yes | Property field label displayed on top. | +| disabled | boolean | no | Specify if the control needs to be disabled. | +| context | WebPartContext | yes | Context of the current web part. | +| initialTeams | IPropertyFieldTeam[] | no | Initial teams to load in the site picker (optional). | +| multiSelect | boolean | no | Define if you want to allow multiple teams selection. (optional, false by default). | +| onPropertyChange | function | yes | Defines a `onPropertyChange` function to raise when the teams get changed. | +| properties | any | yes | Parent web part properties, this object is used to update the property value. | +| key | string | yes | An unique key that indicates the identity of this control. | +| onGetErrorMessage | function | no | The method is used to get the validation error message and determine whether the input value is valid or not. See [this documentation](https://dev.office.com/sharepoint/docs/spfx/web-parts/guidance/validate-web-part-property-values) to learn how to use it. | +| deferredValidationTime | number | no | Control will start to validate after users stop typing for `deferredValidationTime` milliseconds. Default value is 200. | + +Interface `IPropertyFieldTeam` + +| Property | Type | Required | Description | +| ---- | ---- | ---- | ---- | +| id | string | no | The ID of the team (group) | +| title | string | no | Teams's display name | +| url | string | no | URL to the underlying site | + +![](https://telemetry.sharepointpnp.com/sp-dev-fx-property-controls/wiki/PropertyFieldTeamPicker) diff --git a/docs/documentation/docs/index.md b/docs/documentation/docs/index.md index 035b564f..c2088ac8 100644 --- a/docs/documentation/docs/index.md +++ b/docs/documentation/docs/index.md @@ -70,6 +70,7 @@ The following controls are currently available: - [PropertyFieldSpinButton](./controls/PropertyFieldSpinButton) (Property pane spin button) - [PropertyFieldSpinner](./controls/PropertyFieldSpinButton) (Property pane spinner) - [PropertyFieldSwatchColorPicker](./controls/PropertyFieldSwatchColorPicker) (Property pane color selector) +- [PropertyFieldTeamPicker](./controls/PropertyFieldTeamPicker) (Property pane team selector) - [PropertyFieldTermPicker](./controls/PropertyFieldTermPicker) (Property pane managed metadata term selector) - [PropertyFieldEnterpriseTermPicker](./controls/PropertyFieldEnterpriseTermPicker) (Property pane managed metadata term selector for enterprise scenarios) - [PropertyFieldViewPicker](./controls/PropertyFIeldViewPicker) (Property pane view selector) diff --git a/docs/documentation/mkdocs.yml b/docs/documentation/mkdocs.yml index 758be16b..044da620 100644 --- a/docs/documentation/mkdocs.yml +++ b/docs/documentation/mkdocs.yml @@ -23,6 +23,7 @@ nav: - PropertyFieldSpinButton: 'controls/PropertyFieldSpinButton.md' - PropertyFieldSpinner: 'controls/PropertyFieldSpinner.md' - PropertyFieldSwatchColorPicker: 'controls/PropertyFieldSwatchColorPicker.md' + - PropertyFieldTeamPicker: 'controls/PropertyFieldTeamPicker.md' - PropertyFieldTermPicker: 'controls/PropertyFieldTermPicker.md' - PropertyFieldViewPicker: 'controls/PropertyFieldViewPicker.md' - PropertyPaneMarkdownContent: 'controls/PropertyPaneMarkdownContent.md' diff --git a/src/helpers/GraphHelper.ts b/src/helpers/GraphHelper.ts new file mode 100644 index 00000000..672f3066 --- /dev/null +++ b/src/helpers/GraphHelper.ts @@ -0,0 +1,51 @@ +import { MSGraphClient } from '@microsoft/sp-http'; +import { WebPartContext } from '@microsoft/sp-webpart-base'; + +export interface IGraphBatchRequestItem { + id: string; + method: 'GET' | 'POST'; + url: string; + dependsOn?: string[]; + body?: {[key: string]: string}; +} + +export interface IGraphBatchResponseItem { + id: string; + status: number; + body: any; +} + +const RequestsPerBatch = 10; + +export async function batch(batchRequestItems: IGraphBatchRequestItem[], version: string, context: WebPartContext): Promise { + const requestsCount = batchRequestItems.length; + const batchesCount = Math.ceil(requestsCount / RequestsPerBatch); + let batchIndex = 0; + + const result: IGraphBatchResponseItem[] = []; + + const client = await getGraphClient(context); + + while (batchIndex < batchesCount) { + let start = batchIndex * RequestsPerBatch; + let end = start + RequestsPerBatch; + if (end > requestsCount) { + end = requestsCount; + } + + const response = await client.api('/$batch').version(version).post({ + requests: batchRequestItems.slice(start, end) + }); + + result.push(...response.responses); + batchIndex++; + } + + return result; +} + +export async function getGraphClient(context: WebPartContext): Promise { + const client = await context.msGraphClientFactory.getClient(); + + return client; +} diff --git a/src/propertyFields/teamPicker/IPropertyFieldTeamPicker.ts b/src/propertyFields/teamPicker/IPropertyFieldTeamPicker.ts index 8f6cc71f..3d4269e0 100644 --- a/src/propertyFields/teamPicker/IPropertyFieldTeamPicker.ts +++ b/src/propertyFields/teamPicker/IPropertyFieldTeamPicker.ts @@ -1,4 +1,4 @@ -import { IWebPartContext } from '@microsoft/sp-webpart-base'; +import { WebPartContext } from '@microsoft/sp-webpart-base'; export interface IPropertyFieldTeam { /** @@ -31,11 +31,11 @@ export interface IPropertyFieldTeamPickerProps { /** * Web Part context */ - context: IWebPartContext; + context: WebPartContext; /** - * Intial data to load in the 'Selected sites' area (optional) + * Intial data to load in the 'Selected teams' area (optional) */ - initialSites: IPropertyFieldTeam[]; + initialTeams?: IPropertyFieldTeam[]; /** * Define if you want to allow multi site selection. True by default. */ @@ -81,4 +81,4 @@ export interface IPropertyFieldTeamPickerPropsInternal extends IPropertyFieldTea targetProperty: string; onRender(elem: HTMLElement): void; onDispose(elem: HTMLElement): void; -} \ No newline at end of file +} diff --git a/src/propertyFields/teamPicker/IPropertyFieldTeamPickerHost.ts b/src/propertyFields/teamPicker/IPropertyFieldTeamPickerHost.ts index d94f86e7..18ac2c9c 100644 --- a/src/propertyFields/teamPicker/IPropertyFieldTeamPickerHost.ts +++ b/src/propertyFields/teamPicker/IPropertyFieldTeamPickerHost.ts @@ -8,8 +8,8 @@ export interface IPropertyFieldTeamPickerHostProps extends IPropertyFieldTeamPic } export interface ITeamPickerState { - siteSearchResults?: Array; - selectedSites?: Array; + teamSearchResults?: Array; + selectedTeams?: Array; isLoading: boolean; errorMessage?: string; -} \ No newline at end of file +} diff --git a/src/propertyFields/teamPicker/PropertyFieldTeamPicker.ts b/src/propertyFields/teamPicker/PropertyFieldTeamPicker.ts index 9a778032..fd5a2820 100644 --- a/src/propertyFields/teamPicker/PropertyFieldTeamPicker.ts +++ b/src/propertyFields/teamPicker/PropertyFieldTeamPicker.ts @@ -1,10 +1,12 @@ import * as React from 'react'; import * as ReactDom from 'react-dom'; import { - IPropertyPaneField, - PropertyPaneFieldType, - IWebPartContext + WebPartContext } from '@microsoft/sp-webpart-base'; +import { + IPropertyPaneField, + PropertyPaneFieldType +} from '@microsoft/sp-property-pane'; import { IPropertyFieldTeamPickerPropsInternal, IPropertyFieldTeam, IPropertyFieldTeamPickerProps } from './IPropertyFieldTeamPicker'; import { IPropertyFieldTeamPickerHostProps } from './IPropertyFieldTeamPickerHost'; import PropertyFieldTeamPickerHost from './PropertyFieldTeamPickerHost'; @@ -23,8 +25,8 @@ class PropertyFieldTeamPickerBuilder implements IPropertyPaneField void; private customProperties: any; @@ -44,7 +46,7 @@ class PropertyFieldTeamPickerBuilder implements IPropertyPaneField { private teamsService: TeamsSearchService; @@ -38,8 +38,8 @@ export default class PropertyFieldTeamPickerHost extends React.Component 2) { this.setState({ isLoading: true }); try { - const sites = await this.teamsService.searchTeams(this.props.context, newValue); - this.setState({ siteSearchResults: sites }); + const teams = await this.teamsService.searchTeams(this.props.context, newValue); + this.setState({ teamSearchResults: teams }); } catch (error) { this.setState({ errorMessage: error.message }); } finally { this.setState({ isLoading: false }); } } else { - this.setState({ siteSearchResults: [] }); + this.setState({ teamSearchResults: [] }); } } - private handleCheckboxChange = (site: IPropertyFieldTeam, checked: boolean): void => { - let selectedSites = [...this.state.selectedSites]; + private handleCheckboxChange = (team: IPropertyFieldTeam, checked: boolean): void => { + let selectedTeams = [...this.state.selectedTeams]; if (checked) { if (this.props.multiSelect) { - selectedSites.push(site); + selectedTeams.push(team); } else { - selectedSites = [site]; + selectedTeams = [team]; } } else { if (this.props.multiSelect) { - selectedSites.splice(selectedSites.indexOf(site), 1); + selectedTeams.splice(selectedTeams.indexOf(team), 1); } else { - selectedSites = []; + selectedTeams = []; } } - this.props.onPropertyChange(this.props.targetProperty, this.state.selectedSites, selectedSites); + this.props.onPropertyChange(this.props.targetProperty, this.state.selectedTeams, selectedTeams); // Trigger the apply button if (typeof this.props.onChange !== 'undefined' && this.props.onChange !== null) { - this.props.onChange(this.props.targetProperty, selectedSites); + this.props.onChange(this.props.targetProperty, selectedTeams); } - this.setState({ selectedSites }); + this.setState({ selectedTeams }); } public render(): JSX.Element { - const { isLoading, siteSearchResults, selectedSites } = this.state; + const { isLoading, teamSearchResults, selectedTeams } = this.state; return (
    @@ -104,41 +104,41 @@ export default class PropertyFieldTeamPickerHost extends React.Component } { - !isLoading && siteSearchResults && + !isLoading && teamSearchResults &&
    { - siteSearchResults.length > 0 && + teamSearchResults.length > 0 &&
      { - siteSearchResults.map((site: IPropertyFieldTeam): JSX.Element => + teamSearchResults.map((team: IPropertyFieldTeam): JSX.Element => s.id === site.id).length > 0} + key={team.id} + checked={selectedTeams.filter(s => s.id === team.id).length > 0} handleCheckboxChange={this.handleCheckboxChange} - site={site} + team={team} /> ) }
    } { - siteSearchResults.length === 0 && + teamSearchResults.length === 0 && }
    } { - selectedSites && selectedSites.length > 0 && + selectedTeams && selectedTeams.length > 0 &&
    - +
      { - selectedSites.map((site: IPropertyFieldTeam): JSX.Element => + selectedTeams.map((team: IPropertyFieldTeam): JSX.Element => s.id === site.id).length > 0} + key={team.id} + checked={selectedTeams.filter(s => s.id === team.id).length > 0} handleCheckboxChange={this.handleCheckboxChange} - site={site} + team={team} /> ) } diff --git a/src/propertyFields/teamPicker/PropertyFieldTeamPickerListItem/IPropertyFieldSitePickerListItem.ts b/src/propertyFields/teamPicker/PropertyFieldTeamPickerListItem/IPropertyFieldTeamPickerListItem.ts similarity index 62% rename from src/propertyFields/teamPicker/PropertyFieldTeamPickerListItem/IPropertyFieldSitePickerListItem.ts rename to src/propertyFields/teamPicker/PropertyFieldTeamPickerListItem/IPropertyFieldTeamPickerListItem.ts index 69e3e4ab..a891e259 100644 --- a/src/propertyFields/teamPicker/PropertyFieldTeamPickerListItem/IPropertyFieldSitePickerListItem.ts +++ b/src/propertyFields/teamPicker/PropertyFieldTeamPickerListItem/IPropertyFieldTeamPickerListItem.ts @@ -1,7 +1,7 @@ import { IPropertyFieldTeam } from '../IPropertyFieldTeamPicker'; export interface IPropertyFieldTeamPickerListItemProps { - site: IPropertyFieldTeam; + team: IPropertyFieldTeam; checked: boolean; - handleCheckboxChange(site: IPropertyFieldTeam, checked: boolean): void; -} \ No newline at end of file + handleCheckboxChange(team: IPropertyFieldTeam, checked: boolean): void; +} diff --git a/src/propertyFields/teamPicker/PropertyFieldTeamPickerListItem/PropertyFieldSitePickerListItem.tsx b/src/propertyFields/teamPicker/PropertyFieldTeamPickerListItem/PropertyFieldTeamPickerListItem.tsx similarity index 74% rename from src/propertyFields/teamPicker/PropertyFieldTeamPickerListItem/PropertyFieldSitePickerListItem.tsx rename to src/propertyFields/teamPicker/PropertyFieldTeamPickerListItem/PropertyFieldTeamPickerListItem.tsx index 00e2ddd5..8455ba03 100644 --- a/src/propertyFields/teamPicker/PropertyFieldTeamPickerListItem/PropertyFieldSitePickerListItem.tsx +++ b/src/propertyFields/teamPicker/PropertyFieldTeamPickerListItem/PropertyFieldTeamPickerListItem.tsx @@ -1,19 +1,19 @@ import * as React from 'react'; -import { IPropertyFieldTeamPickerListItemProps } from './IPropertyFieldSitePickerListItem'; +import { IPropertyFieldTeamPickerListItemProps } from './IPropertyFieldTeamPickerListItem'; import { Checkbox } from 'office-ui-fabric-react/lib/Checkbox'; import styles from './PropertyFieldTeamPickerListItem.module.scss'; export const PropertyFieldTeamPickerListItem = (props: IPropertyFieldTeamPickerListItemProps): JSX.Element => { - const { site, checked } = props; + const { team, checked } = props; return ( -
    • +
    • , nowChecked?: boolean): void => props.handleCheckboxChange(site, nowChecked)} + onChange={(ev?: React.FormEvent, nowChecked?: boolean): void => props.handleCheckboxChange(team, nowChecked)} /> - {site.title} + {team.title}
    • ); -}; \ No newline at end of file +}; diff --git a/src/services/TeamsSearchService.ts b/src/services/TeamsSearchService.ts index 0f35051b..17a3c3b5 100644 --- a/src/services/TeamsSearchService.ts +++ b/src/services/TeamsSearchService.ts @@ -7,12 +7,12 @@ import { dateAdd, PnPClientStorage } from "@pnp/common"; +import { batch, IGraphBatchRequestItem } from "../helpers/GraphHelper"; import { IPropertyFieldTeam } from "../propertyFields/teamPicker/IPropertyFieldTeamPicker"; import { ITeamsSearchService } from "./ITeamsSearchService"; -import SPPeoplePickerMockHttpClient from "./SPPeopleSearchMockService"; /** * Service implementation to search sites in SharePoint @@ -21,60 +21,50 @@ export default class TeamsSearchService implements ITeamsSearchService { /** * Search sites from the SharePoint */ - private storage = new PnPClientStorage(); + private storage = new PnPClientStorage(); public async searchTeams(ctx: any, query: string): Promise { if (Environment.type === EnvironmentType.Local) { // If the running environment is local, load the data from the mock return this.searchSitesFromMock(ctx, query); } else { - const _msGraphClient = await ctx.msGraphClientFactory.getClient(); - const _listOfTeamsResults: any = await _msGraphClient - .api(`/groups?$filter=startswith(displayName,'${query}') AND resourceProvisioningOptions/Any(x:x eq 'Team')`) - .version("beta") + const msGraphClient = await ctx.msGraphClientFactory.getClient(); + const listOfTeamsResults: any = await msGraphClient + .api(`/me/joinedTeams?$filter=startswith(displayName,'${query}')&$select=id,displayName`) + .version("v1.0") .get(); - const _listOfTeams: any[] = _listOfTeamsResults.value; + const listOfTeams: any[] = listOfTeamsResults.value; - let _res: IPropertyFieldTeam[] = []; - if (_listOfTeams && _listOfTeams.length > 0) { - for (const _team of _listOfTeams) { - const _webUrl = await this.getGroupUrl(ctx,_team.id); - _res.push({ id: _team.id, title: _team.displayName, url: _webUrl}); - } - } - return _res; - } - } + const res: IPropertyFieldTeam[] = []; + if (listOfTeams && listOfTeams.length > 0) { - private async getGroupUrl(ctx:any, groupId:string):Promise{ - const cachedGroupUrl:string = this.storage.local.get(`${groupId}WebUrl`); - if (!cachedGroupUrl){ - const _msGraphClient = await ctx.msGraphClientFactory.getClient(); - const _groupInfo: any = await _msGraphClient - .api(`/groups/${groupId}/drive/root/webUrl`) - .version("beta") - .get(); + const batchRequests: IGraphBatchRequestItem[] = []; + listOfTeams.forEach((t) => { + batchRequests.push({ + id: t.id, + method: 'GET', + url: `/groups/${t.id}/drive/root?$select=webUrl` + }); + }); - let _webUrl:string = _groupInfo.value; - const _lastSlash = _webUrl.lastIndexOf('/'); - _webUrl = _webUrl.substring(0, _lastSlash); - this.storage.local.put(`${groupId}WebUrl`, _webUrl, dateAdd(new Date(), "day", 5)); - return _webUrl; - }else{ - return cachedGroupUrl; + const batchResponses = await batch(batchRequests, 'v1.0', ctx); + + for (const team of listOfTeams) { + const webUrl = batchResponses.filter(br => br.id === team.id)[0].body.webUrl; + res.push({ id: team.id, title: team.displayName, url: webUrl }); + } + } + return res; } } /** * Returns fake sites results for the Mock mode */ - private searchSitesFromMock(ctx: IWebPartContext, query: string): Promise> { - return SPPeoplePickerMockHttpClient.searchPeople(ctx.pageContext.web.absoluteUrl).then(() => { - const results: IPropertyFieldTeam[] = [ - { title: 'Contoso Team', id: '611453e1-5b5d-45ec-94aa-a180a02df897', url: ctx.pageContext.web.absoluteUrl } - ]; - return results; - }) as Promise>; + private async searchSitesFromMock(ctx: IWebPartContext, query: string): Promise> { + return [ + { title: 'Contoso Team', id: '611453e1-5b5d-45ec-94aa-a180a02df897', url: ctx.pageContext.web.absoluteUrl } + ]; } } diff --git a/src/webparts/propertyControlsTest/IPropertyControlsTestWebPartProps.ts b/src/webparts/propertyControlsTest/IPropertyControlsTestWebPartProps.ts index 60cca01a..ede76aad 100644 --- a/src/webparts/propertyControlsTest/IPropertyControlsTestWebPartProps.ts +++ b/src/webparts/propertyControlsTest/IPropertyControlsTestWebPartProps.ts @@ -7,6 +7,7 @@ import { IPropertyFieldSite } from '../../propertyFields/sitePicker'; import { IFilePickerResult } from '../../PropertyFieldFilePicker'; import { IRoleDefinitionInformation } from "../../PropertyFieldRoleDefinitionPicker"; import { IFolder } from "../../PropertyFieldFolderPicker"; +import { IPropertyFieldTeam } from '../../PropertyFieldTeamPicker'; export interface IPropertyControlsTestWebPartProps { siteUrl: string; @@ -45,4 +46,5 @@ export interface IPropertyControlsTestWebPartProps { roleDefinitions: IRoleDefinitionInformation[]; folderPicker: IFolder; guid: string; + teams: IPropertyFieldTeam[]; } diff --git a/src/webparts/propertyControlsTest/PropertyControlsTestWebPart.ts b/src/webparts/propertyControlsTest/PropertyControlsTestWebPart.ts index 904d0f88..29f4a2e9 100644 --- a/src/webparts/propertyControlsTest/PropertyControlsTestWebPart.ts +++ b/src/webparts/propertyControlsTest/PropertyControlsTestWebPart.ts @@ -57,6 +57,7 @@ import { IFolder, IPropertyFieldFolderPickerProps , PropertyFieldFolderPicker } import { PropertyPaneMarkdownContent } from '../../PropertyPaneMarkdownContent'; import { PropertyFieldGuid } from '../../PropertyFieldGuid'; import FieldErrorMessage from '../../propertyFields/errorMessage/FieldErrorMessage'; +import { PropertyFieldTeamPicker } from '../../propertyFields/teamPicker'; /** * Web part that can be used to test out the various property controls @@ -514,7 +515,7 @@ export default class PropertyControlsTestWebPart extends BaseClientSideWebPart Date: Wed, 28 Oct 2020 18:55:13 -0700 Subject: [PATCH 7/8] 2.2.0 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index ba7d555f..11af3573 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "@pnp/spfx-property-controls", - "version": "2.1.1", + "version": "2.2.0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index ea6b9ad5..4da713fa 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": "2.1.1", + "version": "2.2.0", "engines": { "node": ">=0.10.0" }, From dc99c2024ef30874bd7c25c89ed62271570956e8 Mon Sep 17 00:00:00 2001 From: Alex Terentiev Date: Wed, 28 Oct 2020 18:56:42 -0700 Subject: [PATCH 8/8] changelog --- CHANGELOG.json | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/CHANGELOG.json b/CHANGELOG.json index 474d299c..40672417 100644 --- a/CHANGELOG.json +++ b/CHANGELOG.json @@ -1,5 +1,18 @@ { "versions": [ + { + "version": "2.2.0", + "changes": { + "new": [ + "`PropertyFieldTeamPicker`: new Teams picker control [#303](https://github.com/pnp/sp-dev-fx-property-controls/pull/303)" + ], + "enhancements": [], + "fixes": [] + }, + "contributions": [ + "[João Mendes](https://github.com/joaojmendes)" + ] + }, { "version": "2.1.1", "changes": {