├── frontend └── angular11 │ ├── src │ ├── assets │ │ ├── .gitkeep │ │ ├── markdown │ │ │ ├── displayTemplate.md │ │ │ ├── meeting.md │ │ │ ├── common.md │ │ │ ├── sort.md │ │ │ └── speller.md │ │ ├── favicon.png │ │ └── microsoft.svg │ ├── app │ │ ├── samples │ │ │ ├── common │ │ │ │ ├── common.component.scss │ │ │ │ ├── common.component.spec.ts │ │ │ │ ├── common.component.ts │ │ │ │ └── common.component.html │ │ │ ├── sort │ │ │ │ ├── sort.component.scss │ │ │ │ ├── sort.component.spec.ts │ │ │ │ ├── sort.component.ts │ │ │ │ └── sort.component.html │ │ │ ├── speller │ │ │ │ ├── speller.component.scss │ │ │ │ ├── speller.component.spec.ts │ │ │ │ ├── speller.component.ts │ │ │ │ └── speller.component.html │ │ │ ├── welcome │ │ │ │ ├── welcome.component.scss │ │ │ │ ├── welcome.component.spec.ts │ │ │ │ ├── welcome.component.html │ │ │ │ └── welcome.component.ts │ │ │ ├── display-template │ │ │ │ ├── display-template.component.scss │ │ │ │ ├── display-template.component.spec.ts │ │ │ │ ├── display-template.component.html │ │ │ │ └── display-template.component.ts │ │ │ ├── semantic-label │ │ │ │ ├── semantic-label.component.scss │ │ │ │ ├── semantic-label.component.spec.ts │ │ │ │ ├── semantic-label.component.html │ │ │ │ └── semantic-label.component.ts │ │ │ ├── meeting │ │ │ │ ├── meeting.component.scss │ │ │ │ ├── meeting.component.spec.ts │ │ │ │ ├── meeting.component.ts │ │ │ │ └── meeting.component.html │ │ │ └── sort-v2 │ │ │ │ ├── sort-v2.component.spec.ts │ │ │ │ ├── sort-v2.component.scss │ │ │ │ ├── sort-v2.component.ts │ │ │ │ └── sort-v2.component.html │ │ ├── app.component.ts │ │ ├── service │ │ │ ├── common.service.spec.ts │ │ │ └── common.service.ts │ │ ├── app.component.spec.ts │ │ ├── icons-provider.module.ts │ │ ├── app-routing.module.ts │ │ ├── app.component.scss │ │ ├── app.component.html │ │ └── app.module.ts │ ├── environments │ │ ├── environment.prod.ts │ │ └── environment.ts │ ├── styles.scss │ ├── favicon.ico │ ├── microsoft.svg │ ├── index.html │ ├── main.ts │ ├── test.ts │ └── polyfills.ts │ ├── e2e │ ├── src │ │ ├── app.po.ts │ │ └── app.e2e-spec.ts │ ├── tsconfig.json │ └── protractor.conf.js │ ├── .editorconfig │ ├── tsconfig.app.json │ ├── tsconfig.spec.json │ ├── tsconfig.json │ ├── .browserslistrc │ ├── README.md │ ├── karma.conf.js │ ├── package.json │ ├── tslint.json │ └── angular.json ├── Images ├── Token.PNG ├── SetToken.PNG ├── Backend_demo.PNG ├── Frontend_demo.PNG ├── OpenTerminal.PNG ├── SearchResult.PNG ├── run_frontend.PNG ├── Import_frontend.PNG ├── Install_fronend.PNG ├── VisualStudio_Run.PNG └── VisualStudio_PackageManager.PNG ├── backend └── Csharp │ ├── Model │ └── SearchRequest.cs │ ├── day30Sample.csproj │ ├── Helpers │ ├── EventHelper.cs │ ├── SearchHelper.cs │ └── GraphSdkHelper.cs │ ├── Program.cs │ ├── Properties │ └── launchSettings.json │ ├── Controllers │ ├── EventController.cs │ └── SearchController.cs │ ├── day30Sample.sln │ └── Startup.cs ├── SECURITY.md ├── LICENSE ├── README.md └── .gitignore /frontend/angular11/src/assets/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /frontend/angular11/src/app/samples/common/common.component.scss: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /frontend/angular11/src/app/samples/sort/sort.component.scss: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /frontend/angular11/src/app/samples/speller/speller.component.scss: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /frontend/angular11/src/app/samples/welcome/welcome.component.scss: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /frontend/angular11/src/app/samples/display-template/display-template.component.scss: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /frontend/angular11/src/app/samples/semantic-label/semantic-label.component.scss: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /frontend/angular11/src/assets/markdown/displayTemplate.md: -------------------------------------------------------------------------------- 1 | ```csharp 2 | // Not onboard 3 | ``` -------------------------------------------------------------------------------- /Images/Token.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoftgraph/aspnetcore-search-sample/main/Images/Token.PNG -------------------------------------------------------------------------------- /Images/SetToken.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoftgraph/aspnetcore-search-sample/main/Images/SetToken.PNG -------------------------------------------------------------------------------- /frontend/angular11/src/environments/environment.prod.ts: -------------------------------------------------------------------------------- 1 | export const environment = { 2 | production: true 3 | }; 4 | -------------------------------------------------------------------------------- /frontend/angular11/src/styles.scss: -------------------------------------------------------------------------------- 1 | /* You can add global styles to this file, and also import other style files */ 2 | -------------------------------------------------------------------------------- /Images/Backend_demo.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoftgraph/aspnetcore-search-sample/main/Images/Backend_demo.PNG -------------------------------------------------------------------------------- /Images/Frontend_demo.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoftgraph/aspnetcore-search-sample/main/Images/Frontend_demo.PNG -------------------------------------------------------------------------------- /Images/OpenTerminal.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoftgraph/aspnetcore-search-sample/main/Images/OpenTerminal.PNG -------------------------------------------------------------------------------- /Images/SearchResult.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoftgraph/aspnetcore-search-sample/main/Images/SearchResult.PNG -------------------------------------------------------------------------------- /Images/run_frontend.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoftgraph/aspnetcore-search-sample/main/Images/run_frontend.PNG -------------------------------------------------------------------------------- /frontend/angular11/src/app/samples/meeting/meeting.component.scss: -------------------------------------------------------------------------------- 1 | .nz-date-picker { 2 | margin: 0 8px 12px 0; 3 | } -------------------------------------------------------------------------------- /Images/Import_frontend.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoftgraph/aspnetcore-search-sample/main/Images/Import_frontend.PNG -------------------------------------------------------------------------------- /Images/Install_fronend.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoftgraph/aspnetcore-search-sample/main/Images/Install_fronend.PNG -------------------------------------------------------------------------------- /Images/VisualStudio_Run.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoftgraph/aspnetcore-search-sample/main/Images/VisualStudio_Run.PNG -------------------------------------------------------------------------------- /frontend/angular11/src/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoftgraph/aspnetcore-search-sample/main/frontend/angular11/src/favicon.ico -------------------------------------------------------------------------------- /Images/VisualStudio_PackageManager.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoftgraph/aspnetcore-search-sample/main/Images/VisualStudio_PackageManager.PNG -------------------------------------------------------------------------------- /frontend/angular11/src/assets/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoftgraph/aspnetcore-search-sample/main/frontend/angular11/src/assets/favicon.png -------------------------------------------------------------------------------- /frontend/angular11/src/microsoft.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /frontend/angular11/src/app/app.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-root', 5 | templateUrl: './app.component.html', 6 | styleUrls: ['./app.component.scss'], 7 | }) 8 | export class AppComponent { 9 | isCollapsed = false; 10 | } 11 | -------------------------------------------------------------------------------- /frontend/angular11/src/assets/microsoft.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /frontend/angular11/e2e/src/app.po.ts: -------------------------------------------------------------------------------- 1 | import { browser, by, element } from 'protractor'; 2 | 3 | export class AppPage { 4 | async navigateTo(): Promise { 5 | return browser.get(browser.baseUrl); 6 | } 7 | 8 | async getTitleText(): Promise { 9 | return element(by.css('app-root .content span')).getText(); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /backend/Csharp/Model/SearchRequest.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Graph; 2 | using System.Collections.Generic; 3 | 4 | namespace day30Sample.Model 5 | { 6 | public class SearchRequest 7 | { 8 | public List Requests {set;get;} 9 | 10 | public SearchAlterationOptions QueryAlterationOptions { set; get; } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /frontend/angular11/e2e/tsconfig.json: -------------------------------------------------------------------------------- 1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */ 2 | { 3 | "extends": "../tsconfig.json", 4 | "compilerOptions": { 5 | "outDir": "../out-tsc/e2e", 6 | "module": "commonjs", 7 | "target": "es2018", 8 | "types": [ 9 | "jasmine", 10 | "node" 11 | ] 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /frontend/angular11/.editorconfig: -------------------------------------------------------------------------------- 1 | # Editor configuration, see https://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | indent_style = space 7 | indent_size = 2 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | 11 | [*.ts] 12 | quote_type = single 13 | 14 | [*.md] 15 | max_line_length = off 16 | trim_trailing_whitespace = false 17 | -------------------------------------------------------------------------------- /frontend/angular11/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */ 2 | { 3 | "extends": "./tsconfig.json", 4 | "compilerOptions": { 5 | "outDir": "./out-tsc/app", 6 | "types": [] 7 | }, 8 | "files": [ 9 | "src/main.ts", 10 | "src/polyfills.ts" 11 | ], 12 | "include": [ 13 | "src/**/*.d.ts" 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /frontend/angular11/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Graph Search API Demo 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /frontend/angular11/src/main.ts: -------------------------------------------------------------------------------- 1 | import { enableProdMode } from '@angular/core'; 2 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; 3 | 4 | import { AppModule } from './app/app.module'; 5 | import { environment } from './environments/environment'; 6 | 7 | if (environment.production) { 8 | enableProdMode(); 9 | } 10 | 11 | platformBrowserDynamic().bootstrapModule(AppModule) 12 | .catch(err => console.error(err)); 13 | -------------------------------------------------------------------------------- /frontend/angular11/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */ 2 | { 3 | "extends": "./tsconfig.json", 4 | "compilerOptions": { 5 | "outDir": "./out-tsc/spec", 6 | "types": [ 7 | "jasmine" 8 | ] 9 | }, 10 | "files": [ 11 | "src/test.ts", 12 | "src/polyfills.ts" 13 | ], 14 | "include": [ 15 | "src/**/*.spec.ts", 16 | "src/**/*.d.ts" 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /backend/Csharp/day30Sample.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net5.0 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /frontend/angular11/src/app/service/common.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed } from '@angular/core/testing'; 2 | 3 | import { CommonService } from './common.service'; 4 | 5 | describe('CommonService', () => { 6 | let service: CommonService; 7 | 8 | beforeEach(() => { 9 | TestBed.configureTestingModule({}); 10 | service = TestBed.inject(CommonService); 11 | }); 12 | 13 | it('should be created', () => { 14 | expect(service).toBeTruthy(); 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /frontend/angular11/src/app/app.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed } from '@angular/core/testing'; 2 | import { RouterTestingModule } from '@angular/router/testing'; 3 | import { AppComponent } from './app.component'; 4 | 5 | describe('AppComponent', () => { 6 | beforeEach(async () => { 7 | await TestBed.configureTestingModule({ 8 | imports: [ 9 | RouterTestingModule 10 | ], 11 | declarations: [ 12 | AppComponent 13 | ], 14 | }).compileComponents(); 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /frontend/angular11/tsconfig.json: -------------------------------------------------------------------------------- 1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */ 2 | { 3 | "compileOnSave": false, 4 | "compilerOptions": { 5 | "baseUrl": "./", 6 | "outDir": "./dist/out-tsc", 7 | "sourceMap": true, 8 | "declaration": false, 9 | "downlevelIteration": true, 10 | "experimentalDecorators": true, 11 | "moduleResolution": "node", 12 | "importHelpers": true, 13 | "target": "es2015", 14 | "module": "es2020", 15 | "lib": [ 16 | "es2018", 17 | "dom" 18 | ] 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /backend/Csharp/Helpers/EventHelper.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Graph; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Threading.Tasks; 6 | 7 | namespace day30Sample.Helpers 8 | { 9 | public class EventHelper 10 | { 11 | public static async Task GetEventByEventId(string id, string token) 12 | { 13 | 14 | GraphServiceClient graphClient = GraphSdkHelper.GetAuthenticatedGraphClient(token); 15 | return await graphClient.Me.Events[id].Request().GetAsync(); 16 | 17 | } 18 | 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /frontend/angular11/src/assets/markdown/meeting.md: -------------------------------------------------------------------------------- 1 | ```csharp 2 | GraphServiceClient graphClient = new GraphServiceClient( authProvider ); 3 | 4 | SearchRequestObject searchRequestObject = new SearchRequestObject 5 | { 6 | EntityTypes = new List() 7 | { 8 | EntityType.Event 9 | }, 10 | Query = new SearchQuery 11 | { 12 | QueryString = "*" 13 | } 14 | }; 15 | 16 | 17 | var requests = new List() { searchRequestObject }; 18 | 19 | await graphClient.Search 20 | .Query(requests,null) 21 | .Request() 22 | .PostAsync(); 23 | ``` -------------------------------------------------------------------------------- /frontend/angular11/src/app/icons-provider.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { NZ_ICONS, NzIconModule } from 'ng-zorro-antd/icon'; 3 | 4 | import { 5 | MenuFoldOutline, 6 | MenuUnfoldOutline, 7 | FormOutline, 8 | DashboardOutline, 9 | } from '@ant-design/icons-angular/icons'; 10 | 11 | const icons = [ 12 | MenuFoldOutline, 13 | MenuUnfoldOutline, 14 | DashboardOutline, 15 | FormOutline, 16 | ]; 17 | 18 | @NgModule({ 19 | imports: [NzIconModule], 20 | exports: [NzIconModule], 21 | providers: [{ provide: NZ_ICONS, useValue: icons }], 22 | }) 23 | export class IconsProviderModule {} 24 | -------------------------------------------------------------------------------- /backend/Csharp/Program.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Hosting; 2 | using Microsoft.Extensions.Hosting; 3 | 4 | namespace day30Sample 5 | { 6 | public class Program 7 | { 8 | public static void Main(string[] args) 9 | { 10 | CreateHostBuilder(args).Build().Run(); 11 | } 12 | 13 | 14 | public static IHostBuilder CreateHostBuilder(string[] args) => 15 | Host.CreateDefaultBuilder(args) 16 | .ConfigureWebHostDefaults(webBuilder => 17 | { 18 | webBuilder.UseStartup(); 19 | }); 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | ## Supported Versions 4 | 5 | Use this section to tell people about which versions of your project are 6 | currently being supported with security updates. 7 | 8 | | Version | Supported | 9 | | ------- | ------------------ | 10 | | 5.1.x | :white_check_mark: | 11 | | 5.0.x | :x: | 12 | | 4.0.x | :white_check_mark: | 13 | | < 4.0 | :x: | 14 | 15 | ## Reporting a Vulnerability 16 | 17 | Use this section to tell people how to report a vulnerability. 18 | 19 | Tell them where to go, how often they can expect to get an update on a 20 | reported vulnerability, what to expect if the vulnerability is accepted or 21 | declined, etc. 22 | -------------------------------------------------------------------------------- /backend/Csharp/Helpers/SearchHelper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Net.Http; 4 | using System.Threading.Tasks; 5 | using day30Sample.Helpers; 6 | using day30Sample.Model; 7 | using Microsoft.Graph; 8 | 9 | namespace day30Sample.helpers 10 | { 11 | public class SearchHelper 12 | { 13 | public static async Task Search(SearchRequest searchRequest, string token) 14 | { 15 | GraphServiceClient graphClient = GraphSdkHelper.GetAuthenticatedGraphClient(token); 16 | return await graphClient.Search.Query(searchRequest.Requests, queryAlterationOptions:searchRequest.QueryAlterationOptions).Request().PostAsync(); 17 | } 18 | } 19 | } -------------------------------------------------------------------------------- /frontend/angular11/src/assets/markdown/common.md: -------------------------------------------------------------------------------- 1 | ```csharp 2 | GraphServiceClient graphClient = new GraphServiceClient( authProvider ); 3 | 4 | SearchRequestObject searchRequestObject = new SearchRequestObject 5 | { 6 | EntityTypes = new List() 7 | { 8 | EntityType.DriveItem, 9 | EntityType.List 10 | //EntityType.ListItem, 11 | //EntityType.Drive, 12 | //EntityType.Site, 13 | }, 14 | Query = new SearchQuery 15 | { 16 | QueryString = "*" 17 | } 18 | }; 19 | 20 | var requests = new List() { searchRequestObject }; 21 | 22 | 23 | await graphClient.Search 24 | .Query(requests,null) 25 | .Request() 26 | .PostAsync(); 27 | ``` -------------------------------------------------------------------------------- /frontend/angular11/src/environments/environment.ts: -------------------------------------------------------------------------------- 1 | // This file can be replaced during build by using the `fileReplacements` array. 2 | // `ng build --prod` replaces `environment.ts` with `environment.prod.ts`. 3 | // The list of file replacements can be found in `angular.json`. 4 | 5 | export const environment = { 6 | production: false 7 | }; 8 | 9 | /* 10 | * For easier debugging in development mode, you can import the following file 11 | * to ignore zone related error stack frames such as `zone.run`, `zoneDelegate.invokeTask`. 12 | * 13 | * This import should be commented out in production mode because it will have a negative impact 14 | * on performance if an error is thrown. 15 | */ 16 | // import 'zone.js/dist/zone-error'; // Included with Angular CLI. 17 | -------------------------------------------------------------------------------- /frontend/angular11/src/app/samples/sort/sort.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { SortComponent } from './sort.component'; 4 | 5 | describe('SortComponent', () => { 6 | let component: SortComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | declarations: [ SortComponent ] 12 | }) 13 | .compileComponents(); 14 | }); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(SortComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /frontend/angular11/src/assets/markdown/sort.md: -------------------------------------------------------------------------------- 1 | ```csharp 2 | GraphServiceClient graphClient = new GraphServiceClient(authProvider); 3 | 4 | SearchRequestObject searchRequestObject = new SearchRequestObject 5 | { 6 | EntityTypes = new List() 7 | { 8 | EntityType.DriveItem 9 | }, 10 | Query = new SearchQuery 11 | { 12 | QueryString = "*" 13 | }, 14 | SortProperties = new List() 15 | { 16 | new SortProperty 17 | { 18 | Name = "lastModifiedDateTime", 19 | IsDescending = true 20 | } 21 | } 22 | }; 23 | 24 | 25 | var requests = new List() { searchRequestObject }; 26 | 27 | await graphClient.Search 28 | .Query(requests, null) 29 | .Request() 30 | .PostAsync(); 31 | ``` -------------------------------------------------------------------------------- /frontend/angular11/e2e/src/app.e2e-spec.ts: -------------------------------------------------------------------------------- 1 | import { AppPage } from './app.po'; 2 | import { browser, logging } from 'protractor'; 3 | 4 | describe('workspace-project App', () => { 5 | let page: AppPage; 6 | 7 | beforeEach(() => { 8 | page = new AppPage(); 9 | }); 10 | 11 | it('should display welcome message', async () => { 12 | await page.navigateTo(); 13 | expect(await page.getTitleText()).toEqual('front-end app is running!'); 14 | }); 15 | 16 | afterEach(async () => { 17 | // Assert that there are no errors emitted from the browser 18 | const logs = await browser.manage().logs().get(logging.Type.BROWSER); 19 | expect(logs).not.toContain(jasmine.objectContaining({ 20 | level: logging.Level.SEVERE, 21 | } as logging.Entry)); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /frontend/angular11/src/app/samples/common/common.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { CommonComponent } from './common.component'; 4 | 5 | describe('CommonComponent', () => { 6 | let component: CommonComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | declarations: [ CommonComponent ] 12 | }) 13 | .compileComponents(); 14 | }); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(CommonComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /frontend/angular11/.browserslistrc: -------------------------------------------------------------------------------- 1 | # This file is used by the build system to adjust CSS and JS output to support the specified browsers below. 2 | # For additional information regarding the format and rule options, please see: 3 | # https://github.com/browserslist/browserslist#queries 4 | 5 | # For the full list of supported browsers by the Angular framework, please see: 6 | # https://angular.io/guide/browser-support 7 | 8 | # You can see what browsers were selected by your queries by running: 9 | # npx browserslist 10 | 11 | last 1 Chrome version 12 | last 1 Firefox version 13 | last 2 Edge major versions 14 | last 2 Safari major versions 15 | last 2 iOS major versions 16 | Firefox ESR 17 | not IE 11 # Angular supports IE 11 only as an opt-in. To opt-in, remove the 'not' prefix on this line. 18 | -------------------------------------------------------------------------------- /frontend/angular11/src/app/samples/sort-v2/sort-v2.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { SortV2Component } from './sort-v2.component'; 4 | 5 | describe('SortV2Component', () => { 6 | let component: SortV2Component; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | declarations: [ SortV2Component ] 12 | }) 13 | .compileComponents(); 14 | }); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(SortV2Component); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /frontend/angular11/src/app/samples/meeting/meeting.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { MeetingComponent } from './meeting.component'; 4 | 5 | describe('MeetingComponent', () => { 6 | let component: MeetingComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | declarations: [ MeetingComponent ] 12 | }) 13 | .compileComponents(); 14 | }); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(MeetingComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /frontend/angular11/src/app/samples/speller/speller.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { SpellerComponent } from './speller.component'; 4 | 5 | describe('SpellerComponent', () => { 6 | let component: SpellerComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | declarations: [ SpellerComponent ] 12 | }) 13 | .compileComponents(); 14 | }); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(SpellerComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /frontend/angular11/src/app/samples/welcome/welcome.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { WelcomeComponent } from './welcome.component'; 4 | 5 | describe('WelcomeComponent', () => { 6 | let component: WelcomeComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | declarations: [ WelcomeComponent ] 12 | }) 13 | .compileComponents(); 14 | }); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(WelcomeComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /frontend/angular11/src/app/samples/semantic-label/semantic-label.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { SemanticLabelComponent } from './semantic-label.component'; 4 | 5 | describe('SemanticLabelComponent', () => { 6 | let component: SemanticLabelComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | declarations: [ SemanticLabelComponent ] 12 | }) 13 | .compileComponents(); 14 | }); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(SemanticLabelComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /frontend/angular11/src/app/samples/display-template/display-template.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { DisplayTemplateComponent } from './display-template.component'; 4 | 5 | describe('DisplayTemplateComponent', () => { 6 | let component: DisplayTemplateComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | declarations: [ DisplayTemplateComponent ] 12 | }) 13 | .compileComponents(); 14 | }); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(DisplayTemplateComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /frontend/angular11/src/test.ts: -------------------------------------------------------------------------------- 1 | // This file is required by karma.conf.js and loads recursively all the .spec and framework files 2 | 3 | import 'zone.js/dist/zone-testing'; 4 | import { getTestBed } from '@angular/core/testing'; 5 | import { 6 | BrowserDynamicTestingModule, 7 | platformBrowserDynamicTesting 8 | } from '@angular/platform-browser-dynamic/testing'; 9 | 10 | declare const require: { 11 | context(path: string, deep?: boolean, filter?: RegExp): { 12 | keys(): string[]; 13 | (id: string): T; 14 | }; 15 | }; 16 | 17 | // First, initialize the Angular testing environment. 18 | getTestBed().initTestEnvironment( 19 | BrowserDynamicTestingModule, 20 | platformBrowserDynamicTesting() 21 | ); 22 | // Then we find all the tests. 23 | const context = require.context('./', true, /\.spec\.ts$/); 24 | // And load the modules. 25 | context.keys().map(context); 26 | -------------------------------------------------------------------------------- /frontend/angular11/src/app/samples/semantic-label/semantic-label.component.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 |
col-12
10 |
---
11 |
col-12
12 |
13 | 14 |
15 |
col-12
16 |
---
17 |
col-12
18 |
19 | 20 |
21 |
col-12
22 |
---
23 |
col-12
24 |
25 | 26 |
27 | 28 |
29 | 30 | 31 |
32 | 33 | -------------------------------------------------------------------------------- /backend/Csharp/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json.schemastore.org/launchsettings.json", 3 | "iisSettings": { 4 | "windowsAuthentication": false, 5 | "anonymousAuthentication": true, 6 | "iisExpress": { 7 | "applicationUrl": "http://localhost:55508", 8 | "sslPort": 44383 9 | } 10 | }, 11 | "profiles": { 12 | "IIS Express": { 13 | "commandName": "IISExpress", 14 | "launchBrowser": true, 15 | "launchUrl": "swagger", 16 | "environmentVariables": { 17 | "ASPNETCORE_ENVIRONMENT": "Development" 18 | } 19 | }, 20 | "day30Sample": { 21 | "commandName": "Project", 22 | "dotnetRunMessages": "true", 23 | "launchBrowser": true, 24 | "launchUrl": "swagger", 25 | "applicationUrl": "https://localhost:5001;http://localhost:5000", 26 | "environmentVariables": { 27 | "ASPNETCORE_ENVIRONMENT": "Development" 28 | } 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /backend/Csharp/Controllers/EventController.cs: -------------------------------------------------------------------------------- 1 | using day30Sample.Helpers; 2 | using Microsoft.AspNetCore.Mvc; 3 | using Microsoft.Extensions.Logging; 4 | using Microsoft.Extensions.Primitives; 5 | using Microsoft.Graph; 6 | using System.Threading.Tasks; 7 | 8 | namespace day30Sample.Controllers 9 | { 10 | [Route("api/[controller]")] 11 | [ApiController] 12 | public class EventController : ControllerBase 13 | { 14 | private readonly ILogger _logger; 15 | 16 | public EventController(ILogger logger) 17 | { 18 | _logger = logger; 19 | } 20 | 21 | [HttpGet] 22 | public async Task GetAsync(string eventId) 23 | { 24 | eventId = eventId.Trim().Replace(" ", "+"); 25 | Request.Headers.TryGetValue("Custom-Token", out StringValues token); 26 | return await EventHelper.GetEventByEventId(eventId, token.ToString()); 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /frontend/angular11/src/app/samples/welcome/welcome.component.html: -------------------------------------------------------------------------------- 1 | 2 | Please go to Graph Explorer get a token, then set the token here. 3 |
4 | It will help you run the demo quickly. It's only for tests, please follow the guide below, config your authentication. 5 |
6 | Sample Login Please Refer more details from MSAL 7 | 8 | 9 | 10 |
-------------------------------------------------------------------------------- /backend/Csharp/Controllers/SearchController.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Mvc; 2 | using Microsoft.Extensions.Logging; 3 | using System.Threading.Tasks; 4 | using Microsoft.Graph; 5 | using day30Sample.helpers; 6 | using day30Sample.Model; 7 | using Microsoft.Extensions.Primitives; 8 | 9 | namespace day30Sample.Controllers 10 | { 11 | [Route("api/[controller]")] 12 | [ApiController] 13 | public class SearchController : ControllerBase 14 | { 15 | private readonly ILogger _logger; 16 | 17 | public SearchController(ILogger logger) 18 | { 19 | _logger = logger; 20 | } 21 | 22 | [HttpPost] 23 | public async Task PostAsync(SearchRequest searchRequest) 24 | { 25 | Request.Headers.TryGetValue("Custom-Token", out StringValues token); 26 | SearchResponse response = await SearchHelper.Search(searchRequest, token.ToString()); 27 | return response; 28 | } 29 | 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /frontend/angular11/src/assets/markdown/speller.md: -------------------------------------------------------------------------------- 1 | ```csharp 2 | GraphServiceClient graphClient = new GraphServiceClient(authProvider); 3 | 4 | SearchAlterationOptions searchAlterationOptions = new SearchAlterationOptions() 5 | { 6 | // Set it as false, will not return results when service get results from corrected word 7 | EnableModification = true, 8 | // Return the suggestion corrected search term 9 | EnableSuggestion = true 10 | }; 11 | 12 | SearchRequestObject searchRequestObject = new SearchRequestObject 13 | { 14 | EntityTypes = new List() 15 | { 16 | EntityType.DriveItem, // sample entity types, not only support them 17 | EntityType.List 18 | }, 19 | Query = new SearchQuery 20 | { 21 | QueryString = "informatino" // wrong search term with no results 22 | } 23 | }; 24 | var requests = new List() { searchRequestObject }; 25 | 26 | await graphClient.Search 27 | .Query(requests, searchAlterationOptions) 28 | .Request() 29 | .PostAsync(); 30 | ``` -------------------------------------------------------------------------------- /frontend/angular11/e2e/protractor.conf.js: -------------------------------------------------------------------------------- 1 | // @ts-check 2 | // Protractor configuration file, see link for more information 3 | // https://github.com/angular/protractor/blob/master/lib/config.ts 4 | 5 | const { SpecReporter, StacktraceOption } = require('jasmine-spec-reporter'); 6 | 7 | /** 8 | * @type { import("protractor").Config } 9 | */ 10 | exports.config = { 11 | allScriptsTimeout: 11000, 12 | specs: [ 13 | './src/**/*.e2e-spec.ts' 14 | ], 15 | capabilities: { 16 | browserName: 'chrome' 17 | }, 18 | directConnect: true, 19 | SELENIUM_PROMISE_MANAGER: false, 20 | baseUrl: 'http://localhost:4200/', 21 | framework: 'jasmine', 22 | jasmineNodeOpts: { 23 | showColors: true, 24 | defaultTimeoutInterval: 30000, 25 | print: function() {} 26 | }, 27 | onPrepare() { 28 | require('ts-node').register({ 29 | project: require('path').join(__dirname, './tsconfig.json') 30 | }); 31 | jasmine.getEnv().addReporter(new SpecReporter({ 32 | spec: { 33 | displayStacktrace: StacktraceOption.PRETTY 34 | } 35 | })); 36 | } 37 | }; -------------------------------------------------------------------------------- /backend/Csharp/Helpers/GraphSdkHelper.cs: -------------------------------------------------------------------------------- 1 | using day30Sample.helpers; 2 | using Microsoft.AspNetCore.Http; 3 | using Microsoft.Extensions.Configuration; 4 | using Microsoft.Graph; 5 | using Microsoft.Identity.Client; 6 | using System.Collections.Generic; 7 | using System.Net.Http.Headers; 8 | using System.Threading.Tasks; 9 | 10 | namespace day30Sample.Helpers 11 | { 12 | 13 | public static class GraphSdkHelper 14 | { 15 | // Mock way to get SDK Clients 16 | // Set a token here to test this demo. 17 | public static GraphServiceClient GetAuthenticatedGraphClient(string token) 18 | { 19 | var graphClient = new GraphServiceClient( 20 | new DelegateAuthenticationProvider( 21 | (requestMessage) => 22 | { 23 | requestMessage.Headers.Authorization = 24 | new AuthenticationHeaderValue("Bearer", token); 25 | return Task.FromResult(0); 26 | }) 27 | ); 28 | return graphClient; 29 | } 30 | 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Microsoft Graph 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /frontend/angular11/README.md: -------------------------------------------------------------------------------- 1 | # FrontEnd 2 | 3 | This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 11.0.6. 4 | 5 | ## Development server 6 | 7 | Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The app will automatically reload if you change any of the source files. 8 | 9 | ## Code scaffolding 10 | 11 | Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module`. 12 | 13 | ## Build 14 | 15 | Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory. Use the `--prod` flag for a production build. 16 | 17 | ## Running unit tests 18 | 19 | Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io). 20 | 21 | ## Running end-to-end tests 22 | 23 | Run `ng e2e` to execute the end-to-end tests via [Protractor](http://www.protractortest.org/). 24 | 25 | ## Further help 26 | 27 | To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI Overview and Command Reference](https://angular.io/cli) page. 28 | 29 | 30 | Test -------------------------------------------------------------------------------- /backend/Csharp/day30Sample.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.31205.134 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "day30Sample", "day30Sample.csproj", "{23081183-A074-4DA2-AF09-56AEE9744082}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {23081183-A074-4DA2-AF09-56AEE9744082}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {23081183-A074-4DA2-AF09-56AEE9744082}.Debug|Any CPU.Build.0 = Debug|Any CPU 16 | {23081183-A074-4DA2-AF09-56AEE9744082}.Release|Any CPU.ActiveCfg = Release|Any CPU 17 | {23081183-A074-4DA2-AF09-56AEE9744082}.Release|Any CPU.Build.0 = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | GlobalSection(ExtensibilityGlobals) = postSolution 23 | SolutionGuid = {A69DAF00-73D1-4F95-ABC2-668BDC7B3548} 24 | EndGlobalSection 25 | EndGlobal 26 | -------------------------------------------------------------------------------- /frontend/angular11/src/app/samples/sort-v2/sort-v2.component.scss: -------------------------------------------------------------------------------- 1 | .sort-item-list { 2 | width: 500px; 3 | div { 4 | max-width: 240px; 5 | float: left; 6 | height: 40px; 7 | line-height: 40px; 8 | //border: solid 1px black; 9 | /* px em rem vh vw cal() */ 10 | } 11 | } 12 | 13 | .sort-options { 14 | width: 500px; 15 | div { 16 | max-width: 240px; 17 | height: 40px; 18 | line-height: 40px; 19 | //border: solid 1px black; 20 | /* px em rem vh vw cal() */ 21 | } 22 | } 23 | 24 | .item-list { 25 | width: 1000px; 26 | div { 27 | font-size: 13px; 28 | width: 20%; 29 | max-width: 240px; 30 | float: left; 31 | //height: 80px; 32 | //line-height: 40px; 33 | display: flex; 34 | //border: solid 1px black; 35 | /* px em rem vh vw cal() */ 36 | position: relative; 37 | } 38 | clear: both; 39 | } 40 | 41 | .fieldInput { 42 | width: 200px; 43 | } 44 | 45 | .dynamic-add-button:hover { 46 | color: #777; 47 | border: solid 1px black; 48 | height: 40px; 49 | line-height: 40px; 50 | } 51 | 52 | .highlightText { 53 | background: yellow; 54 | } 55 | 56 | .plus-icon{ 57 | color: #66ccff; 58 | font-size: 20px; 59 | font-weight: 600; 60 | margin-left: 15px; 61 | padding-top: 13px; 62 | &:hover{ 63 | cursor: pointer; 64 | color: orange; 65 | } 66 | } -------------------------------------------------------------------------------- /frontend/angular11/src/app/samples/semantic-label/semantic-label.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import { CommonService } from 'src/app/service/common.service'; 3 | 4 | @Component({ 5 | selector: 'app-semantic-label', 6 | templateUrl: './semantic-label.component.html', 7 | styleUrls: ['./semantic-label.component.scss'] 8 | }) 9 | export class SemanticLabelComponent implements OnInit { 10 | isSpinning = false; 11 | entityTypes = ['list', 'driveItem']; 12 | 13 | constructor(private commonService: CommonService) {} 14 | 15 | ngOnInit(): void {} 16 | 17 | loading = false; 18 | 19 | searchInput1 = ''; 20 | 21 | showConfiguration = false; 22 | 23 | data: any; 24 | 25 | encodeUri(input: string): string { 26 | return encodeURI(input); 27 | } 28 | 29 | executeSearch(input: string) { 30 | if (this.searchInput1 == '') { 31 | alert('Search term cannot be empty'); 32 | return; 33 | } 34 | this.isSpinning = true; 35 | this.commonService 36 | .Search(this.searchInput1, this.entityTypes) 37 | .subscribe((data) => { 38 | this.data = data; 39 | this.isSpinning = false; 40 | }, error=>{ 41 | this.isSpinning = false; 42 | alert(error["message"]); 43 | }); 44 | } 45 | 46 | setEntityTypes(value: string[]): void { 47 | this.entityTypes = value; 48 | } 49 | 50 | configOpen(): void { 51 | this.showConfiguration = true; 52 | } 53 | 54 | configClose(): void { 55 | this.showConfiguration = false; 56 | } 57 | 58 | getMockData(){} 59 | } 60 | -------------------------------------------------------------------------------- /frontend/angular11/karma.conf.js: -------------------------------------------------------------------------------- 1 | // Karma configuration file, see link for more information 2 | // https://karma-runner.github.io/1.0/config/configuration-file.html 3 | 4 | module.exports = function (config) { 5 | config.set({ 6 | basePath: '', 7 | frameworks: ['jasmine', '@angular-devkit/build-angular'], 8 | plugins: [ 9 | require('karma-jasmine'), 10 | require('karma-chrome-launcher'), 11 | require('karma-jasmine-html-reporter'), 12 | require('karma-coverage'), 13 | require('@angular-devkit/build-angular/plugins/karma') 14 | ], 15 | client: { 16 | jasmine: { 17 | // you can add configuration options for Jasmine here 18 | // the possible options are listed at https://jasmine.github.io/api/edge/Configuration.html 19 | // for example, you can disable the random execution with `random: false` 20 | // or set a specific seed with `seed: 4321` 21 | }, 22 | clearContext: false // leave Jasmine Spec Runner output visible in browser 23 | }, 24 | jasmineHtmlReporter: { 25 | suppressAll: true // removes the duplicated traces 26 | }, 27 | coverageReporter: { 28 | dir: require('path').join(__dirname, './coverage/front-end'), 29 | subdir: '.', 30 | reporters: [ 31 | { type: 'html' }, 32 | { type: 'text-summary' } 33 | ] 34 | }, 35 | reporters: ['progress', 'kjhtml'], 36 | port: 9876, 37 | colors: true, 38 | logLevel: config.LOG_INFO, 39 | autoWatch: true, 40 | browsers: ['Chrome'], 41 | singleRun: false, 42 | restartOnFileChange: true 43 | }); 44 | }; 45 | -------------------------------------------------------------------------------- /frontend/angular11/src/app/app-routing.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { Routes, RouterModule } from '@angular/router'; 3 | import { CommonComponent } from './samples/common/common.component'; 4 | import { DisplayTemplateComponent } from './samples/display-template/display-template.component'; 5 | import { MeetingComponent } from './samples/meeting/meeting.component'; 6 | import { SemanticLabelComponent } from './samples/semantic-label/semantic-label.component'; 7 | import { SortV2Component } from './samples/sort-v2/sort-v2.component'; 8 | import { SortComponent } from './samples/sort/sort.component'; 9 | import { SpellerComponent } from './samples/speller/speller.component'; 10 | import { WelcomeComponent } from './samples/welcome/welcome.component'; 11 | 12 | const routes: Routes = [ 13 | { path: '', pathMatch: 'full', redirectTo: 'welcome' }, 14 | { path: 'common', pathMatch: 'full', component: CommonComponent }, 15 | { path: 'meeting', pathMatch: 'full', component: MeetingComponent }, 16 | //{ path: 'sort', pathMatch: 'full', component:SortComponent }, 17 | { path: 'sort', pathMatch: 'full', component: SortV2Component }, 18 | { path: 'welcome', pathMatch: 'full', component: WelcomeComponent }, 19 | { path: 'speller', pathMatch: 'full', component: SpellerComponent }, 20 | { path: 'semanticLabel', pathMatch: 'full', component: SemanticLabelComponent }, 21 | { path: 'displayTemplate', pathMatch: 'full', component: DisplayTemplateComponent }, 22 | ]; 23 | 24 | @NgModule({ 25 | imports: [RouterModule.forRoot(routes)], 26 | exports: [RouterModule], 27 | }) 28 | export class AppRoutingModule {} 29 | -------------------------------------------------------------------------------- /frontend/angular11/src/app/app.component.scss: -------------------------------------------------------------------------------- 1 | :host { 2 | display: flex; 3 | text-rendering: optimizeLegibility; 4 | -webkit-font-smoothing: antialiased; 5 | -moz-osx-font-smoothing: grayscale; 6 | } 7 | 8 | .app-layout { 9 | height: 100vh; 10 | } 11 | 12 | .menu-sidebar { 13 | position: relative; 14 | z-index: 10; 15 | min-height: 100vh; 16 | box-shadow: 2px 0 6px rgba(0, 21, 41, 0.35); 17 | } 18 | 19 | .header-trigger { 20 | height: 64px; 21 | padding: 20px 24px; 22 | font-size: 20px; 23 | cursor: pointer; 24 | transition: all 0.3s, padding 0s; 25 | } 26 | 27 | .trigger:hover { 28 | color: #1890ff; 29 | } 30 | 31 | .sidebar-logo { 32 | position: relative; 33 | height: 64px; 34 | padding-left: 24px; 35 | overflow: hidden; 36 | line-height: 64px; 37 | background: #001529; 38 | transition: all 0.3s; 39 | } 40 | 41 | .sidebar-logo img { 42 | display: inline-block; 43 | height: 28px; 44 | width: 32px; 45 | vertical-align: middle; 46 | } 47 | 48 | .sidebar-logo h1 { 49 | display: inline-block; 50 | margin: 0 0 0 20px; 51 | color: #fff; 52 | font-weight: 600; 53 | font-size: 14px; 54 | font-family: Avenir, Helvetica Neue, Arial, Helvetica, sans-serif; 55 | vertical-align: middle; 56 | } 57 | 58 | nz-header { 59 | padding: 0; 60 | width: 100%; 61 | z-index: 2; 62 | } 63 | 64 | .app-header { 65 | position: relative; 66 | height: 64px; 67 | padding: 0; 68 | background: #fff; 69 | box-shadow: 0 1px 4px rgba(0, 21, 41, 0.08); 70 | } 71 | 72 | nz-content { 73 | margin: 24px; 74 | } 75 | 76 | .inner-content { 77 | padding: 24px; 78 | background: #fff; 79 | height: 100%; 80 | } 81 | -------------------------------------------------------------------------------- /frontend/angular11/src/app/samples/common/common.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import { CommonService } from 'src/app/service/common.service'; 3 | 4 | @Component({ 5 | selector: 'app-common', 6 | templateUrl: './common.component.html', 7 | styleUrls: ['./common.component.scss'], 8 | }) 9 | export class CommonComponent implements OnInit { 10 | isSpinning = false; 11 | entityTypes = ['list', 'driveItem']; 12 | 13 | constructor(private commonService: CommonService) {} 14 | 15 | ngOnInit(): void {} 16 | 17 | loading = false; 18 | 19 | showCode = false; 20 | 21 | searchInput1 = ''; 22 | 23 | showConfiguration = false; 24 | 25 | data: any; 26 | 27 | encodeUri(input: string): string { 28 | return encodeURI(input); 29 | } 30 | 31 | executeSearch(input: string) { 32 | if (this.searchInput1 == '') { 33 | alert('Search term cannot be empty'); 34 | return; 35 | } 36 | this.isSpinning = true; 37 | this.commonService 38 | .Search(this.searchInput1, this.entityTypes) 39 | .subscribe((data) => { 40 | this.data = data; 41 | this.isSpinning = false; 42 | }, error=>{ 43 | this.isSpinning = false; 44 | alert(error["message"]); 45 | }); 46 | } 47 | 48 | setEntityTypes(value: string[]): void { 49 | this.entityTypes = value; 50 | } 51 | 52 | configOpen(): void { 53 | this.showConfiguration = true; 54 | } 55 | 56 | configClose(): void { 57 | this.showConfiguration = false; 58 | } 59 | 60 | codeOpen(): void { 61 | this.showCode = true; 62 | } 63 | 64 | codeClose(): void { 65 | this.showCode = false; 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /frontend/angular11/src/app/app.component.html: -------------------------------------------------------------------------------- 1 | 3 | 9 |
    10 |
  • 11 | 55 |
  • 56 |
57 |
58 | 59 | 60 |
61 | 62 |
63 |
-------------------------------------------------------------------------------- /frontend/angular11/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "front-end", 3 | "version": "0.0.0", 4 | "scripts": { 5 | "ng": "ng", 6 | "start": "ng serve", 7 | "build": "ng build", 8 | "test": "ng test", 9 | "lint": "ng lint", 10 | "e2e": "ng e2e" 11 | }, 12 | "private": true, 13 | "dependencies": { 14 | "@angular/animations": "~11.0.6", 15 | "@angular/common": "~11.0.6", 16 | "@angular/compiler": "~11.0.6", 17 | "@angular/core": "~11.0.6", 18 | "@angular/forms": "~11.0.6", 19 | "@angular/platform-browser": "~11.0.6", 20 | "@angular/platform-browser-dynamic": "~11.0.6", 21 | "@angular/router": "~11.0.6", 22 | "@azure/msal-angular": "^2.0.0", 23 | "@azure/msal-browser": "^2.14.2", 24 | "adaptivecards": "^2.9.0", 25 | "adaptivecards-templating": "0.1.0-alpha1", 26 | "markdown-it": "^8.4.0", 27 | "msal": "^1.4.11", 28 | "ng-zorro-antd": "^11.4.0", 29 | "ngx-markdown": "^11.1.3", 30 | "prismjs": "^1.23.0", 31 | "rxjs": "~6.6.0", 32 | "tslib": "^2.0.0", 33 | "zone.js": "~0.10.2" 34 | }, 35 | "devDependencies": { 36 | "@angular-devkit/build-angular": "~0.1100.6", 37 | "@angular/cli": "~11.0.6", 38 | "@angular/compiler-cli": "~11.0.6", 39 | "@types/jasmine": "~3.6.0", 40 | "@types/node": "^12.11.1", 41 | "codelyzer": "^6.0.0", 42 | "jasmine-core": "~3.6.0", 43 | "jasmine-spec-reporter": "~5.0.0", 44 | "karma": "^6.3.2", 45 | "karma-chrome-launcher": "~3.1.0", 46 | "karma-coverage": "~2.0.3", 47 | "karma-jasmine": "~4.0.0", 48 | "karma-jasmine-html-reporter": "^1.5.0", 49 | "protractor": "~7.0.0", 50 | "ts-node": "~8.3.0", 51 | "tslint": "~6.1.0", 52 | "typescript": "~4.0.2" 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /backend/Csharp/Startup.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Builder; 2 | using Microsoft.AspNetCore.Hosting; 3 | using Microsoft.AspNetCore.Http; 4 | using Microsoft.Extensions.Configuration; 5 | using Microsoft.Extensions.DependencyInjection; 6 | using Microsoft.Extensions.Hosting; 7 | using Microsoft.OpenApi.Models; 8 | using System; 9 | 10 | namespace day30Sample 11 | { 12 | public class Startup 13 | { 14 | public Startup(IConfiguration configuration) 15 | { 16 | Configuration = configuration; 17 | } 18 | 19 | public IConfiguration Configuration { get; } 20 | 21 | // This method gets called by the runtime. Use this method to add services to the container. 22 | public void ConfigureServices(IServiceCollection services) 23 | { 24 | 25 | services.AddCors(options => 26 | { 27 | options.AddPolicy("default", policy => 28 | { 29 | policy.WithOrigins("http://localhost:4200") 30 | .AllowAnyHeader() 31 | .AllowAnyMethod() 32 | .AllowCredentials(); 33 | }); 34 | }); 35 | services.AddControllers(); 36 | services.AddSwaggerGen(c => 37 | { 38 | c.SwaggerDoc("v1", new OpenApiInfo { Title = "day30Sample", Version = "v1" }); 39 | }); 40 | } 41 | 42 | // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. 43 | public void Configure(IApplicationBuilder app, IWebHostEnvironment env) 44 | { 45 | if (env.IsDevelopment()) 46 | { 47 | app.UseDeveloperExceptionPage(); 48 | app.UseSwagger(); 49 | app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "day30Sample v1")); 50 | } 51 | 52 | app.UseHttpsRedirection(); 53 | 54 | app.UseRouting(); 55 | 56 | app.UseCors("default"); 57 | 58 | app.UseAuthorization(); 59 | 60 | app.UseEndpoints(endpoints => 61 | { 62 | endpoints.MapControllers(); 63 | }); 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /frontend/angular11/src/app/samples/speller/speller.component.ts: -------------------------------------------------------------------------------- 1 | import { stringify } from '@angular/compiler/src/util'; 2 | import { Component, OnInit } from '@angular/core'; 3 | import { CommonService } from 'src/app/service/common.service'; 4 | 5 | @Component({ 6 | selector: 'app-speller', 7 | templateUrl: './speller.component.html', 8 | styleUrls: ['./speller.component.scss'] 9 | }) 10 | export class SpellerComponent implements OnInit { 11 | isSpinning = false; 12 | entityTypes = ['message']; 13 | 14 | constructor(private commonService: CommonService) {} 15 | 16 | ngOnInit(): void {} 17 | 18 | loading = false; 19 | 20 | showCode = false; 21 | 22 | searchInput = ''; 23 | 24 | spellerSuggestion = ""; 25 | 26 | showCorrect = false; 27 | 28 | enableModification = true; 29 | 30 | showConfiguration = false; 31 | 32 | data: any; 33 | 34 | encodeUri(input: string): string { 35 | if(input == 'undefined' || input == "" ) return null; 36 | return encodeURI(input); 37 | } 38 | 39 | executeSearch(input: string) { 40 | if (this.searchInput == '') { 41 | alert('Search term cannot be empty'); 42 | return; 43 | } 44 | this.isSpinning = true; 45 | this.commonService 46 | .SearchWithSpeller(this.searchInput, this.entityTypes, this.enableModification) 47 | .subscribe((data) => { 48 | this.data = data; 49 | this.isSpinning = false; 50 | console.log(data); 51 | this.spellerSuggestion = this.data["queryAlterationResponse"]["queryAlteration"]["alteredQueryString"]; 52 | if(this.spellerSuggestion.toLocaleLowerCase() != this.searchInput.toLocaleLowerCase()){ 53 | this.showCorrect = true; 54 | }else{ 55 | this.showCorrect = false; 56 | } 57 | 58 | }, error=>{ 59 | this.isSpinning = false; 60 | alert(error["message"]); 61 | }); 62 | } 63 | 64 | excuteRawSearch(){ 65 | this.enableModification = false; 66 | } 67 | 68 | setEntityTypes(value: string[]): void { 69 | this.entityTypes = value; 70 | } 71 | 72 | configOpen(): void { 73 | this.showConfiguration = true; 74 | } 75 | 76 | configClose(): void { 77 | this.showConfiguration = false; 78 | } 79 | 80 | codeOpen(): void { 81 | this.showCode = true; 82 | } 83 | 84 | codeClose(): void { 85 | this.showCode = false; 86 | } 87 | 88 | 89 | 90 | } 91 | -------------------------------------------------------------------------------- /frontend/angular11/src/app/samples/sort/sort.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import { CommonService } from 'src/app/service/common.service'; 3 | 4 | @Component({ 5 | selector: 'app-sort', 6 | templateUrl: './sort.component.html', 7 | styleUrls: ['./sort.component.scss'], 8 | }) 9 | export class SortComponent implements OnInit { 10 | isSpinning = false; 11 | entityTypes = ['list', 'driveItem']; 12 | 13 | constructor(private commonService: CommonService) {} 14 | 15 | ngOnInit(): void {} 16 | 17 | loading = false; 18 | 19 | searchInput1 = ''; 20 | 21 | showConfiguration = false; 22 | 23 | sortPropertiesList = [ 24 | { value: 'Created', label: 'Created' }, 25 | { value: 'Summary', label: 'Summary' }, 26 | { value: 'displayName', label: 'displayName' }, 27 | { value: 'id', label: 'id' }, 28 | { value: 'lastModifiedDateTime', label: 'lastModifiedDateTime' }, 29 | ]; 30 | 31 | selectedASCSortPropertiesList: string[] = ['Created', 'Summary']; 32 | 33 | selectedDESCSortPropertiesList: string[] = []; 34 | 35 | data: any; 36 | 37 | encodeUri(input: string): string { 38 | return encodeURI(input); 39 | } 40 | 41 | executeSearch1(input: string) { 42 | if (this.searchInput1 == '') { 43 | alert('Search term cannot be empty'); 44 | return; 45 | } 46 | 47 | var intersection: string[] = this.selectedASCSortPropertiesList.filter( 48 | (x) => this.selectedDESCSortPropertiesList.indexOf(x) > -1 49 | ); 50 | 51 | if (intersection.length > 0) { 52 | alert('Fields cannot included in desc and asc list at same time'); 53 | return; 54 | } 55 | 56 | this.isSpinning = true; 57 | this.commonService 58 | .Search( 59 | this.searchInput1, 60 | this.entityTypes, 61 | this.selectedASCSortPropertiesList 62 | ) 63 | .subscribe((data) => { 64 | this.data = data; 65 | this.isSpinning = false; 66 | }); 67 | } 68 | 69 | setEntityTypes(value: string[]): void { 70 | this.entityTypes = value; 71 | } 72 | 73 | configOpen(): void { 74 | this.showConfiguration = true; 75 | } 76 | 77 | configClose(): void { 78 | this.showConfiguration = false; 79 | } 80 | 81 | select(ret: {}): void { 82 | console.log('nzSelectChange', ret); 83 | } 84 | 85 | change(ret: {}): void { 86 | console.log('nzChange', ret); 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /frontend/angular11/src/polyfills.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * This file includes polyfills needed by Angular and is loaded before the app. 3 | * You can add your own extra polyfills to this file. 4 | * 5 | * This file is divided into 2 sections: 6 | * 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers. 7 | * 2. Application imports. Files imported after ZoneJS that should be loaded before your main 8 | * file. 9 | * 10 | * The current setup is for so-called "evergreen" browsers; the last versions of browsers that 11 | * automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera), 12 | * Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile. 13 | * 14 | * Learn more in https://angular.io/guide/browser-support 15 | */ 16 | 17 | /*************************************************************************************************** 18 | * BROWSER POLYFILLS 19 | */ 20 | 21 | /** IE11 requires the following for NgClass support on SVG elements */ 22 | // import 'classlist.js'; // Run `npm install --save classlist.js`. 23 | 24 | /** 25 | * Web Animations `@angular/platform-browser/animations` 26 | * Only required if AnimationBuilder is used within the application and using IE/Edge or Safari. 27 | * Standard animation support in Angular DOES NOT require any polyfills (as of Angular 6.0). 28 | */ 29 | // import 'web-animations-js'; // Run `npm install --save web-animations-js`. 30 | 31 | /** 32 | * By default, zone.js will patch all possible macroTask and DomEvents 33 | * user can disable parts of macroTask/DomEvents patch by setting following flags 34 | * because those flags need to be set before `zone.js` being loaded, and webpack 35 | * will put import in the top of bundle, so user need to create a separate file 36 | * in this directory (for example: zone-flags.ts), and put the following flags 37 | * into that file, and then add the following code before importing zone.js. 38 | * import './zone-flags'; 39 | * 40 | * The flags allowed in zone-flags.ts are listed here. 41 | * 42 | * The following flags will work for all browsers. 43 | * 44 | * (window as any).__Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame 45 | * (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick 46 | * (window as any).__zone_symbol__UNPATCHED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames 47 | * 48 | * in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js 49 | * with the following flag, it will bypass `zone.js` patch for IE/Edge 50 | * 51 | * (window as any).__Zone_enable_cross_context_check = true; 52 | * 53 | */ 54 | 55 | /*************************************************************************************************** 56 | * Zone JS is required by default for Angular itself. 57 | */ 58 | import 'zone.js/dist/zone'; // Included with Angular CLI. 59 | 60 | 61 | /*************************************************************************************************** 62 | * APPLICATION IMPORTS 63 | */ 64 | -------------------------------------------------------------------------------- /frontend/angular11/src/app/samples/display-template/display-template.component.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 | 19 | 20 | 21 | 22 | 23 |
24 |
25 | 26 | 27 | 28 |
29 | 30 | 31 | 32 |
33 | 34 |
35 |
36 |
37 | 38 |
39 | 40 | 41 |
42 | 43 | 44 | Display Layouts 45 | 46 | 47 |
48 | 49 | 50 |
51 | 52 | 53 | 54 | 56 | 57 | 58 | 59 |
60 | 61 | 62 | Entity Types 63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 | 73 |
74 |
75 | 76 | 79 | 80 | 82 | 83 | 84 | 85 | -------------------------------------------------------------------------------- /frontend/angular11/src/app/samples/meeting/meeting.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit, ViewChild } from '@angular/core'; 2 | import { NzDatePickerComponent } from 'ng-zorro-antd/date-picker'; 3 | import { CommonService } from 'src/app/service/common.service'; 4 | 5 | @Component({ 6 | selector: 'app-meeting', 7 | templateUrl: './meeting.component.html', 8 | styleUrls: ['./meeting.component.scss'], 9 | }) 10 | export class MeetingComponent implements OnInit { 11 | SearchEvent1 = true; 12 | 13 | // Control 14 | showMeetingParticipates; 15 | 16 | showCode = false; 17 | 18 | peopleLoading = false; 19 | 20 | mockEventdata1: any[] = []; 21 | 22 | mockMeetingDetails: any = {}; 23 | 24 | constructor(private commonService: CommonService) {} 25 | 26 | ngOnInit(): void {} 27 | 28 | isSpinning = false; 29 | searchTerms: string = ''; 30 | showConfiguration = false; 31 | 32 | public getMonthAndDay(date: string): string { 33 | return date.substr(0, 10); 34 | } 35 | 36 | public getHourAndMinutes(date: string): string { 37 | return date.substring(11, 16); 38 | } 39 | 40 | meetingOpen(data: any): void { 41 | this.isSpinning = true; 42 | this.commonService.getMeetingDetails(data.hitId).subscribe( 43 | (data) => { 44 | this.isSpinning = false; 45 | this.showMeetingParticipates = true; 46 | this.mockMeetingDetails = data; 47 | }, 48 | (error) => { 49 | this.isSpinning = false; 50 | alert(error['message']); 51 | } 52 | ); 53 | } 54 | 55 | meetingClose(): void { 56 | this.showMeetingParticipates = false; 57 | } 58 | 59 | executeSearchEvent(): void { 60 | if (this.searchTerms == '') { 61 | alert('Search term cannot be empty'); 62 | return; 63 | } 64 | this.isSpinning = true; 65 | this.commonService 66 | .SearchMeeting(this.searchTerms, this.startValue, this.endValue) 67 | .subscribe( 68 | (data) => { 69 | this.mockEventdata1 = data['value'][0]['hitsContainers'][0]['hits']; 70 | this.isSpinning = false; 71 | }, 72 | (error) => { 73 | this.isSpinning = false; 74 | alert(error['message']); 75 | } 76 | ); 77 | } 78 | 79 | configOpen(): void { 80 | this.showConfiguration = true; 81 | } 82 | 83 | configClose(): void { 84 | this.showConfiguration = false; 85 | } 86 | 87 | startValue: Date | null = null; 88 | endValue: Date | null = null; 89 | @ViewChild('endDatePicker') endDatePicker!: NzDatePickerComponent; 90 | 91 | disabledStartDate = (startValue: Date): boolean => { 92 | if (!startValue || !this.endValue) { 93 | return false; 94 | } 95 | return startValue.getTime() > this.endValue.getTime(); 96 | }; 97 | 98 | disabledEndDate = (endValue: Date): boolean => { 99 | if (!endValue || !this.startValue) { 100 | return false; 101 | } 102 | return endValue.getTime() <= this.startValue.getTime(); 103 | }; 104 | 105 | handleStartOpenChange(open: boolean): void { 106 | if (!open) { 107 | this.endDatePicker.open(); 108 | } 109 | console.log('handleStartOpenChange', open); 110 | } 111 | 112 | handleEndOpenChange(open: boolean): void { 113 | console.log('handleEndOpenChange', open); 114 | } 115 | 116 | showDateRange() { 117 | console.log(this.startValue, this.endValue); 118 | } 119 | 120 | codeOpen(): void { 121 | this.showCode = true; 122 | } 123 | 124 | codeClose(): void { 125 | this.showCode = false; 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /frontend/angular11/src/app/samples/common/common.component.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 | 20 | 21 | 22 | 23 | 24 |
25 |
26 | 27 | 28 | 29 |
30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | {{ item.resource.name }} 43 | 44 | 45 | 46 | 47 | {{ encodeUri(item.resource.webUrl) }} 48 |
49 | Last modified by {{item.resource.lastModifiedBy.user.displayName}} 50 |
51 | in {{item.resource.lastModifiedDateTime}} 52 | 53 |
54 | 55 |
56 |
57 | 58 |
59 | 60 |
61 | 62 | 63 |
64 | 65 |
66 | 67 | 68 |
69 | 70 | 71 | 72 | 74 | 75 | 76 | 77 |
78 | 79 | 80 | Entity Types 81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 | 91 |
92 |
93 | 94 | 95 | 98 | 99 | 101 | 102 | 103 | 104 | -------------------------------------------------------------------------------- /frontend/angular11/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "tslint:recommended", 3 | "rulesDirectory": [ 4 | "codelyzer" 5 | ], 6 | "rules": { 7 | "align": { 8 | "options": [ 9 | "parameters", 10 | "statements" 11 | ] 12 | }, 13 | "array-type": false, 14 | "arrow-return-shorthand": true, 15 | "curly": true, 16 | "deprecation": { 17 | "severity": "warning" 18 | }, 19 | "eofline": true, 20 | "import-blacklist": [ 21 | true, 22 | "rxjs/Rx" 23 | ], 24 | "import-spacing": true, 25 | "indent": { 26 | "options": [ 27 | "spaces" 28 | ] 29 | }, 30 | "max-classes-per-file": false, 31 | "max-line-length": [ 32 | true, 33 | 140 34 | ], 35 | "member-ordering": [ 36 | true, 37 | { 38 | "order": [ 39 | "static-field", 40 | "instance-field", 41 | "static-method", 42 | "instance-method" 43 | ] 44 | } 45 | ], 46 | "no-console": [ 47 | true, 48 | "debug", 49 | "info", 50 | "time", 51 | "timeEnd", 52 | "trace" 53 | ], 54 | "no-empty": false, 55 | "no-inferrable-types": [ 56 | true, 57 | "ignore-params" 58 | ], 59 | "no-non-null-assertion": true, 60 | "no-redundant-jsdoc": true, 61 | "no-switch-case-fall-through": true, 62 | "no-var-requires": false, 63 | "object-literal-key-quotes": [ 64 | true, 65 | "as-needed" 66 | ], 67 | "quotemark": [ 68 | true, 69 | "single" 70 | ], 71 | "semicolon": { 72 | "options": [ 73 | "always" 74 | ] 75 | }, 76 | "space-before-function-paren": { 77 | "options": { 78 | "anonymous": "never", 79 | "asyncArrow": "always", 80 | "constructor": "never", 81 | "method": "never", 82 | "named": "never" 83 | } 84 | }, 85 | "typedef": [ 86 | true, 87 | "call-signature" 88 | ], 89 | "typedef-whitespace": { 90 | "options": [ 91 | { 92 | "call-signature": "nospace", 93 | "index-signature": "nospace", 94 | "parameter": "nospace", 95 | "property-declaration": "nospace", 96 | "variable-declaration": "nospace" 97 | }, 98 | { 99 | "call-signature": "onespace", 100 | "index-signature": "onespace", 101 | "parameter": "onespace", 102 | "property-declaration": "onespace", 103 | "variable-declaration": "onespace" 104 | } 105 | ] 106 | }, 107 | "variable-name": { 108 | "options": [ 109 | "ban-keywords", 110 | "check-format", 111 | "allow-pascal-case" 112 | ] 113 | }, 114 | "whitespace": { 115 | "options": [ 116 | "check-branch", 117 | "check-decl", 118 | "check-operator", 119 | "check-separator", 120 | "check-type", 121 | "check-typecast" 122 | ] 123 | }, 124 | "component-class-suffix": true, 125 | "contextual-lifecycle": true, 126 | "directive-class-suffix": true, 127 | "no-conflicting-lifecycle": true, 128 | "no-host-metadata-property": true, 129 | "no-input-rename": true, 130 | "no-inputs-metadata-property": true, 131 | "no-output-native": true, 132 | "no-output-on-prefix": true, 133 | "no-output-rename": true, 134 | "no-outputs-metadata-property": true, 135 | "template-banana-in-box": true, 136 | "template-no-negated-async": true, 137 | "use-lifecycle-interface": true, 138 | "use-pipe-transform-interface": true, 139 | "directive-selector": [ 140 | true, 141 | "attribute", 142 | "app", 143 | "camelCase" 144 | ], 145 | "component-selector": [ 146 | true, 147 | "element", 148 | "app", 149 | "kebab-case" 150 | ] 151 | } 152 | } 153 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Use the Microsoft Search API to query data 2 | 3 | This sample was added after the 30 Days of Microsoft Graph blog series and as such has limited documentation. The key points to note: 4 | - [Prerequisites](#prerequisites) 5 | - [Step 1: Start Backend](#step-1-start-backend) 6 | - [Step 2: Start Frontend](#step-2-start-frontend) 7 | - [Step 3: Try the demo](#step-3-try-the-demo) 8 | ## Prerequisites 9 | - Permissions required 10 | - Delegated (work or school account) 11 | - Mail.Read, Mail.ReadWrite, Calendars.Read, Calendars.ReadWrite, Files.Read.All, Files.ReadWrite.All, Sites.Read.All, Sites.ReadWrite.All, ExternalItem.Read.All 12 | - [Visual Studio Code](https://code.visualstudio.com/) installed on your development machine. If you do not have Visual Studio Code, visit the previous link for download options. (**Note:** This tutorial was written with Visual Studio Code version 1.55.2. The steps in this guide may work with other versions, but that has not been tested.) 13 | - [Visual Studio](https://visualstudio.microsoft.com/). (**Note** This tutorial was written with Visual Studio 2019. The steps in this guide may work with other versions, but that has not been tested.), when start installation, please: 14 | - Make sure you installed the **ASP.NET & web development** under the **Web & Cloud** 15 | - Make sure you installed **.Net desktop development** under the **Desktop & Mobile** 16 | - If you want to extend authentication, please refer [the guides](https://github.com/microsoftgraph/dotnetcore-console-sample/tree/main/day29-onedrive) before or try to use this [MSAL sample](https://github.com/AzureAD/microsoft-authentication-library-for-js/tree/dev/samples/msal-angular-v2-samples/angular11-sample-app) or go to [Azure Document](https://docs.microsoft.com/azure/active-directory/fundamentals/auth-oidc) for getting auth helps. In this guide, please ensure you have a way to get a token for accessing graph endpoint. Try [Graph Explorer](https://developer.microsoft.com/graph/graph-explorer) and got a token from there. 17 | ![Screenshot of getting a token from graph explorer](Images/Token.PNG) 18 | 19 | - [Nodejs](https://nodejs.org/en/) This tutorial was written with NodeJS version 14.15.4. Please click the link then install the nodeJS 20 | 21 | 22 | ## Step 1: Start Backend 23 | 24 | ### Double click **day30Sample.sln** under the **backend/Csharp/day30Sample** 25 | ### Open Package Manager 26 | ![Screenshot of opening package manager](Images/VisualStudio_PackageManager.PNG), type below and enter 27 | ``` 28 | dotnet restore 29 | ``` 30 | ### Run Project 31 | ![Screenshot of running project](Images/VisualStudio_Run.PNG) 32 | 33 | ### After starting the backend, you will see below and please keep the browser window. 34 | ![Screenshot of backend demo](Images/Backend_demo.PNG) 35 | 36 | 37 | ## Step 2: Start Frontend 38 | 39 | ### Open commandline on your PC 40 | run command below: 41 | ``` 42 | npm install -g @angular/cli 43 | ``` 44 | 45 | - Open Visual Studio Code, and import frontend project. 46 | - 47 | ![Screenshot of importing frontend project](Images/Import_frontend.PNG) 48 | 49 | ### Open a Terminal in Visual Studio Code 50 | 51 | ![Screenshot of terminal](Images/OpenTerminal.PNG) 52 | 53 | ### Run npm install in the terminal as below, it will take a little long time: 54 | 55 | ![Screenshot of installing frontend](Images/Install_fronend.PNG) 56 | 57 | ### Run ng serve, start project 58 | ![Screenshot of running frontend](Images/run_frontend.PNG) 59 | 60 | ### After starting successfully, go http://localhost:4200, will see below: 61 | ![Screenshot of frontend demo](Images/Frontend_demo.PNG) 62 | 63 | ## Step 3: Try the demo 64 | ### **Set a token in welcome page**, [Graph Explorer](https://developer.microsoft.com/graph/graph-explorer) and got a token from there. 65 | ![Screenshot of getting a token from graph explorer](Images/Token.PNG) 66 | 67 | ![Screenshot of setting a token in welcome page](Images/SetToken.PNG) 68 | 69 | ### **Click Search Button**, 70 | ![Screenshot of search result](Images/SearchResult.PNG) 71 | 72 | 73 | 74 | -------------------------------------------------------------------------------- /frontend/angular11/src/app/samples/welcome/welcome.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit, Inject, OnDestroy } from '@angular/core'; 2 | import { CommonService } from 'src/app/service/common.service'; 3 | import { MsalService, MsalBroadcastService, MSAL_GUARD_CONFIG, MsalGuardConfiguration } from '@azure/msal-angular'; 4 | import { AuthenticationResult, InteractionStatus, PopupRequest, RedirectRequest } from '@azure/msal-browser'; 5 | import { Subject } from 'rxjs'; 6 | import { filter, takeUntil } from 'rxjs/operators'; 7 | 8 | @Component({ 9 | selector: 'app-welcome', 10 | templateUrl: './welcome.component.html', 11 | styleUrls: ['./welcome.component.scss'], 12 | }) 13 | export class WelcomeComponent implements OnInit { 14 | tokenValue: string; 15 | isSpinning: boolean = false; 16 | title = 'Angular 11 - Angular v2 Sample'; 17 | isIframe = false; 18 | loginDisplay = false; 19 | private readonly _destroying$ = new Subject(); 20 | 21 | constructor(private commonService: CommonService, 22 | @Inject(MSAL_GUARD_CONFIG) private msalGuardConfig: MsalGuardConfiguration, 23 | private authService: MsalService, 24 | private msalBroadcastService: MsalBroadcastService 25 | ) {} 26 | 27 | ngOnInit(): void { 28 | this.isIframe = window !== window.parent && !window.opener; // Remove this line to use Angular Universal 29 | this.setLoginDisplay(); 30 | 31 | this.msalBroadcastService.inProgress$ 32 | .pipe( 33 | filter((status: InteractionStatus) => status === InteractionStatus.None), 34 | takeUntil(this._destroying$) 35 | ) 36 | .subscribe(() => { 37 | this.setLoginDisplay(); 38 | this.checkAndSetActiveAccount(); 39 | }) 40 | } 41 | 42 | setLoginDisplay() { 43 | this.loginDisplay = this.authService.instance.getAllAccounts().length > 0; 44 | } 45 | 46 | checkAndSetActiveAccount(){ 47 | /** 48 | * If no active account set but there are accounts signed in, sets first account to active account 49 | * To use active account set here, subscribe to inProgress$ first in your component 50 | * Note: Basic usage demonstrated. Your app may require more complicated account selection logic 51 | */ 52 | let activeAccount = this.authService.instance.getActiveAccount(); 53 | 54 | if (!activeAccount && this.authService.instance.getAllAccounts().length > 0) { 55 | let accounts = this.authService.instance.getAllAccounts(); 56 | this.authService.instance.setActiveAccount(accounts[0]); 57 | } 58 | } 59 | 60 | 61 | setToken(): void { 62 | this.commonService.setMockToken(this.tokenValue); 63 | alert('set token succeed'); 64 | } 65 | 66 | getToken():void{ 67 | this.loginPopup(); 68 | } 69 | 70 | // you should use your application id and redirect link confiurated in your application. please replace them in app.module.ts 71 | loginPopup() { 72 | if (this.msalGuardConfig.authRequest){ 73 | this.authService.loginPopup({...this.msalGuardConfig.authRequest} as PopupRequest) 74 | .subscribe((response: AuthenticationResult) => { 75 | console.log(response); 76 | this.tokenValue = response["accessToken"]; 77 | this.setToken(); 78 | this.authService.instance.setActiveAccount(response.account); 79 | }); 80 | } else { 81 | this.authService.loginPopup() 82 | .subscribe((response: AuthenticationResult) => { 83 | console.log(response); 84 | this.tokenValue = response["accessToken"]; 85 | this.setToken(); 86 | this.authService.instance.setActiveAccount(response.account); 87 | }); 88 | } 89 | } 90 | 91 | logout(popup?: boolean) { 92 | if (popup) { 93 | this.authService.logoutPopup({ 94 | mainWindowRedirectUri: "/" 95 | }); 96 | } else { 97 | this.authService.logoutRedirect(); 98 | } 99 | } 100 | 101 | ngOnDestroy(): void { 102 | this._destroying$.next(undefined); 103 | this._destroying$.complete(); 104 | } 105 | 106 | 107 | } 108 | -------------------------------------------------------------------------------- /frontend/angular11/src/app/samples/sort/sort.component.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 | 18 | 19 | 20 | 21 | 22 |
23 |
24 | 25 | 26 | 27 |
28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | {{ item.resource.name }} 41 | 42 | 43 | 44 | 45 | {{ encodeUri(item.resource.webUrl) }} 46 |
47 | Last modified by {{item.resource.lastModifiedBy.user.displayName}} 48 |
49 | in {{item.resource.lastModifiedDateTime}} 50 | 51 |
52 | 53 |
54 |
55 | 56 |
57 | 58 |
59 |
60 | 61 | 62 | 63 | 64 | 65 |
66 | 67 | 68 | 69 | 70 | 71 |
72 | 73 | 74 | 76 | 77 | 78 | 79 |
80 | 81 | 82 | 83 | 84 | Entity Types 85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 | 94 | 95 |
96 | 97 | Sort Properties 98 | 99 |
100 | ASC 101 | 103 | DESC 104 | 106 | 107 |
108 | These fields just some sample fields, not all fields. 109 |
110 | The select order determine the sort order 111 | 112 |
113 |
114 | 115 |
116 | 117 | 118 | 119 | 120 |
121 |
-------------------------------------------------------------------------------- /frontend/angular11/src/app/samples/speller/speller.component.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 | 20 | 21 | 22 | 23 | 24 | 25 |
26 |
27 | 28 |
29 | 30 | 31 | No results for {{searchInput}}, do you mean {{spellerSuggestion}}? 32 | 33 |
34 | 35 | 36 | 37 | 38 |
39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | {{ item.resource.name }} 52 | 53 | 54 | 55 | 56 |
{{ encodeUri(item.resource.webUrl) }}
57 |
58 | Last modified by {{item.resource.lastModifiedBy.user.displayName}} 59 |
60 | in {{item.resource.lastModifiedDateTime}} 61 | 62 |
63 | {{ 64 | item.summary 65 | }} 66 | 67 |
68 |
69 | 70 |
71 | 72 |
73 | 74 | 75 |
76 | 77 |
78 | 79 | 80 |
81 | 82 | 83 | 84 | 86 | 87 |
88 | 89 | 90 | Entity Types 91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 | 102 |
103 |
104 | 105 | 108 | 109 | 111 | 112 | 113 | 114 | -------------------------------------------------------------------------------- /frontend/angular11/src/app/samples/sort-v2/sort-v2.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import { CommonService } from 'src/app/service/common.service'; 3 | import { FormGroup } from '@angular/forms'; 4 | 5 | @Component({ 6 | selector: 'app-sort-v2', 7 | templateUrl: './sort-v2.component.html', 8 | styleUrls: ['./sort-v2.component.scss'], 9 | }) 10 | export class SortV2Component implements OnInit { 11 | entityTypes = ['list', 'driveItem']; 12 | 13 | isSpinning = false; 14 | data: any; 15 | showConfiguration = false; 16 | showCode = false; 17 | 18 | visible = false; 19 | 20 | selectedSortPropertiesList: string[] = []; 21 | 22 | sortPropertiesList: Array<{ value: string; label: string }> = []; 23 | 24 | validateForm!: FormGroup; 25 | listOfControl: Array<{ id: number; controlInstance: string }> = []; 26 | 27 | constructor(private commonService: CommonService) {} 28 | 29 | ngOnInit(): void {} 30 | 31 | searchInput1 = ''; 32 | loading = false; 33 | hitObjects: any; 34 | response = ''; 35 | isDescending = false; 36 | fieldInput = ''; 37 | token = ''; 38 | 39 | executeSearch(input: string) { 40 | if (this.searchInput1 == '') { 41 | alert('Search term cannot be empty'); 42 | return; 43 | } 44 | 45 | this.isSpinning = true; 46 | this.commonService 47 | .GetSortResult( 48 | this.searchInput1, 49 | this.entityTypes, 50 | this.selectedSortPropertiesList 51 | ) 52 | .subscribe( 53 | (data) => { 54 | this.data = data; 55 | this.isSpinning = false; 56 | }, 57 | (error) => { 58 | this.isSpinning = false; 59 | alert(error['message']); 60 | } 61 | ); 62 | } 63 | 64 | encodeUri(uri: string) { 65 | return encodeURI(uri); 66 | } 67 | 68 | submitAndGetSortResult() { 69 | this.visible = false; 70 | this.executeSearch(this.searchInput1); 71 | } 72 | 73 | formatEmptyOrNullString(resourceProperty: string) { 74 | if (resourceProperty == null || resourceProperty == '') { 75 | return 'null'; 76 | } 77 | return resourceProperty; 78 | } 79 | 80 | returnWebUrlIfNameIsnull(hitObject: any) { 81 | var name = hitObject.resource.name; 82 | if (name == '' || name == null) { 83 | return 'null'; 84 | } 85 | return name; 86 | } 87 | 88 | configOpen(): void { 89 | this.showConfiguration = true; 90 | } 91 | 92 | configClose(): void { 93 | this.showConfiguration = false; 94 | } 95 | 96 | codeOpen(): void { 97 | this.showCode = true; 98 | } 99 | 100 | codeClose(): void { 101 | this.showCode = false; 102 | } 103 | 104 | setEntityTypes(value: string[]): void { 105 | this.entityTypes = value; 106 | } 107 | 108 | AddToselectedSortPropertiesList() { 109 | if (this.fieldInput != '') { 110 | var sortOrder = 'ascending'; 111 | if (String(this.isDescending).includes('true')) { 112 | sortOrder = 'descending'; 113 | } 114 | var sortProperty = this.fieldInput + ': ' + sortOrder; 115 | if (!this.selectedSortPropertiesList.includes(sortProperty)) { 116 | this.selectedSortPropertiesList.push(sortProperty); 117 | } 118 | } 119 | if (this.selectedSortPropertiesList.length > 0) 120 | this.sortPropertiesList = this.selectedSortPropertiesList.map((item) => { 121 | return { 122 | value: item, 123 | label: item, 124 | }; 125 | }); 126 | } 127 | CSharp_Code = ` 128 | GraphServiceClient graphClient = new GraphServiceClient( authProvider ); 129 | 130 | var requests = new List() 131 | { 132 | new SearchRequestObject 133 | { 134 | EntityTypes = new List() 135 | { 136 | EntityType.DriveItem 137 | }, 138 | Query = new SearchQuery 139 | { 140 | QueryString = "*" 141 | }, 142 | SortProperties = new List() 143 | { 144 | new SortProperty 145 | { 146 | Name = "lastModifiedDateTime", 147 | IsDescending = true 148 | } 149 | } 150 | } 151 | }; 152 | 153 | await graphClient.Search 154 | .Query(requests,null) 155 | .Request() 156 | .PostAsync(); 157 | `; 158 | 159 | highlight() { 160 | var renderCSharpCode = this.CSharp_Code.replace( 161 | new RegExp('var|await|null|new'), 162 | (match) => { 163 | return '' + match + ''; 164 | } 165 | ); 166 | return renderCSharpCode; 167 | } 168 | } 169 | -------------------------------------------------------------------------------- /frontend/angular11/src/app/samples/meeting/meeting.component.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 |
23 | 24 |
25 | 26 | 27 |
28 |
29 |
30 |
31 | 34 | {{data.resource.subject}} 35 | 36 | 37 | More 38 | 39 |
40 |
41 |
42 |
43 | 44 |
45 | 46 |
47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 |
55 | 56 | Subjects:{{mockMeetingDetails.subject}} 57 |
58 | Orgnizer:{{mockMeetingDetails.organizer.emailAddress.name}} 59 |
60 | Attendees: 61 | 64 |
65 | 66 |
67 |
68 | 69 | 70 | 71 |
72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 115 | 116 | 118 | 119 | 120 | 121 | 122 | -------------------------------------------------------------------------------- /frontend/angular11/src/app/samples/sort-v2/sort-v2.component.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 | 18 | 19 | 20 | 21 | 22 |
23 |
24 | 25 | 26 | 27 |
28 | 29 | 30 | 31 | 32 |
33 | 34 | 35 | 36 | 37 | 38 |
39 | 40 | 41 | 42 | 43 | 44 |
45 | 46 | 47 | 48 | 50 | 51 | 52 | 53 |
54 | 55 | 56 | 57 | 58 | Entity Types 59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 | 69 | Sort Properties 70 |
71 |
72 | Field: 74 |
75 |
76 | IsDescending: 77 | 78 |
79 |
80 | 81 |
82 |
83 |
84 | 86 |
87 |
88 | 89 |
90 |
91 |
92 | 93 | 94 | 97 | 98 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 109 | 110 | 111 | 112 | 113 | 114 |
  • 115 |
    Name
    116 |
    LastModifiedDateTime
    117 |
    CreatedDateTime
    118 |
    Description
    119 |
    LastModifiedBy
    120 |
  • 121 |
    122 |
    123 |
    124 | 125 | 126 | 127 |
  • 128 | 131 |
    132 | {{formatEmptyOrNullString(hitObject.resource.lastModifiedDateTime)}} 133 |
    134 |
    135 | {{formatEmptyOrNullString(hitObject.resource.createdDateTime)}} 136 |
    137 |
    138 | {{formatEmptyOrNullString(hitObject.resource.description)}} 139 |
    140 |
    141 | {{formatEmptyOrNullString(hitObject.resource.lastModifiedBy?.user?.displayName)}} 142 |
    143 |
  • 144 |
    145 |
    146 |
    147 | 148 |
    149 | -------------------------------------------------------------------------------- /frontend/angular11/angular.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "./node_modules/@angular/cli/lib/config/schema.json", 3 | "version": 1, 4 | "newProjectRoot": "projects", 5 | "projects": { 6 | "front-end": { 7 | "projectType": "application", 8 | "schematics": { 9 | "@schematics/angular:component": { 10 | "style": "scss" 11 | } 12 | }, 13 | "root": "", 14 | "sourceRoot": "src", 15 | "prefix": "app", 16 | "architect": { 17 | "build": { 18 | "builder": "@angular-devkit/build-angular:browser", 19 | "options": { 20 | "outputPath": "dist/front-end", 21 | "index": "src/index.html", 22 | "main": "src/main.ts", 23 | "polyfills": "src/polyfills.ts", 24 | "tsConfig": "tsconfig.app.json", 25 | "aot": true, 26 | "assets": [ 27 | "src/microsoft.svg", 28 | "src/assets" 29 | ], 30 | "styles": [ 31 | "./node_modules/ng-zorro-antd/ng-zorro-antd.min.css", 32 | "src/styles.scss", 33 | "node_modules/prismjs/themes/prism-okaidia.css", 34 | "node_modules/prismjs/plugins/line-numbers/prism-line-numbers.css" 35 | ], 36 | "scripts": [ 37 | "node_modules/marked/lib/marked.js", 38 | "node_modules/prismjs/prism.js", 39 | "node_modules/prismjs/components/prism-csharp.min.js", 40 | "node_modules/prismjs/components/prism-css.min.js", 41 | "node_modules/prismjs/plugins/line-numbers/prism-line-numbers.js" 42 | ] 43 | }, 44 | "configurations": { 45 | "production": { 46 | "fileReplacements": [ 47 | { 48 | "replace": "src/environments/environment.ts", 49 | "with": "src/environments/environment.prod.ts" 50 | } 51 | ], 52 | "optimization": true, 53 | "outputHashing": "all", 54 | "sourceMap": false, 55 | "namedChunks": false, 56 | "extractLicenses": true, 57 | "vendorChunk": false, 58 | "buildOptimizer": true, 59 | "budgets": [ 60 | { 61 | "type": "initial", 62 | "maximumWarning": "2mb", 63 | "maximumError": "5mb" 64 | }, 65 | { 66 | "type": "anyComponentStyle", 67 | "maximumWarning": "6kb", 68 | "maximumError": "10kb" 69 | } 70 | ] 71 | } 72 | } 73 | }, 74 | "serve": { 75 | "builder": "@angular-devkit/build-angular:dev-server", 76 | "options": { 77 | "browserTarget": "front-end:build" 78 | }, 79 | "configurations": { 80 | "production": { 81 | "browserTarget": "front-end:build:production" 82 | } 83 | } 84 | }, 85 | "extract-i18n": { 86 | "builder": "@angular-devkit/build-angular:extract-i18n", 87 | "options": { 88 | "browserTarget": "front-end:build" 89 | } 90 | }, 91 | "test": { 92 | "builder": "@angular-devkit/build-angular:karma", 93 | "options": { 94 | "main": "src/test.ts", 95 | "polyfills": "src/polyfills.ts", 96 | "tsConfig": "tsconfig.spec.json", 97 | "karmaConfig": "karma.conf.js", 98 | "assets": [ 99 | "src/microsoft.svg", 100 | "src/assets", 101 | { 102 | "glob": "**/*", 103 | "input": "./node_modules/@ant-design/icons-angular/src/inline-svg/", 104 | "output": "/assets/" 105 | } 106 | ], 107 | "styles": [ 108 | "./node_modules/ng-zorro-antd/ng-zorro-antd.min.css", 109 | "src/styles.scss", 110 | "node_modules/prismjs/themes/prism-okaidia.css", 111 | "node_modules/prismjs/plugins/line-numbers/prism-line-numbers.css" 112 | ], 113 | "scripts": [ 114 | "node_modules/marked/lib/marked.js", 115 | "node_modules/prismjs/prism.js", 116 | "node_modules/prismjs/components/prism-csharp.min.js", 117 | "node_modules/prismjs/components/prism-css.min.js", 118 | "node_modules/prismjs/plugins/line-numbers/prism-line-numbers.js" 119 | ] 120 | } 121 | }, 122 | "lint": { 123 | "builder": "@angular-devkit/build-angular:tslint", 124 | "options": { 125 | "tsConfig": [ 126 | "tsconfig.app.json", 127 | "tsconfig.spec.json", 128 | "e2e/tsconfig.json" 129 | ], 130 | "exclude": [ 131 | "**/node_modules/**" 132 | ] 133 | } 134 | }, 135 | "e2e": { 136 | "builder": "@angular-devkit/build-angular:protractor", 137 | "options": { 138 | "protractorConfig": "e2e/protractor.conf.js", 139 | "devServerTarget": "front-end:serve" 140 | }, 141 | "configurations": { 142 | "production": { 143 | "devServerTarget": "front-end:serve:production" 144 | } 145 | } 146 | } 147 | } 148 | } 149 | }, 150 | "defaultProject": "front-end", 151 | "cli": { 152 | "analytics": false 153 | } 154 | } -------------------------------------------------------------------------------- /frontend/angular11/src/app/app.module.ts: -------------------------------------------------------------------------------- 1 | import { BrowserModule } from '@angular/platform-browser'; 2 | import { NgModule } from '@angular/core'; 3 | import { AppRoutingModule } from './app-routing.module'; 4 | import { AppComponent } from './app.component'; 5 | import { NZ_I18N } from 'ng-zorro-antd/i18n'; 6 | import { en_US } from 'ng-zorro-antd/i18n'; 7 | import { registerLocaleData, DatePipe } from '@angular/common'; 8 | import en from '@angular/common/locales/en'; 9 | import { FormsModule } from '@angular/forms'; 10 | import { HttpClient, HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http'; 11 | import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; 12 | import { IconsProviderModule } from './icons-provider.module'; 13 | import { NzLayoutModule } from 'ng-zorro-antd/layout'; 14 | import { NzMenuModule } from 'ng-zorro-antd/menu'; 15 | import { MeetingComponent } from './samples/meeting/meeting.component'; 16 | import { NzInputModule } from 'ng-zorro-antd/input'; 17 | import { NzGridModule } from 'ng-zorro-antd/grid'; 18 | import { SortComponent } from './samples/sort/sort.component'; 19 | import { NzIconModule } from 'ng-zorro-antd/icon'; 20 | import { NzTabsModule } from 'ng-zorro-antd/tabs'; 21 | import { NzButtonModule } from 'ng-zorro-antd/button'; 22 | import { NzCardModule } from 'ng-zorro-antd/card'; 23 | import { NzDrawerModule } from 'ng-zorro-antd/drawer'; 24 | import { NzSpinModule } from 'ng-zorro-antd/spin'; 25 | import { CommonComponent } from './samples/common/common.component'; 26 | import { NzListModule } from 'ng-zorro-antd/list'; 27 | import { NzCheckboxModule } from 'ng-zorro-antd/checkbox'; 28 | import { NzTransferModule } from 'ng-zorro-antd/transfer'; 29 | import { NzSelectModule } from 'ng-zorro-antd/select'; 30 | import { NzDatePickerModule } from 'ng-zorro-antd/date-picker'; 31 | import { SortV2Component } from './samples/sort-v2/sort-v2.component'; 32 | import { WelcomeComponent } from './samples/welcome/welcome.component'; 33 | import { SpellerComponent } from './samples/speller/speller.component'; 34 | import { SemanticLabelComponent } from './samples/semantic-label/semantic-label.component'; 35 | import { DisplayTemplateComponent } from './samples/display-template/display-template.component'; 36 | import { IconDefinition } from '@ant-design/icons-angular'; 37 | import { NzSwitchModule } from 'ng-zorro-antd/switch'; 38 | import { MarkdownModule } from 'ngx-markdown'; 39 | import { SecurityContext } from '@angular/core'; 40 | 41 | // import icons 42 | import * as AllIcons from '@ant-design/icons-angular/icons'; 43 | import { IPublicClientApplication, PublicClientApplication, InteractionType, BrowserCacheLocation, LogLevel } from '@azure/msal-browser'; 44 | import { MsalGuard, MsalInterceptor, MsalBroadcastService, MsalInterceptorConfiguration, MsalModule, MsalService, MSAL_GUARD_CONFIG, MSAL_INSTANCE, MSAL_INTERCEPTOR_CONFIG, MsalGuardConfiguration, MsalRedirectComponent } from '@azure/msal-angular'; 45 | const antDesignIcons = AllIcons as { 46 | [key: string]: IconDefinition; 47 | }; 48 | const icons: IconDefinition[] = Object.keys(antDesignIcons).map(key => antDesignIcons[key]) 49 | 50 | registerLocaleData(en); 51 | const isIE = window.navigator.userAgent.indexOf("MSIE ") > -1 || window.navigator.userAgent.indexOf("Trident/") > -1; // Remove this line to use Angular Universal 52 | 53 | export function loggerCallback(logLevel: LogLevel, message: string) { 54 | console.log(message); 55 | } 56 | 57 | export function MSALInstanceFactory(): IPublicClientApplication { 58 | // var secret 59 | return new PublicClientApplication({ 60 | auth: { 61 | clientId: '6226576d-37e9-49eb-b201-ec1eeb0029b6', // your application id, (this for graph-explorer) 62 | authority: `https://login.microsoftonline.com/common`, 63 | redirectUri: 'http://localhost:4200', 64 | postLogoutRedirectUri: '/' 65 | }, 66 | cache: { 67 | cacheLocation: BrowserCacheLocation.LocalStorage, 68 | storeAuthStateInCookie: isIE, // set to true for IE 11. Remove this line to use Angular Universal 69 | }, 70 | system: { 71 | loggerOptions: { 72 | loggerCallback, 73 | logLevel: LogLevel.Info, 74 | piiLoggingEnabled: false 75 | } 76 | } 77 | }); 78 | } 79 | 80 | 81 | export function MSALInterceptorConfigFactory(): MsalInterceptorConfiguration { 82 | const protectedResourceMap = new Map>(); 83 | //protectedResourceMap.set('https://graph.microsoft-ppe.com/v1.0/me', ['user.read']); 84 | protectedResourceMap.set('https://graph.microsoft.com/v1.0/me', ['user.read']); 85 | 86 | return { 87 | interactionType: InteractionType.Redirect, 88 | protectedResourceMap 89 | }; 90 | } 91 | 92 | 93 | export function MSALGuardConfigFactory(): MsalGuardConfiguration { 94 | return { 95 | interactionType: InteractionType.Redirect, 96 | authRequest: { 97 | scopes: ['user.read'] 98 | }, 99 | loginFailedRoute: '/login-failed' 100 | }; 101 | } 102 | 103 | @NgModule({ 104 | declarations: [ 105 | AppComponent, 106 | MeetingComponent, 107 | SortComponent, 108 | CommonComponent, 109 | SortV2Component, 110 | WelcomeComponent, 111 | SpellerComponent, 112 | SemanticLabelComponent, 113 | DisplayTemplateComponent, 114 | ], 115 | imports: [ 116 | BrowserModule, 117 | AppRoutingModule, 118 | FormsModule, 119 | HttpClientModule, 120 | BrowserAnimationsModule, 121 | IconsProviderModule, 122 | NzLayoutModule, 123 | NzMenuModule, 124 | NzInputModule, 125 | NzGridModule, 126 | NzIconModule.forRoot(icons), 127 | NzTabsModule, 128 | NzButtonModule, 129 | NzCardModule, 130 | NzDrawerModule, 131 | NzSpinModule, 132 | NzListModule, 133 | NzCheckboxModule, 134 | NzTransferModule, 135 | NzSelectModule, 136 | NzDatePickerModule, 137 | NzSelectModule, 138 | NzSwitchModule, 139 | MarkdownModule.forRoot({ 140 | loader: HttpClient, 141 | sanitize: SecurityContext.NONE 142 | }), 143 | ], 144 | providers: [ 145 | { provide: NZ_I18N, useValue: en_US }, 146 | DatePipe, 147 | { 148 | provide: HTTP_INTERCEPTORS, 149 | useClass: MsalInterceptor, 150 | multi: true 151 | }, 152 | { 153 | provide: MSAL_INSTANCE, 154 | useFactory: MSALInstanceFactory 155 | }, 156 | { 157 | provide: MSAL_GUARD_CONFIG, 158 | useFactory: MSALGuardConfigFactory 159 | }, 160 | { 161 | provide: MSAL_INTERCEPTOR_CONFIG, 162 | useFactory: MSALInterceptorConfigFactory 163 | }, 164 | MsalService, 165 | MsalGuard, 166 | MsalBroadcastService 167 | ], 168 | bootstrap: [AppComponent], 169 | }) 170 | export class AppModule {} 171 | -------------------------------------------------------------------------------- /frontend/angular11/src/app/service/common.service.ts: -------------------------------------------------------------------------------- 1 | import { DatePipe } from '@angular/common'; 2 | import { HttpClient, HttpHeaders } from '@angular/common/http'; 3 | import { Injectable } from '@angular/core'; 4 | 5 | @Injectable({ 6 | providedIn: 'root', 7 | }) 8 | export class CommonService { 9 | headers: any; 10 | searchUri = 'https://localhost:44383/api/Search'; 11 | constructor(private http: HttpClient, private datePipe: DatePipe) {} 12 | 13 | // search meeting 14 | Search( 15 | query: string, 16 | entityTypes: string[], 17 | sortASCPropertiesList?: string[], 18 | sortDESCPropertiesList?: string[] 19 | ) { 20 | /* 21 | User Token, get a test token from Graph Explorer https://developer.microsoft.com/en-us/graph/graph-explorer, 22 | For client's application, please refer https://docs.microsoft.com/en-us/azure/active-directory/fundamentals/auth-oidc 23 | */ 24 | this.headers = new HttpHeaders({ 25 | 'Content-Type': 'application/json', 26 | 'Custom-Token': this.getMockToken(), 27 | }); 28 | 29 | var requestBody: any = { 30 | requests: [ 31 | { 32 | entityTypes: entityTypes, 33 | query: { 34 | queryString: query, 35 | }, 36 | size: 10, 37 | }, 38 | ], 39 | }; 40 | 41 | if ( 42 | (sortASCPropertiesList && sortASCPropertiesList.length > 0) || 43 | (sortDESCPropertiesList && sortDESCPropertiesList.length > 0) 44 | ) { 45 | var sortProperties: string[] = this.buildSortProperties( 46 | sortASCPropertiesList, 47 | sortDESCPropertiesList 48 | ); 49 | requestBody = { 50 | requests: [ 51 | { 52 | entityTypes: entityTypes, 53 | query: { 54 | queryString: query, 55 | }, 56 | size: 10, 57 | sortProperties: sortProperties, 58 | }, 59 | ], 60 | }; 61 | } 62 | 63 | return this.http.post(this.searchUri, requestBody, { 64 | headers: this.headers, 65 | }); 66 | } 67 | 68 | // search meeting 69 | SearchMeeting(query: string, startDate?: Date, endDate?: Date) { 70 | this.headers = new HttpHeaders({ 71 | 'Content-Type': 'application/json', 72 | 'Custom-Token': this.getMockToken(), 73 | }); 74 | 75 | var requestBody: any = { 76 | requests: [ 77 | { 78 | entityTypes: ['event'], 79 | query: { 80 | queryString: query, 81 | }, 82 | size: 10, 83 | }, 84 | ], 85 | }; 86 | 87 | if (startDate || endDate) { 88 | requestBody = { 89 | requests: [ 90 | { 91 | entityTypes: ['event'], 92 | query: { 93 | queryString: query, 94 | }, 95 | size: 10, 96 | Filter: this.buildDateRange(startDate, endDate), 97 | }, 98 | ], 99 | }; 100 | } 101 | 102 | return this.http.post(this.searchUri, requestBody, { 103 | headers: this.headers, 104 | }); 105 | } 106 | 107 | 108 | // Speller Request 109 | SearchWithSpeller(query:string, entityTypes: string[], enableModification:boolean){ 110 | this.headers = new HttpHeaders({ 111 | 'Content-Type': 'application/json', 112 | 'Custom-Token': this.getMockToken(), 113 | }); 114 | 115 | var requestBody: any = { 116 | requests: [ 117 | { 118 | entityTypes: entityTypes, 119 | query: { 120 | queryString: query, 121 | }, 122 | size: 10, 123 | }, 124 | ], 125 | "queryAlterationOptions":{ 126 | "enableSuggestion":true, 127 | "enableModification":enableModification 128 | } 129 | }; 130 | 131 | console.log("request body:",requestBody); 132 | 133 | return this.http.post( 134 | this.searchUri, 135 | requestBody, { 136 | headers: this.headers, 137 | }); 138 | } 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | // get meeting details 152 | getMeetingDetails(eventId: String) { 153 | eventId = eventId.replace(new RegExp('/', 'g'), '-'); 154 | return this.http.get( 155 | 'https://localhost:44383/api/Event?eventId=' + eventId, 156 | { headers: this.headers } 157 | ); 158 | } 159 | 160 | // set Mock token 161 | // only for test 162 | setMockToken(token: string) { 163 | localStorage.setItem('token', token); 164 | } 165 | 166 | getMockToken(): string { 167 | return localStorage.getItem('token'); 168 | } 169 | 170 | buildSortProperties( 171 | ascProperties: string[], 172 | descProperties: string[] 173 | ): string[] { 174 | var result: any[] = []; 175 | 176 | if (ascProperties) 177 | for (let item of ascProperties) { 178 | result.push({ 179 | name: item, 180 | isDescending: false, 181 | }); 182 | } 183 | 184 | if (descProperties) 185 | for (let item of descProperties) { 186 | result.push({ 187 | name: item, 188 | isDescending: true, 189 | }); 190 | } 191 | 192 | return result; 193 | } 194 | 195 | buildDateRange(startDate: Date, endDate: Date): any { 196 | var dateRange = []; 197 | if (startDate) { 198 | dateRange.push({ 199 | Range: { 200 | StartTime: { 201 | gte: this.getYearMonthDay(startDate), 202 | }, 203 | }, 204 | }); 205 | } 206 | 207 | if (endDate) { 208 | dateRange.push({ 209 | Range: { 210 | EndTime: { 211 | lte: this.getYearMonthDay(startDate), 212 | }, 213 | }, 214 | }); 215 | } 216 | 217 | return { 218 | And: dateRange, 219 | }; 220 | } 221 | 222 | getYearMonthDay(date: Date): string { 223 | return this.datePipe.transform(date, 'yyyy-MM-dd'); 224 | } 225 | 226 | //get sort result 227 | GetSortResult( 228 | query: string, 229 | entityTypes: string[], 230 | selectedSortPropertiesList: string[] 231 | ) { 232 | this.headers = new HttpHeaders({ 233 | 'Content-Type': 'application/json', 234 | 'Custom-Token': this.getMockToken(), 235 | }); 236 | var requestBody: any; 237 | if (selectedSortPropertiesList && selectedSortPropertiesList.length > 0) { 238 | var sortProperties: string[] = this.buildSortPropertiesFromList( 239 | selectedSortPropertiesList 240 | ); 241 | requestBody = { 242 | requests: [ 243 | { 244 | entityTypes: entityTypes, 245 | query: { 246 | queryString: query, 247 | }, 248 | size: 10, 249 | sortProperties: sortProperties, 250 | }, 251 | ], 252 | }; 253 | } else { 254 | requestBody = { 255 | requests: [ 256 | { 257 | entityTypes: entityTypes, 258 | query: { 259 | queryString: query, 260 | }, 261 | size: 10, 262 | }, 263 | ], 264 | }; 265 | } 266 | return this.http.post( 267 | 'https://graph.microsoft.com/beta/search/query', 268 | requestBody, 269 | { headers: this.headers } 270 | ); 271 | } 272 | 273 | buildSortPropertiesFromList(sortPropertiesList: string[]): string[] { 274 | var result: any[] = []; 275 | 276 | if (sortPropertiesList) 277 | for (let sortItem of sortPropertiesList) { 278 | var itemArray = sortItem.split(':'); 279 | var isDescending = itemArray[1].includes('descending') ? true : false; 280 | result.push({ 281 | name: itemArray[0], 282 | isDescending: isDescending, 283 | }); 284 | } 285 | return result; 286 | } 287 | } 288 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 5 | 6 | # User-specific files 7 | *.rsuser 8 | *.suo 9 | *.user 10 | *.userosscache 11 | *.sln.docstates 12 | 13 | # User-specific files (MonoDevelop/Xamarin Studio) 14 | *.userprefs 15 | 16 | # Mono auto generated files 17 | mono_crash.* 18 | 19 | # Build results 20 | [Dd]ebug/ 21 | [Dd]ebugPublic/ 22 | [Rr]elease/ 23 | [Rr]eleases/ 24 | x64/ 25 | x86/ 26 | [Aa][Rr][Mm]/ 27 | [Aa][Rr][Mm]64/ 28 | bld/ 29 | [Bb]in/ 30 | [Oo]bj/ 31 | [Ll]og/ 32 | [Ll]ogs/ 33 | 34 | # Visual Studio 2015/2017 cache/options directory 35 | .vs/ 36 | # Uncomment if you have tasks that create the project's static files in wwwroot 37 | #wwwroot/ 38 | 39 | # Visual Studio 2017 auto generated files 40 | Generated\ Files/ 41 | 42 | # MSTest test Results 43 | [Tt]est[Rr]esult*/ 44 | [Bb]uild[Ll]og.* 45 | 46 | # NUnit 47 | *.VisualState.xml 48 | TestResult.xml 49 | nunit-*.xml 50 | 51 | # Build Results of an ATL Project 52 | [Dd]ebugPS/ 53 | [Rr]eleasePS/ 54 | dlldata.c 55 | 56 | # Benchmark Results 57 | BenchmarkDotNet.Artifacts/ 58 | 59 | # .NET Core 60 | project.lock.json 61 | project.fragment.lock.json 62 | artifacts/ 63 | 64 | # StyleCop 65 | StyleCopReport.xml 66 | 67 | # Files built by Visual Studio 68 | *_i.c 69 | *_p.c 70 | *_h.h 71 | *.ilk 72 | *.meta 73 | *.obj 74 | *.iobj 75 | *.pch 76 | *.pdb 77 | *.ipdb 78 | *.pgc 79 | *.pgd 80 | *.rsp 81 | *.sbr 82 | *.tlb 83 | *.tli 84 | *.tlh 85 | *.tmp 86 | *.tmp_proj 87 | *_wpftmp.csproj 88 | *.log 89 | *.vspscc 90 | *.vssscc 91 | .builds 92 | *.pidb 93 | *.svclog 94 | *.scc 95 | 96 | # Chutzpah Test files 97 | _Chutzpah* 98 | 99 | # Visual C++ cache files 100 | ipch/ 101 | *.aps 102 | *.ncb 103 | *.opendb 104 | *.opensdf 105 | *.sdf 106 | *.cachefile 107 | *.VC.db 108 | *.VC.VC.opendb 109 | 110 | # Visual Studio profiler 111 | *.psess 112 | *.vsp 113 | *.vspx 114 | *.sap 115 | 116 | # Visual Studio Trace Files 117 | *.e2e 118 | 119 | # TFS 2012 Local Workspace 120 | $tf/ 121 | 122 | # Guidance Automation Toolkit 123 | *.gpState 124 | 125 | # ReSharper is a .NET coding add-in 126 | _ReSharper*/ 127 | *.[Rr]e[Ss]harper 128 | *.DotSettings.user 129 | 130 | # TeamCity is a build add-in 131 | _TeamCity* 132 | 133 | # DotCover is a Code Coverage Tool 134 | *.dotCover 135 | 136 | # AxoCover is a Code Coverage Tool 137 | .axoCover/* 138 | !.axoCover/settings.json 139 | 140 | # Visual Studio code coverage results 141 | *.coverage 142 | *.coveragexml 143 | 144 | # NCrunch 145 | _NCrunch_* 146 | .*crunch*.local.xml 147 | nCrunchTemp_* 148 | 149 | # MightyMoose 150 | *.mm.* 151 | AutoTest.Net/ 152 | 153 | # Web workbench (sass) 154 | .sass-cache/ 155 | 156 | # Installshield output folder 157 | [Ee]xpress/ 158 | 159 | # DocProject is a documentation generator add-in 160 | DocProject/buildhelp/ 161 | DocProject/Help/*.HxT 162 | DocProject/Help/*.HxC 163 | DocProject/Help/*.hhc 164 | DocProject/Help/*.hhk 165 | DocProject/Help/*.hhp 166 | DocProject/Help/Html2 167 | DocProject/Help/html 168 | 169 | # Click-Once directory 170 | publish/ 171 | 172 | # Publish Web Output 173 | *.[Pp]ublish.xml 174 | *.azurePubxml 175 | # Note: Comment the next line if you want to checkin your web deploy settings, 176 | # but database connection strings (with potential passwords) will be unencrypted 177 | *.pubxml 178 | *.publishproj 179 | 180 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 181 | # checkin your Azure Web App publish settings, but sensitive information contained 182 | # in these scripts will be unencrypted 183 | PublishScripts/ 184 | 185 | # NuGet Packages 186 | *.nupkg 187 | # NuGet Symbol Packages 188 | *.snupkg 189 | # The packages folder can be ignored because of Package Restore 190 | **/[Pp]ackages/* 191 | # except build/, which is used as an MSBuild target. 192 | !**/[Pp]ackages/build/ 193 | # Uncomment if necessary however generally it will be regenerated when needed 194 | #!**/[Pp]ackages/repositories.config 195 | # NuGet v3's project.json files produces more ignorable files 196 | *.nuget.props 197 | *.nuget.targets 198 | 199 | # Microsoft Azure Build Output 200 | csx/ 201 | *.build.csdef 202 | 203 | # Microsoft Azure Emulator 204 | ecf/ 205 | rcf/ 206 | 207 | # Windows Store app package directories and files 208 | AppPackages/ 209 | BundleArtifacts/ 210 | Package.StoreAssociation.xml 211 | _pkginfo.txt 212 | *.appx 213 | *.appxbundle 214 | *.appxupload 215 | 216 | # Visual Studio cache files 217 | # files ending in .cache can be ignored 218 | *.[Cc]ache 219 | # but keep track of directories ending in .cache 220 | !?*.[Cc]ache/ 221 | 222 | # Others 223 | ClientBin/ 224 | ~$* 225 | *~ 226 | *.dbmdl 227 | *.dbproj.schemaview 228 | *.jfm 229 | *.pfx 230 | *.publishsettings 231 | orleans.codegen.cs 232 | 233 | # Including strong name files can present a security risk 234 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 235 | #*.snk 236 | 237 | # Since there are multiple workflows, uncomment next line to ignore bower_components 238 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 239 | #bower_components/ 240 | 241 | # RIA/Silverlight projects 242 | Generated_Code/ 243 | 244 | # Backup & report files from converting an old project file 245 | # to a newer Visual Studio version. Backup files are not needed, 246 | # because we have git ;-) 247 | _UpgradeReport_Files/ 248 | Backup*/ 249 | UpgradeLog*.XML 250 | UpgradeLog*.htm 251 | ServiceFabricBackup/ 252 | *.rptproj.bak 253 | 254 | # SQL Server files 255 | *.mdf 256 | *.ldf 257 | *.ndf 258 | 259 | # Business Intelligence projects 260 | *.rdl.data 261 | *.bim.layout 262 | *.bim_*.settings 263 | *.rptproj.rsuser 264 | *- [Bb]ackup.rdl 265 | *- [Bb]ackup ([0-9]).rdl 266 | *- [Bb]ackup ([0-9][0-9]).rdl 267 | 268 | # Microsoft Fakes 269 | FakesAssemblies/ 270 | 271 | # GhostDoc plugin setting file 272 | *.GhostDoc.xml 273 | 274 | # Node.js Tools for Visual Studio 275 | .ntvs_analysis.dat 276 | node_modules/ 277 | 278 | # Visual Studio 6 build log 279 | *.plg 280 | 281 | # Visual Studio 6 workspace options file 282 | *.opt 283 | 284 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 285 | *.vbw 286 | 287 | # Visual Studio LightSwitch build output 288 | **/*.HTMLClient/GeneratedArtifacts 289 | **/*.DesktopClient/GeneratedArtifacts 290 | **/*.DesktopClient/ModelManifest.xml 291 | **/*.Server/GeneratedArtifacts 292 | **/*.Server/ModelManifest.xml 293 | _Pvt_Extensions 294 | 295 | # Paket dependency manager 296 | .paket/paket.exe 297 | paket-files/ 298 | 299 | # FAKE - F# Make 300 | .fake/ 301 | 302 | # CodeRush personal settings 303 | .cr/personal 304 | 305 | # Python Tools for Visual Studio (PTVS) 306 | __pycache__/ 307 | *.pyc 308 | 309 | # Cake - Uncomment if you are using it 310 | # tools/** 311 | # !tools/packages.config 312 | 313 | # Tabs Studio 314 | *.tss 315 | 316 | # Telerik's JustMock configuration file 317 | *.jmconfig 318 | 319 | # BizTalk build output 320 | *.btp.cs 321 | *.btm.cs 322 | *.odx.cs 323 | *.xsd.cs 324 | 325 | # OpenCover UI analysis results 326 | OpenCover/ 327 | 328 | # Azure Stream Analytics local run output 329 | ASALocalRun/ 330 | 331 | # MSBuild Binary and Structured Log 332 | *.binlog 333 | 334 | # NVidia Nsight GPU debugger configuration file 335 | *.nvuser 336 | 337 | # MFractors (Xamarin productivity tool) working folder 338 | .mfractor/ 339 | 340 | # Local History for Visual Studio 341 | .localhistory/ 342 | 343 | # BeatPulse healthcheck temp database 344 | healthchecksdb 345 | 346 | # Backup folder for Package Reference Convert tool in Visual Studio 2017 347 | MigrationBackup/ 348 | 349 | # Ionide (cross platform F# VS Code tools) working folder 350 | .ionide/ 351 | -------------------------------------------------------------------------------- /frontend/angular11/src/app/samples/display-template/display-template.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import { CommonService } from 'src/app/service/common.service'; 3 | import * as ACData from "adaptivecards-templating"; 4 | import * as AdaptiveCards from "adaptivecards"; 5 | import { DomSanitizer, SafeHtml } from '@angular/platform-browser'; 6 | 7 | 8 | @Component({ 9 | selector: 'app-display-template', 10 | templateUrl: './display-template.component.html', 11 | styleUrls: ['./display-template.component.scss'] 12 | }) 13 | export class DisplayTemplateComponent implements OnInit { 14 | 15 | 16 | isSpinning = false; 17 | showCode = false; 18 | entityTypes = ['list', 'driveItem']; 19 | 20 | constructor(private commonService: CommonService, private sanitizer: DomSanitizer) {} 21 | 22 | ngOnInit(): void {} 23 | 24 | loading = false; 25 | 26 | searchInput1 = ''; 27 | 28 | showConfiguration = false; 29 | 30 | data: any; 31 | 32 | test:any; 33 | 34 | templateDictionary:any; 35 | 36 | renderTemplates:any[] = []; 37 | 38 | encodeUri(input: string): string { 39 | return encodeURI(input); 40 | } 41 | // key: template Id value:template Body 42 | renderedACTList = new Map(); 43 | 44 | executeSearch(input: string) { 45 | 46 | /*if (this.searchInput1 == '') { 47 | alert('Search term cannot be empty'); 48 | return; 49 | } 50 | this.isSpinning = true; 51 | this.commonService 52 | .Search(this.searchInput1, this.entityTypes) 53 | .subscribe((data) => { 54 | this.data = data; 55 | this.isSpinning = false; 56 | }, error=>{ 57 | this.isSpinning = false; 58 | alert(error["message"]); 59 | });*/ 60 | 61 | this.data = this.getMockData(); 62 | this.renderTemplates = []; 63 | this.templateDictionary = this.data["value"][0]["resultTemplates"]; 64 | for(let hit of this.data["value"][0]["hitsContainers"]["0"]["hits"]){ 65 | this.renderTemplates.push(this.renderACT(hit)); 66 | } 67 | console.log(this.renderTemplates); 68 | } 69 | 70 | 71 | renderACT(hit){ 72 | var templateId = hit["resultTemplateId"]; 73 | // Define a template payload 74 | var templatePayload = this.templateDictionary[templateId]["body"]; 75 | var template = new ACData.Template(templatePayload); 76 | 77 | // Expand the template with your `$root` data object. 78 | // This binds it to the data and produces the final Adaptive Card payload 79 | var context = new ACData.EvaluationContext(); 80 | context.$root = hit.resource; 81 | var card = template.expand(context); 82 | 83 | // OPTIONAL: Render the card (requires that the adaptivecards library be loaded) 84 | var adaptiveCard = new AdaptiveCards.AdaptiveCard(); 85 | adaptiveCard.parse(card); 86 | return this.sanitizer.bypassSecurityTrustHtml(adaptiveCard.render().outerHTML); 87 | } 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | setEntityTypes(value: string[]): void { 96 | this.entityTypes = value; 97 | } 98 | 99 | configOpen(): void { 100 | this.showConfiguration = true; 101 | } 102 | 103 | configClose(): void { 104 | this.showConfiguration = false; 105 | } 106 | 107 | codeOpen(): void { 108 | this.showCode = true; 109 | } 110 | 111 | codeClose(): void { 112 | this.showCode = false; 113 | } 114 | 115 | 116 | 117 | getMockData(){ 118 | return { 119 | "@odata.context": "https://graph.microsoft.com/v1.0/$metadata#Collection(microsoft.graph.searchResponse)", 120 | "value": [ 121 | { 122 | "searchTerms": [], 123 | "hitsContainers": [ 124 | { 125 | "total": 1201701, 126 | "moreResultsAvailable": true, 127 | "hits": [ 128 | { 129 | "hitId": "85437765-b430-434f-a945-38eceead5b93", 130 | "rank": 1, 131 | "summary": "", 132 | "resultTemplateId": "1603900360618_5XCBK2OXG", 133 | "resource": { 134 | "@odata.type": "#microsoft.graph.externalItem", 135 | "id": "B5B6E9C7-152C-4478-BCCB-CEF053F17397", 136 | "Title": "[SM00186] Number of tests - Liquid", 137 | "URL": "https://liquid.microsoft.com/Web/Object/Read/scanningtoolwarnings/Requirements/CodeQL.SM00186" 138 | } 139 | }, 140 | { 141 | "hitId": "85437765-5430-434f-a945-38eceead5b94", 142 | "rank": 2, 143 | "summary": "", 144 | "resultTemplateId": "1603900360618_5XCBK2OXP", 145 | "resource": { 146 | "@odata.type": "#microsoft.graph.externalItem", 147 | "title": "Publish Adaptive Card Schema", 148 | "description": "Now that we have defined the main rules and features of the format, we need to produce a schema and publish it to GitHub. The schema will be the starting point of our reference documentation.", 149 | "creator": { 150 | "name": "Matt Hidinger", 151 | "profileImage": "https://pbs.twimg.com/profile_images/3647943215/d7f12830b3c17a5a9e4afcc370e3a37e_400x400.jpeg" 152 | }, 153 | "createdUtc": "2017-02-14T06:08:39Z", 154 | "viewUrl": "https://adaptivecards.io", 155 | "properties": [ 156 | { 157 | "key": "Board", 158 | "value": "Adaptive Cards" 159 | }, 160 | { 161 | "key": "List", 162 | "value": "Backlog" 163 | }, 164 | { 165 | "key": "Assigned to", 166 | "value": "Matt Hidinger" 167 | }, 168 | { 169 | "key": "Due date", 170 | "value": "Not set" 171 | } 172 | ] 173 | } 174 | }, 175 | { 176 | "hitId": "85437765-b430-434f-a945-38eceead5b95", 177 | "rank": 3, 178 | "summary": "", 179 | "resultTemplateId": "1603900360618_5XCBK2OXG", 180 | "resource": { 181 | "@odata.type": "#microsoft.graph.externalItem", 182 | "id": "B5B6E9C7-152C-4478-BCCB-CEF053F17399", 183 | "Title": "[SM00186] Number of tests - Liquid 3", 184 | "URL": "https://liquid.microsoft.com/Web/Object/Read/scanningtoolwarnings/Requirements/CodeQL.SM00186" 185 | } 186 | } 187 | ] 188 | } 189 | ], 190 | "resultTemplates": { 191 | "1603900360618_5XCBK2OXG": { 192 | "displayName": "Liquid-3", 193 | "body": { 194 | "type": "AdaptiveCard", 195 | "version": "1.0", 196 | "body": [ 197 | { 198 | "type": "ColumnSet", 199 | "columns": [ 200 | { 201 | "type": "Column", 202 | "width": "auto", 203 | "items": [ 204 | { 205 | "type": "Image", 206 | "url": "https://searchuxcdn.azureedge.net/designerapp/images/LiquidLogo.png", 207 | "horizontalAlignment": "Center", 208 | "size": "Small" 209 | } 210 | ], 211 | "horizontalAlignment": "Center" 212 | }, 213 | { 214 | "type": "Column", 215 | "width": 10, 216 | "items": [ 217 | { 218 | "type": "TextBlock", 219 | "text": "[{Title}]({URL})", 220 | "weight": "Bolder", 221 | "color": "Accent", 222 | "size": "Medium", 223 | "maxLines": 3 224 | }, 225 | { 226 | "type": "TextBlock", 227 | "text": "{ResultSnippet}", 228 | "maxLines": 3, 229 | "wrap": true 230 | } 231 | ], 232 | "spacing": "Medium" 233 | } 234 | ] 235 | } 236 | ], 237 | "$schema": "http://adaptivecards.io/schemas/adaptive-card.json" 238 | } 239 | }, 240 | "1603900360618_5XCBK2OXP": { 241 | "displayName": "Liquid-2", 242 | "body": { 243 | "type": "AdaptiveCard", 244 | "body": [ 245 | { 246 | "type": "TextBlock", 247 | "size": "Medium", 248 | "weight": "Bolder", 249 | "text": "{title}" 250 | }, 251 | { 252 | "type": "ColumnSet", 253 | "columns": [ 254 | { 255 | "type": "Column", 256 | "items": [ 257 | { 258 | "type": "Image", 259 | "style": "Person", 260 | "url": "{creator.profileImage}", 261 | "size": "Small" 262 | } 263 | ], 264 | "width": "auto" 265 | }, 266 | { 267 | "type": "Column", 268 | "items": [ 269 | { 270 | "type": "TextBlock", 271 | "weight": "Bolder", 272 | "text": "{creator.name}", 273 | "wrap": true 274 | }, 275 | { 276 | "type": "TextBlock", 277 | "spacing": "None", 278 | "text": "Created {{DATE({createdUtc},SHORT)}}", 279 | "isSubtle": true, 280 | "wrap": true 281 | } 282 | ], 283 | "width": "stretch" 284 | } 285 | ] 286 | }, 287 | { 288 | "type": "TextBlock", 289 | "text": "{description}", 290 | "wrap": true 291 | }, 292 | { 293 | "type": "FactSet", 294 | "facts": [ 295 | { 296 | "$data": "{properties}", 297 | "title": "{key}:", 298 | "value": "{value}" 299 | } 300 | ] 301 | } 302 | ], 303 | "actions": [ 304 | { 305 | "type": "Action.ShowCard", 306 | "title": "Set due date", 307 | "card": { 308 | "type": "AdaptiveCard", 309 | "body": [ 310 | { 311 | "type": "Input.Date", 312 | "id": "dueDate" 313 | }, 314 | { 315 | "type": "Input.Text", 316 | "id": "comment", 317 | "placeholder": "Add a comment", 318 | "isMultiline": true 319 | } 320 | ], 321 | "actions": [ 322 | { 323 | "type": "Action.Submit", 324 | "title": "OK" 325 | } 326 | ], 327 | "$schema": "http://adaptivecards.io/schemas/adaptive-card.json" 328 | } 329 | }, 330 | { 331 | "type": "Action.OpenUrl", 332 | "title": "View", 333 | "url": "{viewUrl}" 334 | } 335 | ], 336 | "$schema": "http://adaptivecards.io/schemas/adaptive-card.json", 337 | "version": "1.3" 338 | } 339 | } 340 | } 341 | } 342 | ] 343 | }; 344 | 345 | } 346 | } --------------------------------------------------------------------------------