diff --git a/packages/mgt-components/src/components/components.ts b/packages/mgt-components/src/components/components.ts index dec27498b0..18b99a332a 100644 --- a/packages/mgt-components/src/components/components.ts +++ b/packages/mgt-components/src/components/components.ts @@ -55,6 +55,7 @@ export * from './mgt-search-box/mgt-search-box'; export * from './mgt-search-results/mgt-search-results'; export * from './mgt-theme-toggle/mgt-theme-toggle'; export * from './sub-components/mgt-spinner/mgt-spinner'; +export * from './mgt-teams-channel-picker/teams-channel-picker-types'; // include preview components here for ease of import into mgt-react // There are no preview components in this package at this time // export * from './preview'; diff --git a/packages/mgt-components/src/components/mgt-people-picker/mgt-people-picker.ts b/packages/mgt-components/src/components/mgt-people-picker/mgt-people-picker.ts index c87fe9e412..fe44dc0ac1 100644 --- a/packages/mgt-components/src/components/mgt-people-picker/mgt-people-picker.ts +++ b/packages/mgt-components/src/components/mgt-people-picker/mgt-people-picker.ts @@ -34,7 +34,6 @@ import { mgtHtml } from '@microsoft/mgt-element'; import '../../styles/style-helper'; -import '../sub-components/mgt-spinner/mgt-spinner'; import { debounce, isValidEmail } from '../../utils/Utils'; import { MgtPerson, defaultPersonProperties, registerMgtPersonComponent } from '../mgt-person/mgt-person'; import { PersonCardInteraction } from '../PersonCardInteraction'; @@ -1081,7 +1080,7 @@ export class MgtPeoplePicker extends MgtTemplatedComponent { } catch (_) { this._groupPeople = []; } - } else if (this.groupIds) { + } else { if (this.type === PersonType.group) { try { this._groupPeople = await getGroupsForGroupIds(graph, this.groupIds, this.groupFilters); @@ -1119,21 +1118,13 @@ export class MgtPeoplePicker extends MgtTemplatedComponent { } } } else if (this.type === PersonType.group) { - if (this.groupIds) { - try { - people = await this.getGroupsForGroupIds(graph, people); - } catch (_) { - // nop - } - } else { - let groups = (await findGroups(graph, '', this.showMax, this.groupType, this._groupFilters)) || []; - // eslint-disable-next-line @typescript-eslint/dot-notation - if (groups.length > 0 && groups[0]['value']) { - // eslint-disable-next-line @typescript-eslint/dot-notation, @typescript-eslint/no-unsafe-assignment - groups = groups[0]['value']; - } - people = groups; + let groups = (await findGroups(graph, '', this.showMax, this.groupType, this._groupFilters)) || []; + // eslint-disable-next-line @typescript-eslint/dot-notation + if (groups.length > 0 && groups[0]['value']) { + // eslint-disable-next-line @typescript-eslint/dot-notation, @typescript-eslint/no-unsafe-assignment + groups = groups[0]['value']; } + people = groups; } this.defaultPeople = people; } @@ -1189,7 +1180,7 @@ export class MgtPeoplePicker extends MgtTemplatedComponent { if (this.userType === UserType.contact || this.userType === UserType.user) { // we might have a user-filters property set, search for users with it. if (this.userIds?.length) { - // has the user-ids proerty set + // has the user-ids property set people = await getUsersForUserIds(graph, this.userIds, input, this._userFilters); } else { people = await findUsers(graph, input, this.showMax, this._userFilters); @@ -1197,7 +1188,7 @@ export class MgtPeoplePicker extends MgtTemplatedComponent { } else { if (!this.groupIds) { if (this.userIds?.length) { - // has the user-ids proerty set + // has the user-ids property set people = await getUsersForUserIds(graph, this.userIds, input, this._userFilters); } else { people = (await findPeople(graph, input, this.showMax, this.userType, this._peopleFilters)) || []; diff --git a/packages/mgt-components/src/components/mgt-people/mgt-people.ts b/packages/mgt-components/src/components/mgt-people/mgt-people.ts index 9d45705405..ca0cd41562 100644 --- a/packages/mgt-components/src/components/mgt-people/mgt-people.ts +++ b/packages/mgt-components/src/components/mgt-people/mgt-people.ts @@ -492,10 +492,10 @@ export class MgtPeople extends MgtTemplatedComponent { // populate people if (this.groupId) { this.people = await findGroupMembers(graph, null, this.groupId, this.showMax, PersonType.person); - } else if (this.userIds || this.peopleQueries) { - this.people = this.userIds - ? await getUsersForUserIds(graph, this.userIds, '', '', this._fallbackDetails) - : await getUsersForPeopleQueries(graph, this.peopleQueries, this._fallbackDetails); + } else if (this.userIds) { + this.people = await getUsersForUserIds(graph, this.userIds, '', '', this._fallbackDetails); + } else if (this.peopleQueries) { + this.people = await getUsersForPeopleQueries(graph, this.peopleQueries, this._fallbackDetails); } else if (this.resource) { this.people = await getPeopleFromResource(graph, this.version, this.resource, this.scopes); } else { diff --git a/packages/mgt-components/src/components/mgt-person-card/mgt-person-card.graph.ts b/packages/mgt-components/src/components/mgt-person-card/mgt-person-card.graph.ts index 1fc6203a2e..0527ac985e 100644 --- a/packages/mgt-components/src/components/mgt-person-card/mgt-person-card.graph.ts +++ b/packages/mgt-components/src/components/mgt-person-card/mgt-person-card.graph.ts @@ -119,8 +119,9 @@ const buildOrgStructureRequest = (batch: IBatch, userId: string) => { batch.get(batchKeys.directReports, `users/${userId}/directReports?$select=${userProperties}`); }; +const validPeopleScopes = ['People.Read.All']; const buildWorksWithRequest = (batch: IBatch, userId: string) => { - batch.get(batchKeys.people, `users/${userId}/people?$filter=personType/class eq 'Person'`, validUserByIdScopes); + batch.get(batchKeys.people, `users/${userId}/people?$filter=personType/class eq 'Person'`, validPeopleScopes); }; const validMailSearchScopes = ['Mail.ReadBasic', 'Mail.Read', 'Mail.ReadWrite']; const buildMessagesWithUserRequest = (batch: IBatch, emailAddress: string) => { @@ -139,6 +140,7 @@ const buildFilesRequest = (batch: IBatch, emailAddress?: string) => { batch.get(batchKeys.files, request, validInsightScopes); }; +const validProfileScopes = ['User.Read.All', 'User.ReadWrite.All']; /** * Get the profile for a user * @@ -150,7 +152,7 @@ const getProfile = async (graph: IGraph, userId: string): Promise => (await graph .api(`/users/${userId}/profile`) .version('beta') - .middlewareOptions(prepScopes(validUserByIdScopes)) + .middlewareOptions(prepScopes(validProfileScopes)) .get()) as Profile; const validCreateChatScopes = ['Chat.Create', 'Chat.ReadWrite']; diff --git a/packages/mgt-components/src/components/mgt-taxonomy-picker/mgt-taxonomy-picker.ts b/packages/mgt-components/src/components/mgt-taxonomy-picker/mgt-taxonomy-picker.ts index 6d34dd60a5..6d43e42b6c 100644 --- a/packages/mgt-components/src/components/mgt-taxonomy-picker/mgt-taxonomy-picker.ts +++ b/packages/mgt-components/src/components/mgt-taxonomy-picker/mgt-taxonomy-picker.ts @@ -421,7 +421,7 @@ export class MgtTaxonomyPicker extends MgtTemplatedComponent { class="mgt-get" resource=${resource} version=${this.version} - scopes=${['TermStore.Read.All']} + scopes="TermStore.Read.All, TermStore.ReadWrite.All" ?cache-enabled=${this.cacheEnabled} ?cache-invalidation-period=${this.cacheInvalidationPeriod}> `; diff --git a/packages/mgt-components/src/components/mgt-teams-channel-picker/mgt-teams-channel-picker.graph.ts b/packages/mgt-components/src/components/mgt-teams-channel-picker/mgt-teams-channel-picker.graph.ts index 75f29dae7b..099ba4130d 100644 --- a/packages/mgt-components/src/components/mgt-teams-channel-picker/mgt-teams-channel-picker.graph.ts +++ b/packages/mgt-components/src/components/mgt-teams-channel-picker/mgt-teams-channel-picker.graph.ts @@ -5,8 +5,8 @@ * ------------------------------------------------------------------------------------------- */ -import { IGraph, BetaGraph, CacheService, CacheStore, prepScopes } from '@microsoft/mgt-element'; -import { Team } from '@microsoft/microsoft-graph-types'; +import { IGraph, CacheService, CacheStore, prepScopes } from '@microsoft/mgt-element'; +import { Team, Channel } from '@microsoft/microsoft-graph-types'; import { getPhotoForResource, CachePhoto, @@ -15,6 +15,19 @@ import { } from '../../graph/graph.photos'; import { schemas } from '../../graph/cacheStores'; import { CollectionResponse } from '@microsoft/mgt-element'; +import { DropdownItem } from './teams-channel-picker-types'; + +const teamReadScopes = [ + 'Team.ReadBasic.All', + 'TeamSettings.Read.All', + 'TeamSettings.ReadWrite.All', + 'User.Read.All', + 'User.ReadWrite.All' +]; + +const channelReadScopes = ['Channel.ReadBasic.All', 'ChannelSettings.Read.All', 'ChannelSettings.ReadWrite.All']; + +const teamPhotoReadScopes = ['Team.ReadBasic.All', 'TeamSettings.Read.All', 'TeamSettings.ReadWrite.All']; /** * async promise, returns all Teams associated with the user logged in @@ -22,7 +35,8 @@ import { CollectionResponse } from '@microsoft/mgt-element'; * @returns {Promise} * @memberof Graph */ -export const getAllMyTeams = async (graph: IGraph, scopes: string[]): Promise => { +export const getAllMyTeams = async (graph: IGraph): Promise => { + const scopes = teamReadScopes; const teams = (await graph .api('/me/joinedTeams') .select(['displayName', 'id', 'isArchived']) @@ -38,11 +52,11 @@ type CachePhotos = Record; /** * Load the photos for a give set of teamIds * - * @param graph {BetaGraph} + * @param graph {IGraph} * @param teamIds {string[]} * @returns {Promise} */ -export const getTeamsPhotosForPhotoIds = async (graph: BetaGraph, teamIds: string[]): Promise => { +export const getTeamsPhotosForPhotoIds = async (graph: IGraph, teamIds: string[]): Promise => { let cache: CacheStore; let photos: CachePhotos = {}; @@ -63,12 +77,11 @@ export const getTeamsPhotosForPhotoIds = async (graph: BetaGraph, teamIds: strin } } - const scopes = ['team.readbasic.all']; photos = {}; for (const id of teamIds) { try { - const photoDetail = await getPhotoForResource(graph, `/teams/${id}`, scopes); + const photoDetail = await getPhotoForResource(graph, `/teams/${id}`, teamPhotoReadScopes); if (getIsPhotosCacheEnabled() && photoDetail) { await cache.putValue(id, photoDetail); } @@ -80,3 +93,31 @@ export const getTeamsPhotosForPhotoIds = async (graph: BetaGraph, teamIds: strin return photos; }; + +/** + * Creates an array of DropdownItems from an array of Teams populated with channels and photos + * + * @param graph {IGraph} + * @param teams {Team[]} the teams to get channels for + * @returns {Promise} a promise that resolves to an array of DropdownItems + */ +export const getChannelsForTeams = async (graph: IGraph, teams: Team[]): Promise => { + const batch = graph.createBatch>(); + + for (const team of teams) { + batch.get(team.id, `teams/${team.id}/channels`, channelReadScopes); + } + + const responses = await batch.executeAll(); + const result: DropdownItem[] = []; + for (const team of teams) { + const channelsForTeam = responses.get(team.id); + // skip over any teams that don't have channels + if (!channelsForTeam?.content?.value?.length) continue; + result.push({ + item: team, + channels: channelsForTeam.content.value.map(c => ({ item: c })) + }); + } + return result; +}; diff --git a/packages/mgt-components/src/components/mgt-teams-channel-picker/mgt-teams-channel-picker.ts b/packages/mgt-components/src/components/mgt-teams-channel-picker/mgt-teams-channel-picker.ts index 1cf1342671..ff882dcb37 100644 --- a/packages/mgt-components/src/components/mgt-teams-channel-picker/mgt-teams-channel-picker.ts +++ b/packages/mgt-components/src/components/mgt-teams-channel-picker/mgt-teams-channel-picker.ts @@ -9,20 +9,12 @@ import * as MicrosoftGraph from '@microsoft/microsoft-graph-types'; import { html, TemplateResult } from 'lit'; import { state } from 'lit/decorators.js'; import { classMap } from 'lit/directives/class-map.js'; -import { - Providers, - ProviderState, - MgtTemplatedComponent, - BetaGraph, - mgtHtml, - CollectionResponse -} from '@microsoft/mgt-element'; +import { Providers, ProviderState, MgtTemplatedComponent, mgtHtml } from '@microsoft/mgt-element'; import '../../styles/style-helper'; -import '../sub-components/mgt-spinner/mgt-spinner'; import { getSvg, SvgIcon } from '../../utils/SvgHelper'; import { debounce } from '../../utils/Utils'; import { styles } from './mgt-teams-channel-picker-css'; -import { getAllMyTeams, getTeamsPhotosForPhotoIds } from './mgt-teams-channel-picker.graph'; +import { getAllMyTeams, getChannelsForTeams, getTeamsPhotosForPhotoIds } from './mgt-teams-channel-picker.graph'; import { strings } from './strings'; import { repeat } from 'lit/directives/repeat.js'; import { registerFluentComponents } from '../../utils/FluentComponents'; @@ -36,104 +28,7 @@ import { } from '@fluentui/web-components'; import { registerComponent } from '@microsoft/mgt-element'; import { registerMgtSpinnerComponent } from '../sub-components/mgt-spinner/mgt-spinner'; - -/** - * Team with displayName - * - * @export - * @interface SelectedChannel - */ -export type Team = MicrosoftGraph.Team & { - /** - * Display name Of Team - * - * @type {string} - */ - displayName?: string; -}; - -/** - * Selected Channel item - * - * @export - * @interface SelectedChannel - */ -export interface SelectedChannel { - /** - * Channel - * - * @type {MicrosoftGraph.Channel} - * @memberof SelectedChannel - */ - channel: MicrosoftGraph.Channel; - - /** - * Team - * - * @type {MicrosoftGraph.Team} - * @memberof SelectedChannel - */ - team: Team; -} - -/** - * Drop down menu item - * - * @export - * @interface DropdownItem - */ -interface DropdownItem { - /** - * Teams channel - * - * @type {DropdownItem[]} - * @memberof DropdownItem - */ - channels?: DropdownItem[]; - /** - * Microsoft Graph Channel or Team - * - * @type {(MicrosoftGraph.Channel | MicrosoftGraph.Team)} - * @memberof DropdownItem - */ - item: MicrosoftGraph.Channel | Team; -} - -/** - * Drop down menu item state - * - * @interface DropdownItemState - */ -interface ChannelPickerItemState { - /** - * Microsoft Graph Channel or Team - * - * @type {(MicrosoftGraph.Channel | MicrosoftGraph.Team)} - * @memberof ChannelPickerItemState - */ - item: MicrosoftGraph.Channel | Team; - /** - * if dropdown item shows expanded state - * - * @type {boolean} - * @memberof DropdownItemState - */ - isExpanded?: boolean; - /** - * If item contains channels - * - * @type {ChannelPickerItemState[]} - * @memberof DropdownItemState - */ - channels?: ChannelPickerItemState[]; - /** - * if Item has parent item (team) - * - * @type {ChannelPickerItemState} - * @memberof DropdownItemState - */ - parent: ChannelPickerItemState; -} +import { SelectedChannel, DropdownItem, ChannelPickerItemState } from './teams-channel-picker-types'; export const registerMgtTeamsChannelPickerComponent = () => { registerFluentComponents( @@ -727,31 +622,13 @@ export class MgtTeamsChannelPicker extends MgtTemplatedComponent { if (provider && provider.state === ProviderState.SignedIn) { const graph = provider.graph.forComponent(this); - teams = await getAllMyTeams(graph, MgtTeamsChannelPicker.requiredScopes); + teams = await getAllMyTeams(graph); teams = teams.filter(t => !t.isArchived); - const beta = BetaGraph.fromGraph(graph); - const teamsIds = teams.map(t => t.id); - this.teamsPhotos = await getTeamsPhotosForPhotoIds(beta, teamsIds); - - const batch = graph.createBatch>(); + this.teamsPhotos = await getTeamsPhotosForPhotoIds(graph, teamsIds); - for (const team of teams) { - batch.get(team.id, `teams/${team.id}/channels`, MgtTeamsChannelPicker.requiredScopes); - } - - const responses = await batch.executeAll(); - this._items = []; - for (const team of teams) { - const channelsForTeam = responses.get(team.id); - // skip over any teams that don't have channels - if (!channelsForTeam?.content?.value?.length) continue; - this.items.push({ - item: team, - channels: channelsForTeam.content.value.map(c => ({ item: c })) - }); - } + this._items = await getChannelsForTeams(graph, teams); } this.filterList(); this.resetFocusState(); diff --git a/packages/mgt-components/src/components/mgt-teams-channel-picker/teams-channel-picker-types.ts b/packages/mgt-components/src/components/mgt-teams-channel-picker/teams-channel-picker-types.ts new file mode 100644 index 0000000000..283bcc4f18 --- /dev/null +++ b/packages/mgt-components/src/components/mgt-teams-channel-picker/teams-channel-picker-types.ts @@ -0,0 +1,98 @@ +import * as MicrosoftGraph from '@microsoft/microsoft-graph-types'; + +/** + * Team with displayName + * + * @export + * @interface SelectedChannel + */ + +export type Team = MicrosoftGraph.Team & { + /** + * Display name Of Team + * + * @type {string} + */ + displayName?: string; +}; +/** + * Selected Channel item + * + * @export + * @interface SelectedChannel + */ + +export interface SelectedChannel { + /** + * Channel + * + * @type {MicrosoftGraph.Channel} + * @memberof SelectedChannel + */ + channel: MicrosoftGraph.Channel; + + /** + * Team + * + * @type {MicrosoftGraph.Team} + * @memberof SelectedChannel + */ + team: Team; +} +/** + * Drop down menu item + * + * @export + * @interface DropdownItem + */ +export interface DropdownItem { + /** + * Teams channel + * + * @type {DropdownItem[]} + * @memberof DropdownItem + */ + channels?: DropdownItem[]; + /** + * Microsoft Graph Channel or Team + * + * @type {(MicrosoftGraph.Channel | MicrosoftGraph.Team)} + * @memberof DropdownItem + */ + item: MicrosoftGraph.Channel | Team; +} +/** + * Drop down menu item state + * + * @interface DropdownItemState + */ +export interface ChannelPickerItemState { + /** + * Microsoft Graph Channel or Team + * + * @type {(MicrosoftGraph.Channel | MicrosoftGraph.Team)} + * @memberof ChannelPickerItemState + */ + item: MicrosoftGraph.Channel | Team; + /** + * if dropdown item shows expanded state + * + * @type {boolean} + * @memberof DropdownItemState + */ + isExpanded?: boolean; + /** + * If item contains channels + * + * @type {ChannelPickerItemState[]} + * @memberof DropdownItemState + */ + channels?: ChannelPickerItemState[]; + /** + * if Item has parent item (team) + * + * @type {ChannelPickerItemState} + * @memberof DropdownItemState + */ + parent: ChannelPickerItemState; +} diff --git a/packages/mgt-components/src/components/mgt-todo/mgt-todo.ts b/packages/mgt-components/src/components/mgt-todo/mgt-todo.ts index d8505c4f88..9f43880570 100644 --- a/packages/mgt-components/src/components/mgt-todo/mgt-todo.ts +++ b/packages/mgt-components/src/components/mgt-todo/mgt-todo.ts @@ -8,13 +8,11 @@ import { html, nothing, TemplateResult } from 'lit'; import { state } from 'lit/decorators.js'; import { classMap } from 'lit/directives/class-map.js'; +import { ifDefined } from 'lit/directives/if-defined.js'; import { repeat } from 'lit/directives/repeat.js'; -import { IGraph, mgtHtml } from '@microsoft/mgt-element'; -import { Providers, ProviderState } from '@microsoft/mgt-element'; -import { getSvg, SvgIcon } from '../../utils/SvgHelper'; -import '../mgt-person/mgt-person'; -import { MgtTasksBase } from '../mgt-tasks-base/mgt-tasks-base'; -import '../sub-components/mgt-arrow-options/mgt-arrow-options'; +import { fluentCheckbox, fluentRadioGroup, fluentButton } from '@fluentui/web-components'; +import { IGraph, mgtHtml, registerComponent, Providers, ProviderState } from '@microsoft/mgt-element'; +import { TodoTaskList, TodoTask, TaskStatus } from '@microsoft/microsoft-graph-types'; import { createTodoTask, deleteTodoTask, @@ -25,14 +23,11 @@ import { } from './graph.todo'; import { styles } from './mgt-todo-css'; import { strings } from './strings'; +import { registerMgtPickerComponent } from '../mgt-picker/mgt-picker'; +import { MgtTasksBase } from '../mgt-tasks-base/mgt-tasks-base'; import { registerFluentComponents } from '../../utils/FluentComponents'; -import { fluentCheckbox, fluentRadioGroup, fluentButton } from '@fluentui/web-components'; import { isElementDark } from '../../utils/isDark'; -import { ifDefined } from 'lit/directives/if-defined.js'; - -import { TodoTaskList, TodoTask, TaskStatus } from '@microsoft/microsoft-graph-types'; -import { registerComponent } from '@microsoft/mgt-element'; -import { registerMgtPickerComponent } from '../mgt-picker/mgt-picker'; +import { getSvg, SvgIcon } from '../../utils/SvgHelper'; /** * Filter function diff --git a/packages/mgt-components/src/graph/graph.groups.ts b/packages/mgt-components/src/graph/graph.groups.ts index 20654ab829..bc849e2821 100644 --- a/packages/mgt-components/src/graph/graph.groups.ts +++ b/packages/mgt-components/src/graph/graph.groups.ts @@ -92,8 +92,8 @@ const getIsGroupsCacheEnabled = (): boolean => CacheService.config.groups.isEnab const validGroupQueryScopes = [ 'GroupMember.Read.All', 'Group.Read.All', - 'Group.ReadWrite.All', 'Directory.Read.All', + 'Group.ReadWrite.All', 'Directory.ReadWrite.All' ];