├── graph-tutorial
├── style.css
├── g-raph.png
├── config.example.js
├── auth.js
├── index.html
├── graph.js
├── timezones.js
└── ui.js
├── .gitignore
├── .gitattributes
├── CODE_OF_CONDUCT.md
├── .github
├── ISSUE_TEMPLATE
│ ├── ask-a-question.md
│ └── bug_report.md
└── policies
│ └── resourceManagement.yml
├── LICENSE
├── SECURITY.md
└── README.md
/graph-tutorial/style.css:
--------------------------------------------------------------------------------
1 | body {
2 | padding-top: 70px;
3 | }
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Visual Studio Code
2 | .vscode/
3 |
4 | config.js
5 | custom.js
6 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Set the default behavior, in case people don't have core.autocrlf set.
2 | * text=auto
3 |
--------------------------------------------------------------------------------
/graph-tutorial/g-raph.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoftgraph/msgraph-sample-javascriptspa/HEAD/graph-tutorial/g-raph.png
--------------------------------------------------------------------------------
/graph-tutorial/config.example.js:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation.
2 | // Licensed under the MIT License.
3 |
4 | const msalConfig = {
5 | auth: {
6 | clientId: 'YOUR_APP_ID_HERE',
7 | redirectUri: 'http://localhost:8080'
8 | }
9 | };
10 |
11 | const msalRequest = {
12 | scopes: [
13 | 'user.read',
14 | 'mailboxsettings.read',
15 | 'calendars.readwrite'
16 | ]
17 | }
18 |
--------------------------------------------------------------------------------
/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | # Microsoft Open Source Code of Conduct
2 |
3 | This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/).
4 |
5 | Resources:
6 |
7 | - [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/)
8 | - [Microsoft Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/)
9 | - Contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with questions or concerns
10 | - Employees can reach out at [aka.ms/opensource/moderation-support](https://aka.ms/opensource/moderation-support)
11 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/ask-a-question.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Ask a question
3 | about: Ask a question about Graph, adding features to this sample, etc.
4 | title: ''
5 | labels: question, needs triage
6 | assignees: ''
7 |
8 | ---
9 |
10 | Thank you for taking an interest in Microsoft Graph development! Please feel free to ask a question here, but keep in mind the following:
11 |
12 | - This is not an official Microsoft support channel, and our ability to respond to questions here is limited. Questions about Graph, or questions about adding a new feature to the sample, will be answered on a best-effort basis.
13 | - Questions should be asked on [Microsoft Q&A](https://docs.microsoft.com/answers/products/graph).
14 | - Issues with Microsoft Graph itself should be handled through [support](https://developer.microsoft.com/graph/support).
15 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug_report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Bug report
3 | about: Create a report to help us improve
4 | title: ''
5 | labels: bug report, needs triage
6 | assignees: ''
7 |
8 | ---
9 |
10 | **Describe the bug**
11 | A clear and concise description of what the bug is.
12 |
13 | **To Reproduce**
14 | Steps to reproduce the behavior:
15 | 1. Go to '...'
16 | 2. Click on '....'
17 | 3. Scroll down to '....'
18 | 4. See error
19 |
20 | **Expected behavior**
21 | A clear and concise description of what you expected to happen.
22 |
23 | **Screenshots**
24 | If applicable, add screenshots to help explain your problem.
25 |
26 | **Desktop (please complete the following information):**
27 | - OS: [e.g. iOS]
28 | - Browser [e.g. chrome, safari]
29 | - Version [e.g. 22]
30 |
31 | **Dependency versions**
32 | - Authentication library (MSAL, etc.) version:
33 | - Graph library (Graph SDK, REST library, etc.) version:
34 |
35 | **Additional context**
36 | Add any other context about the problem here.
37 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) Microsoft Corporation.
2 |
3 | MIT License
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 |
--------------------------------------------------------------------------------
/graph-tutorial/auth.js:
--------------------------------------------------------------------------------
1 |
2 | // Copyright (c) Microsoft Corporation.
3 | // Licensed under the MIT License.
4 |
5 | //
6 | // Create the main MSAL instance
7 | // configuration parameters are located in config.js
8 | const msalClient = new msal.PublicClientApplication(msalConfig);
9 | //
10 |
11 | //
12 | // Check for an already logged-in user
13 | const account = msalClient.getActiveAccount();
14 | if (account) {
15 | initializeGraphClient(msalClient, account, msalRequest.scopes);
16 | }
17 | //
18 |
19 | //
20 | async function signIn() {
21 | // Login
22 | try {
23 | // Use MSAL to login
24 | const authResult = await msalClient.loginPopup(msalRequest);
25 | console.log('id_token acquired at: ' + new Date().toString());
26 |
27 | msalClient.setActiveAccount(authResult.account);
28 |
29 | // Initialize the Graph client
30 | initializeGraphClient(msalClient, authResult.account, msalRequest.scopes);
31 |
32 | // Get the user's profile from Graph
33 | const user = await getUser();
34 | // Save the profile in session
35 | sessionStorage.setItem('graphUser', JSON.stringify(user));
36 | updatePage(Views.home);
37 | } catch (error) {
38 | console.log(error);
39 | updatePage(Views.error, {
40 | message: 'Error logging in',
41 | debug: error
42 | });
43 | }
44 | }
45 | //
46 |
47 | //
48 | function signOut() {
49 | sessionStorage.removeItem('graphUser');
50 | msalClient.logout();
51 | }
52 | //
--------------------------------------------------------------------------------
/SECURITY.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | ## Security
4 |
5 | Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet), [Xamarin](https://github.com/xamarin), and [our GitHub organizations](https://opensource.microsoft.com/).
6 |
7 | If you believe you have found a security vulnerability in any Microsoft-owned repository that meets [Microsoft's definition of a security vulnerability](https://aka.ms/opensource/security/definition), please report it to us as described below.
8 |
9 | ## Reporting Security Issues
10 |
11 | **Please do not report security vulnerabilities through public GitHub issues.**
12 |
13 | Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://aka.ms/opensource/security/create-report).
14 |
15 | If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your message with our PGP key; please download it from the [Microsoft Security Response Center PGP Key page](https://aka.ms/opensource/security/pgpkey).
16 |
17 | You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://aka.ms/opensource/security/msrc).
18 |
19 | Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue:
20 |
21 | * Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.)
22 | * Full paths of source file(s) related to the manifestation of the issue
23 | * The location of the affected source code (tag/branch/commit or direct URL)
24 | * Any special configuration required to reproduce the issue
25 | * Step-by-step instructions to reproduce the issue
26 | * Proof-of-concept or exploit code (if possible)
27 | * Impact of the issue, including how an attacker might exploit the issue
28 |
29 | This information will help us triage your report more quickly.
30 |
31 | If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://aka.ms/opensource/security/bounty) page for more details about our active programs.
32 |
33 | ## Preferred Languages
34 |
35 | We prefer all communications to be in English.
36 |
37 | ## Policy
38 |
39 | Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://aka.ms/opensource/security/cvd).
40 |
41 |
42 |
--------------------------------------------------------------------------------
/graph-tutorial/index.html:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 | JavaScript SPA Graph Tutorial
11 |
12 |
13 |
16 |
17 |
18 |
19 |
20 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ---
2 | page_type: sample
3 | description: This sample demonstrates how to use the Microsoft Graph JavaScript SDK to access data in Office 365 from JavaScript browser apps.
4 | products:
5 | - ms-graph
6 | - office-exchange-online
7 | languages:
8 | - javascript
9 | ---
10 |
11 | # Microsoft Graph sample JavaScript single-page app
12 |
13 | This sample demonstrates how to use the Microsoft Graph JavaScript SDK to access data in Office 365 from JavaScript browser apps.
14 |
15 | ## Prerequisites
16 |
17 | Before you start this tutorial, you will need access to an HTTP server to host the sample files. This could be a test server on your development machine, or a remote server.
18 |
19 | You should also have either a personal Microsoft account with a mailbox on Outlook.com, or a Microsoft work or school account. If you don't have a Microsoft account, there are a couple of options to get a free account:
20 |
21 | - You can [sign up for a new personal Microsoft account](https://signup.live.com/signup?wa=wsignin1.0&rpsnv=12&ct=1454618383&rver=6.4.6456.0&wp=MBI_SSL_SHARED&wreply=https://mail.live.com/default.aspx&id=64855&cbcxt=mai&bk=1454618383&uiflavor=web&uaid=b213a65b4fdc484382b6622b3ecaa547&mkt=E-US&lc=1033&lic=1).
22 | - You can [sign up for the Microsoft 365 Developer Program](https://developer.microsoft.com/microsoft-365/dev-program) to get a free Microsoft 365 subscription.
23 |
24 | ## Register the app
25 |
26 | Create a new Azure AD web application registration using the Azure Active Directory admin center.
27 |
28 | 1. Open a browser and navigate to the [Azure Active Directory admin center](https://aad.portal.azure.com). Login using a **personal account** (aka: Microsoft Account) or **Work or School Account**.
29 |
30 | 1. Select **Azure Active Directory** in the left-hand navigation, then select **App registrations** under **Manage**.
31 |
32 | > [!NOTE]
33 | > Azure AD B2C users may only see **App registrations (legacy)**. In this case, please go directly to [https://aka.ms/appregistrations](https://aka.ms/appregistrations).
34 |
35 | 1. Select **New registration**. On the **Register an application** page, set the values as follows.
36 |
37 | - Set **Name** to `JavaScript Graph Tutorial`.
38 | - Set **Supported account types** to **Accounts in any organizational directory and personal Microsoft accounts**.
39 | - Under **Redirect URI**, set the first drop-down to `Single-page application (SPA)` and set the value to `http://localhost:8080`.
40 |
41 | 1. Choose **Register**. On the **JavaScript Graph Tutorial** page, copy the value of the **Application (client) ID** and save it, you will need it in the next step.
42 |
43 | ## Configure the sample
44 |
45 | 1. Rename the `./graph-tutorial/src/Config.example.js` file to `./graph-tutorial/src/Config.js`.
46 | 1. Edit the `./graph-tutorial/src/Config.js` file and make the following changes.
47 | 1. Replace `YOUR_APP_ID_HERE` with the **Application Id** you got from the App Registration Portal.
48 |
49 | > [!NOTE]
50 | > The steps in this section require [Node.js](https://nodejs.org).
51 |
52 | ## Running the sample
53 |
54 | Host the files in the [graph-tutorial](graph-tutorial) directory on your HTTP server. If you don't have access to a server, here are a couple of options for test server tools to run on your development machine.
55 |
56 | ### http-server
57 |
58 | If you have [Node.js](https://nodejs.org), [http-server](https://www.npmjs.com/package/http-server) is a simple command-line HTTP server.
59 |
60 | 1. Open your command-line interface (CLI) in the **graph-tutorial** directory.
61 | 1. Run the following command to start a web server in that directory.
62 |
63 | ```bash
64 | npx http-server -c-1 -p 8080
65 | ```
66 |
67 | 1. Open your browser and browse to `http://localhost:8080`.
68 |
69 | ### dotnet-serve
70 |
71 | If you have the .NET SDK installed, [dotnet-serve] is a simple command-line HTTP server.
72 |
73 | 1. Open your command-line interface (CLI) in the **graph-tutorial** directory.
74 | 1. Run the following command to start a web server in that directory.
75 |
76 | ```bash
77 | dotnet serve -p 8080
78 | ```
79 |
80 | 1. Open your browser and browse to `http://localhost:8080`.
81 |
82 | ## Code of conduct
83 |
84 | This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.
85 |
86 | ## Disclaimer
87 |
88 | **THIS CODE IS PROVIDED _AS IS_ WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.**
89 |
--------------------------------------------------------------------------------
/graph-tutorial/graph.js:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation.
2 | // Licensed under the MIT License.
3 |
4 | //
5 | let graphClient = undefined;
6 |
7 | function initializeGraphClient(msalClient, account, scopes)
8 | {
9 | // Create an authentication provider
10 | const authProvider = new MSGraphAuthCodeMSALBrowserAuthProvider
11 | .AuthCodeMSALBrowserAuthenticationProvider(msalClient, {
12 | account: account,
13 | scopes: scopes,
14 | interactionType: msal.InteractionType.PopUp
15 | });
16 |
17 | // Initialize the Graph client
18 | graphClient = MicrosoftGraph.Client.initWithMiddleware({authProvider});
19 | }
20 | //
21 |
22 | //
23 | async function getUser() {
24 | return graphClient
25 | .api('/me')
26 | // Only get the fields used by the app
27 | .select('id,displayName,mail,userPrincipalName,mailboxSettings')
28 | .get();
29 | }
30 | //
31 |
32 | //
33 | async function getEvents() {
34 | const user = JSON.parse(sessionStorage.getItem('graphUser'));
35 |
36 | // Convert user's Windows time zone ("Pacific Standard Time")
37 | // to IANA format ("America/Los_Angeles")
38 | // Moment needs IANA format
39 | let ianaTimeZone = getIanaFromWindows(user.mailboxSettings.timeZone);
40 | console.log(`Converted: ${ianaTimeZone}`);
41 |
42 | // Configure a calendar view for the current week
43 | // Get midnight on the start of the current week in the user's timezone,
44 | // but in UTC. For example, for Pacific Standard Time, the time value would be
45 | // 07:00:00Z
46 | let startOfWeek = moment.tz(ianaTimeZone).startOf('week').utc();
47 | // Set end of the view to 7 days after start of week
48 | let endOfWeek = moment(startOfWeek).add(7, 'day');
49 |
50 | try {
51 | // GET /me/calendarview?startDateTime=''&endDateTime=''
52 | // &$select=subject,organizer,start,end
53 | // &$orderby=start/dateTime
54 | // &$top=50
55 | let response = await graphClient
56 | .api('/me/calendarview')
57 | // Set the Prefer=outlook.timezone header so date/times are in
58 | // user's preferred time zone
59 | .header("Prefer", `outlook.timezone="${user.mailboxSettings.timeZone}"`)
60 | // Add the startDateTime and endDateTime query parameters
61 | .query({ startDateTime: startOfWeek.format(), endDateTime: endOfWeek.format() })
62 | // Select just the fields we are interested in
63 | .select('subject,organizer,start,end')
64 | // Sort the results by start, earliest first
65 | .orderby('start/dateTime')
66 | // Maximum 50 events in response
67 | .top(50)
68 | .get();
69 |
70 | updatePage(Views.calendar, response.value);
71 | } catch (error) {
72 | updatePage(Views.error, {
73 | message: 'Error getting events',
74 | debug: error
75 | });
76 | }
77 | }
78 | //
79 |
80 | //
81 | async function createNewEvent() {
82 | const user = JSON.parse(sessionStorage.getItem('graphUser'));
83 |
84 | // Get the user's input
85 | const subject = document.getElementById('ev-subject').value;
86 | const attendees = document.getElementById('ev-attendees').value;
87 | const start = document.getElementById('ev-start').value;
88 | const end = document.getElementById('ev-end').value;
89 | const body = document.getElementById('ev-body').value;
90 |
91 | // Require at least subject, start, and end
92 | if (!subject || !start || !end) {
93 | updatePage(Views.error, {
94 | message: 'Please provide a subject, start, and end.'
95 | });
96 | return;
97 | }
98 |
99 | // Build the JSON payload of the event
100 | let newEvent = {
101 | subject: subject,
102 | start: {
103 | dateTime: start,
104 | timeZone: user.mailboxSettings.timeZone
105 | },
106 | end: {
107 | dateTime: end,
108 | timeZone: user.mailboxSettings.timeZone
109 | }
110 | };
111 |
112 | if (attendees)
113 | {
114 | const attendeeArray = attendees.split(';');
115 | newEvent.attendees = [];
116 |
117 | for (const attendee of attendeeArray) {
118 | if (attendee.length > 0) {
119 | newEvent.attendees.push({
120 | type: 'required',
121 | emailAddress: {
122 | address: attendee
123 | }
124 | });
125 | }
126 | }
127 | }
128 |
129 | if (body)
130 | {
131 | newEvent.body = {
132 | contentType: 'text',
133 | content: body
134 | };
135 | }
136 |
137 | try {
138 | // POST the JSON to the /me/events endpoint
139 | await graphClient
140 | .api('/me/events')
141 | .post(newEvent);
142 |
143 | // Return to the calendar view
144 | getEvents();
145 | } catch (error) {
146 | updatePage(Views.error, {
147 | message: 'Error creating event',
148 | debug: error
149 | });
150 | }
151 | }
152 | //
--------------------------------------------------------------------------------
/.github/policies/resourceManagement.yml:
--------------------------------------------------------------------------------
1 | id:
2 | name: GitOps.PullRequestIssueManagement
3 | description: GitOps.PullRequestIssueManagement primitive
4 | owner:
5 | resource: repository
6 | disabled: false
7 | where:
8 | configuration:
9 | resourceManagementConfiguration:
10 | scheduledSearches:
11 | - description:
12 | frequencies:
13 | - hourly:
14 | hour: 6
15 | filters:
16 | - isIssue
17 | - isOpen
18 | - hasLabel:
19 | label: needs author feedback
20 | - hasLabel:
21 | label: no recent activity
22 | - noActivitySince:
23 | days: 3
24 | actions:
25 | - closeIssue
26 | - description:
27 | frequencies:
28 | - hourly:
29 | hour: 6
30 | filters:
31 | - isIssue
32 | - isOpen
33 | - hasLabel:
34 | label: needs author feedback
35 | - noActivitySince:
36 | days: 4
37 | - isNotLabeledWith:
38 | label: no recent activity
39 | actions:
40 | - addLabel:
41 | label: no recent activity
42 | - addReply:
43 | reply: This issue has been automatically marked as stale because it has been marked as requiring author feedback but has not had any activity for **4 days**. It will be closed if no further activity occurs **within 3 days of this comment**.
44 | - description:
45 | frequencies:
46 | - hourly:
47 | hour: 6
48 | filters:
49 | - isIssue
50 | - isOpen
51 | - hasLabel:
52 | label: duplicate
53 | - noActivitySince:
54 | days: 1
55 | actions:
56 | - addReply:
57 | reply: This issue has been marked as duplicate and has not had any activity for **1 day**. It will be closed for housekeeping purposes.
58 | - closeIssue
59 | - description:
60 | frequencies:
61 | - hourly:
62 | hour: 3
63 | filters:
64 | - isOpen
65 | - isIssue
66 | - hasLabel:
67 | label: graph question
68 | actions:
69 | - removeLabel:
70 | label: 'needs attention :wave:'
71 | - removeLabel:
72 | label: needs author feedback
73 | - removeLabel:
74 | label: 'needs triage :mag:'
75 | - removeLabel:
76 | label: no recent activity
77 | - addLabel:
78 | label: out of scope
79 | - addReply:
80 | reply: >-
81 | It looks like you are asking a question about using Microsoft Graph or one of the Microsoft Graph SDKs that is not directly related to this sample. Unfortunately we are not set up to answer general questions in this repository, so this issue will be closed.
82 |
83 |
84 | Please try asking your question on [Stack Overflow](https://stackoverflow.com/questions/tagged/microsoft-graph-api), tagging your question with `microsoft-graph-api`.
85 | - closeIssue
86 | - description:
87 | frequencies:
88 | - hourly:
89 | hour: 3
90 | filters:
91 | - isOpen
92 | - isIssue
93 | - hasLabel:
94 | label: graph issue
95 | actions:
96 | - removeLabel:
97 | label: 'needs attention :wave:'
98 | - removeLabel:
99 | label: needs author feedback
100 | - removeLabel:
101 | label: 'needs triage :mag:'
102 | - removeLabel:
103 | label: no recent activity
104 | - addLabel:
105 | label: out of scope
106 | - addReply:
107 | reply: >-
108 | It looks like you are reporting an issue with Microsoft Graph or one of the Microsoft Graph SDKs that is not fixable by changing code in this sample. Unfortunately we are not set up to provide product support in this repository, so this issue will be closed.
109 |
110 |
111 | Please visit one of the following links to report your issue.
112 |
113 |
114 | - Issue with Microsoft Graph service: [Microsoft Graph support](https://developer.microsoft.com/graph/support#report-issues-with-the-service), choose one of the options under **Report issues with the service**
115 |
116 | - Issue with a Microsoft Graph SDK: Open an issue in the SDK's GitHub repository. See [microsoftgraph on GitHub](https://github.com/microsoftgraph?q=sdk+in%3Aname&type=public&language=) for a list of SDK repositories.
117 | - closeIssue
118 | eventResponderTasks:
119 | - if:
120 | - payloadType: Issue_Comment
121 | - isAction:
122 | action: Created
123 | - isActivitySender:
124 | issueAuthor: True
125 | - hasLabel:
126 | label: needs author feedback
127 | - isOpen
128 | then:
129 | - addLabel:
130 | label: 'needs attention :wave:'
131 | - removeLabel:
132 | label: needs author feedback
133 | description:
134 | - if:
135 | - payloadType: Issues
136 | - not:
137 | isAction:
138 | action: Closed
139 | - hasLabel:
140 | label: no recent activity
141 | then:
142 | - removeLabel:
143 | label: no recent activity
144 | description:
145 | - if:
146 | - payloadType: Issue_Comment
147 | - hasLabel:
148 | label: no recent activity
149 | then:
150 | - removeLabel:
151 | label: no recent activity
152 | description:
153 | - if:
154 | - payloadType: Pull_Request
155 | then:
156 | - inPrLabel:
157 | label: in pr
158 | description:
159 | onFailure:
160 | onSuccess:
161 |
--------------------------------------------------------------------------------
/graph-tutorial/timezones.js:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation.
2 | // Licensed under the MIT License.
3 | /* spell-checker: disable */
4 |
5 | //
6 | // Basic lookup for mapping Windows time zone identifiers to
7 | // IANA identifiers
8 | // Mappings taken from
9 | // https://github.com/unicode-org/cldr/blob/master/common/supplemental/windowsZones.xml
10 | const zoneMappings = {
11 | "Dateline Standard Time": "Etc/GMT+12",
12 | "UTC-11": "Etc/GMT+11",
13 | "Aleutian Standard Time": "America/Adak",
14 | "Hawaiian Standard Time": "Pacific/Honolulu",
15 | "Marquesas Standard Time": "Pacific/Marquesas",
16 | "Alaskan Standard Time": "America/Anchorage",
17 | "UTC-09": "Etc/GMT+9",
18 | "Pacific Standard Time (Mexico)": "America/Tijuana",
19 | "UTC-08": "Etc/GMT+8",
20 | "Pacific Standard Time": "America/Los_Angeles",
21 | "US Mountain Standard Time": "America/Phoenix",
22 | "Mountain Standard Time (Mexico)": "America/Chihuahua",
23 | "Mountain Standard Time": "America/Denver",
24 | "Central America Standard Time": "America/Guatemala",
25 | "Central Standard Time": "America/Chicago",
26 | "Easter Island Standard Time": "Pacific/Easter",
27 | "Central Standard Time (Mexico)": "America/Mexico_City",
28 | "Canada Central Standard Time": "America/Regina",
29 | "SA Pacific Standard Time": "America/Bogota",
30 | "Eastern Standard Time (Mexico)": "America/Cancun",
31 | "Eastern Standard Time": "America/New_York",
32 | "Haiti Standard Time": "America/Port-au-Prince",
33 | "Cuba Standard Time": "America/Havana",
34 | "US Eastern Standard Time": "America/Indianapolis",
35 | "Turks And Caicos Standard Time": "America/Grand_Turk",
36 | "Paraguay Standard Time": "America/Asuncion",
37 | "Atlantic Standard Time": "America/Halifax",
38 | "Venezuela Standard Time": "America/Caracas",
39 | "Central Brazilian Standard Time": "America/Cuiaba",
40 | "SA Western Standard Time": "America/La_Paz",
41 | "Pacific SA Standard Time": "America/Santiago",
42 | "Newfoundland Standard Time": "America/St_Johns",
43 | "Tocantins Standard Time": "America/Araguaina",
44 | "E. South America Standard Time": "America/Sao_Paulo",
45 | "SA Eastern Standard Time": "America/Cayenne",
46 | "Argentina Standard Time": "America/Buenos_Aires",
47 | "Greenland Standard Time": "America/Godthab",
48 | "Montevideo Standard Time": "America/Montevideo",
49 | "Magallanes Standard Time": "America/Punta_Arenas",
50 | "Saint Pierre Standard Time": "America/Miquelon",
51 | "Bahia Standard Time": "America/Bahia",
52 | "UTC-02": "Etc/GMT+2",
53 | "Azores Standard Time": "Atlantic/Azores",
54 | "Cape Verde Standard Time": "Atlantic/Cape_Verde",
55 | "UTC": "Etc/GMT",
56 | "GMT Standard Time": "Europe/London",
57 | "Greenwich Standard Time": "Atlantic/Reykjavik",
58 | "Sao Tome Standard Time": "Africa/Sao_Tome",
59 | "Morocco Standard Time": "Africa/Casablanca",
60 | "W. Europe Standard Time": "Europe/Berlin",
61 | "Central Europe Standard Time": "Europe/Budapest",
62 | "Romance Standard Time": "Europe/Paris",
63 | "Central European Standard Time": "Europe/Warsaw",
64 | "W. Central Africa Standard Time": "Africa/Lagos",
65 | "Jordan Standard Time": "Asia/Amman",
66 | "GTB Standard Time": "Europe/Bucharest",
67 | "Middle East Standard Time": "Asia/Beirut",
68 | "Egypt Standard Time": "Africa/Cairo",
69 | "E. Europe Standard Time": "Europe/Chisinau",
70 | "Syria Standard Time": "Asia/Damascus",
71 | "West Bank Standard Time": "Asia/Hebron",
72 | "South Africa Standard Time": "Africa/Johannesburg",
73 | "FLE Standard Time": "Europe/Kiev",
74 | "Israel Standard Time": "Asia/Jerusalem",
75 | "Kaliningrad Standard Time": "Europe/Kaliningrad",
76 | "Sudan Standard Time": "Africa/Khartoum",
77 | "Libya Standard Time": "Africa/Tripoli",
78 | "Namibia Standard Time": "Africa/Windhoek",
79 | "Arabic Standard Time": "Asia/Baghdad",
80 | "Turkey Standard Time": "Europe/Istanbul",
81 | "Arab Standard Time": "Asia/Riyadh",
82 | "Belarus Standard Time": "Europe/Minsk",
83 | "Russian Standard Time": "Europe/Moscow",
84 | "E. Africa Standard Time": "Africa/Nairobi",
85 | "Iran Standard Time": "Asia/Tehran",
86 | "Arabian Standard Time": "Asia/Dubai",
87 | "Astrakhan Standard Time": "Europe/Astrakhan",
88 | "Azerbaijan Standard Time": "Asia/Baku",
89 | "Russia Time Zone 3": "Europe/Samara",
90 | "Mauritius Standard Time": "Indian/Mauritius",
91 | "Saratov Standard Time": "Europe/Saratov",
92 | "Georgian Standard Time": "Asia/Tbilisi",
93 | "Volgograd Standard Time": "Europe/Volgograd",
94 | "Caucasus Standard Time": "Asia/Yerevan",
95 | "Afghanistan Standard Time": "Asia/Kabul",
96 | "West Asia Standard Time": "Asia/Tashkent",
97 | "Ekaterinburg Standard Time": "Asia/Yekaterinburg",
98 | "Pakistan Standard Time": "Asia/Karachi",
99 | "Qyzylorda Standard Time": "Asia/Qyzylorda",
100 | "India Standard Time": "Asia/Calcutta",
101 | "Sri Lanka Standard Time": "Asia/Colombo",
102 | "Nepal Standard Time": "Asia/Katmandu",
103 | "Central Asia Standard Time": "Asia/Almaty",
104 | "Bangladesh Standard Time": "Asia/Dhaka",
105 | "Omsk Standard Time": "Asia/Omsk",
106 | "Myanmar Standard Time": "Asia/Rangoon",
107 | "SE Asia Standard Time": "Asia/Bangkok",
108 | "Altai Standard Time": "Asia/Barnaul",
109 | "W. Mongolia Standard Time": "Asia/Hovd",
110 | "North Asia Standard Time": "Asia/Krasnoyarsk",
111 | "N. Central Asia Standard Time": "Asia/Novosibirsk",
112 | "Tomsk Standard Time": "Asia/Tomsk",
113 | "China Standard Time": "Asia/Shanghai",
114 | "North Asia East Standard Time": "Asia/Irkutsk",
115 | "Singapore Standard Time": "Asia/Singapore",
116 | "W. Australia Standard Time": "Australia/Perth",
117 | "Taipei Standard Time": "Asia/Taipei",
118 | "Ulaanbaatar Standard Time": "Asia/Ulaanbaatar",
119 | "Aus Central W. Standard Time": "Australia/Eucla",
120 | "Transbaikal Standard Time": "Asia/Chita",
121 | "Tokyo Standard Time": "Asia/Tokyo",
122 | "North Korea Standard Time": "Asia/Pyongyang",
123 | "Korea Standard Time": "Asia/Seoul",
124 | "Yakutsk Standard Time": "Asia/Yakutsk",
125 | "Cen. Australia Standard Time": "Australia/Adelaide",
126 | "AUS Central Standard Time": "Australia/Darwin",
127 | "E. Australia Standard Time": "Australia/Brisbane",
128 | "AUS Eastern Standard Time": "Australia/Sydney",
129 | "West Pacific Standard Time": "Pacific/Port_Moresby",
130 | "Tasmania Standard Time": "Australia/Hobart",
131 | "Vladivostok Standard Time": "Asia/Vladivostok",
132 | "Lord Howe Standard Time": "Australia/Lord_Howe",
133 | "Bougainville Standard Time": "Pacific/Bougainville",
134 | "Russia Time Zone 10": "Asia/Srednekolymsk",
135 | "Magadan Standard Time": "Asia/Magadan",
136 | "Norfolk Standard Time": "Pacific/Norfolk",
137 | "Sakhalin Standard Time": "Asia/Sakhalin",
138 | "Central Pacific Standard Time": "Pacific/Guadalcanal",
139 | "Russia Time Zone 11": "Asia/Kamchatka",
140 | "New Zealand Standard Time": "Pacific/Auckland",
141 | "UTC+12": "Etc/GMT-12",
142 | "Fiji Standard Time": "Pacific/Fiji",
143 | "Chatham Islands Standard Time": "Pacific/Chatham",
144 | "UTC+13": "Etc/GMT-13",
145 | "Tonga Standard Time": "Pacific/Tongatapu",
146 | "Samoa Standard Time": "Pacific/Apia",
147 | "Line Islands Standard Time": "Pacific/Kiritimati"
148 | };
149 |
150 | function getIanaFromWindows(windowsZoneName) {
151 | return zoneMappings[windowsZoneName] || "Etc/GMT";
152 | }
153 | //
--------------------------------------------------------------------------------
/graph-tutorial/ui.js:
--------------------------------------------------------------------------------
1 | //Copyright (c) Microsoft Corporation.
2 | //Licensed under the MIT License.
3 |
4 | // Select DOM elements to work with
5 | const authenticatedNav = document.getElementById('authenticated-nav');
6 | const accountNav = document.getElementById('account-nav');
7 | const mainContainer = document.getElementById('main-container');
8 |
9 | const Views = { error: 1, home: 2, calendar: 3 };
10 |
11 | function createElement(type, className, text) {
12 | var element = document.createElement(type);
13 | element.className = className;
14 |
15 | if (text) {
16 | var textNode = document.createTextNode(text);
17 | element.appendChild(textNode);
18 | }
19 |
20 | return element;
21 | }
22 |
23 | function showAuthenticatedNav(user, view) {
24 | authenticatedNav.innerHTML = '';
25 |
26 | if (user) {
27 | // Add Calendar link
28 | var calendarNav = createElement('li', 'nav-item');
29 |
30 | var calendarLink = createElement('button',
31 | `btn btn-link nav-link${view === Views.calendar ? ' active' : '' }`,
32 | 'Calendar');
33 | calendarLink.setAttribute('onclick', 'getEvents();');
34 | calendarNav.appendChild(calendarLink);
35 |
36 | authenticatedNav.appendChild(calendarNav);
37 | }
38 | }
39 |
40 | function showAccountNav(user) {
41 | accountNav.innerHTML = '';
42 |
43 | if (user) {
44 | // Show the "signed-in" nav
45 | accountNav.className = 'nav-item dropdown';
46 |
47 | var dropdown = createElement('a', 'nav-link dropdown-toggle');
48 | dropdown.setAttribute('data-bs-toggle', 'dropdown');
49 | dropdown.setAttribute('role', 'button');
50 | accountNav.appendChild(dropdown);
51 |
52 | let userIcon = createElement('img', 'rounded-circle align-self-center me-2');
53 | userIcon.style.width = '32px';
54 | userIcon.src = 'g-raph.png';
55 | userIcon.alt = 'user';
56 | dropdown.appendChild(userIcon);
57 |
58 | var menu = createElement('div', 'dropdown-menu dropdown-menu-end');
59 | accountNav.appendChild(menu);
60 |
61 | var userName = createElement('h5', 'dropdown-item-text mb-0', user.displayName);
62 | menu.appendChild(userName);
63 |
64 | var userEmail = createElement('p', 'dropdown-item-text text-muted mb-0', user.mail || user.userPrincipalName);
65 | menu.appendChild(userEmail);
66 |
67 | var divider = createElement('hr', 'dropdown-divider');
68 | menu.appendChild(divider);
69 |
70 | var signOutButton = createElement('button', 'dropdown-item', 'Sign out');
71 | signOutButton.setAttribute('onclick', 'signOut();');
72 | menu.appendChild(signOutButton);
73 | } else {
74 | // Show a "sign in" button
75 | accountNav.className = 'nav-item';
76 |
77 | var signInButton = createElement('button', 'btn btn-link nav-link', 'Sign in');
78 | signInButton.setAttribute('onclick', 'signIn();');
79 | accountNav.appendChild(signInButton);
80 | }
81 | }
82 |
83 | function showWelcomeMessage(user) {
84 | // Create jumbotron
85 | let jumbotron = createElement('div', 'p-5 mb-4 bg-light rounded-3');
86 |
87 | let container = createElement('div', 'container-fluid py-5');
88 | jumbotron.appendChild(container);
89 |
90 | let heading = createElement('h1', null, 'JavaScript SPA Graph Tutorial');
91 | container.appendChild(heading);
92 |
93 | let lead = createElement('p', 'lead',
94 | 'This sample app shows how to use the Microsoft Graph API to access' +
95 | ' a user\'s data from JavaScript.');
96 | container.appendChild(lead);
97 |
98 | if (user) {
99 | // Welcome the user by name
100 | let welcomeMessage = createElement('h4', null, `Welcome ${user.displayName}!`);
101 | container.appendChild(welcomeMessage);
102 |
103 | let callToAction = createElement('p', null,
104 | 'Use the navigation bar at the top of the page to get started.');
105 | container.appendChild(callToAction);
106 | } else {
107 | // Show a sign in button in the jumbotron
108 | let signInButton = createElement('button', 'btn btn-primary btn-large',
109 | 'Click here to sign in');
110 | signInButton.setAttribute('onclick', 'signIn();')
111 | container.appendChild(signInButton);
112 | }
113 |
114 | mainContainer.innerHTML = '';
115 | mainContainer.appendChild(jumbotron);
116 | }
117 |
118 | function showError(error) {
119 | var alert = createElement('div', 'alert alert-danger');
120 |
121 | var message = createElement('p', 'mb-3', error.message);
122 | alert.appendChild(message);
123 |
124 | if (error.debug)
125 | {
126 | var pre = createElement('pre', 'alert-pre border bg-light p-2');
127 | alert.appendChild(pre);
128 |
129 | var code = createElement('code', 'text-break text-wrap',
130 | JSON.stringify(error.debug, null, 2));
131 | pre.appendChild(code);
132 | }
133 |
134 | mainContainer.innerHTML = '';
135 | mainContainer.appendChild(alert);
136 | }
137 |
138 | function updatePage(view, data) {
139 | if (!view) {
140 | view = Views.home;
141 | }
142 |
143 | const user = JSON.parse(sessionStorage.getItem('graphUser'));
144 |
145 | showAccountNav(user);
146 | showAuthenticatedNav(user, view);
147 |
148 | switch (view) {
149 | case Views.error:
150 | showError(data);
151 | break;
152 | case Views.home:
153 | showWelcomeMessage(user);
154 | break;
155 | case Views.calendar:
156 | break;
157 | }
158 | }
159 |
160 | //
161 | function updatePage(view, data) {
162 | if (!view) {
163 | view = Views.home;
164 | }
165 |
166 | const user = JSON.parse(sessionStorage.getItem('graphUser'));
167 |
168 | showAccountNav(user);
169 | showAuthenticatedNav(user, view);
170 |
171 | switch (view) {
172 | case Views.error:
173 | showError(data);
174 | break;
175 | case Views.home:
176 | showWelcomeMessage(user);
177 | break;
178 | case Views.calendar:
179 | showCalendar(data);
180 | break;
181 | }
182 | }
183 | //
184 |
185 | //
186 | function showCalendar(events) {
187 | let div = document.createElement('div');
188 |
189 | div.appendChild(createElement('h1', 'mb-3', 'Calendar'));
190 |
191 | let newEventButton = createElement('button', 'btn btn-light btn-sm mb-3', 'New event');
192 | newEventButton.setAttribute('onclick', 'showNewEventForm();');
193 | div.appendChild(newEventButton);
194 |
195 | let table = createElement('table', 'table');
196 | div.appendChild(table);
197 |
198 | let thead = document.createElement('thead');
199 | table.appendChild(thead);
200 |
201 | let headerrow = document.createElement('tr');
202 | thead.appendChild(headerrow);
203 |
204 | let organizer = createElement('th', null, 'Organizer');
205 | organizer.setAttribute('scope', 'col');
206 | headerrow.appendChild(organizer);
207 |
208 | let subject = createElement('th', null, 'Subject');
209 | subject.setAttribute('scope', 'col');
210 | headerrow.appendChild(subject);
211 |
212 | let start = createElement('th', null, 'Start');
213 | start.setAttribute('scope', 'col');
214 | headerrow.appendChild(start);
215 |
216 | let end = createElement('th', null, 'End');
217 | end.setAttribute('scope', 'col');
218 | headerrow.appendChild(end);
219 |
220 | let tbody = document.createElement('tbody');
221 | table.appendChild(tbody);
222 |
223 | for (const event of events) {
224 | let eventrow = document.createElement('tr');
225 | eventrow.setAttribute('key', event.id);
226 | tbody.appendChild(eventrow);
227 |
228 | let organizercell = createElement('td', null, event.organizer.emailAddress.name);
229 | eventrow.appendChild(organizercell);
230 |
231 | let subjectcell = createElement('td', null, event.subject);
232 | eventrow.appendChild(subjectcell);
233 |
234 | // Use moment.utc() here because times are already in the user's
235 | // preferred timezone, and we don't want moment to try to change them to the
236 | // browser's timezone
237 | let startcell = createElement('td', null,
238 | moment.utc(event.start.dateTime).format('M/D/YY h:mm A'));
239 | eventrow.appendChild(startcell);
240 |
241 | let endcell = createElement('td', null,
242 | moment.utc(event.end.dateTime).format('M/D/YY h:mm A'));
243 | eventrow.appendChild(endcell);
244 | }
245 |
246 | mainContainer.innerHTML = '';
247 | mainContainer.appendChild(div);
248 | }
249 | //
250 |
251 | //
252 | function showNewEventForm() {
253 | let form = document.createElement('form');
254 |
255 | let subjectGroup = createElement('div', 'form-group mb-2');
256 | form.appendChild(subjectGroup);
257 |
258 | subjectGroup.appendChild(createElement('label', '', 'Subject'));
259 |
260 | let subjectInput = createElement('input', 'form-control');
261 | subjectInput.setAttribute('id', 'ev-subject');
262 | subjectInput.setAttribute('type', 'text');
263 | subjectGroup.appendChild(subjectInput);
264 |
265 | let attendeesGroup = createElement('div', 'form-group mb-2');
266 | form.appendChild(attendeesGroup);
267 |
268 | attendeesGroup.appendChild(createElement('label', '', 'Attendees'));
269 |
270 | let attendeesInput = createElement('input', 'form-control');
271 | attendeesInput.setAttribute('id', 'ev-attendees');
272 | attendeesInput.setAttribute('type', 'text');
273 | attendeesGroup.appendChild(attendeesInput);
274 |
275 | let timeRow = createElement('div', 'row mb-2');
276 | form.appendChild(timeRow);
277 |
278 | let leftCol = createElement('div', 'col');
279 | timeRow.appendChild(leftCol);
280 |
281 | let startGroup = createElement('div', 'form-group');
282 | leftCol.appendChild(startGroup);
283 |
284 | startGroup.appendChild(createElement('label', '', 'Start'));
285 |
286 | let startInput = createElement('input', 'form-control');
287 | startInput.setAttribute('id', 'ev-start');
288 | startInput.setAttribute('type', 'datetime-local');
289 | startGroup.appendChild(startInput);
290 |
291 | let rightCol = createElement('div', 'col');
292 | timeRow.appendChild(rightCol);
293 |
294 | let endGroup = createElement('div', 'form-group');
295 | rightCol.appendChild(endGroup);
296 |
297 | endGroup.appendChild(createElement('label', '', 'End'));
298 |
299 | let endInput = createElement('input', 'form-control');
300 | endInput.setAttribute('id', 'ev-end');
301 | endInput.setAttribute('type', 'datetime-local');
302 | endGroup.appendChild(endInput);
303 |
304 | let bodyGroup = createElement('div', 'form-group mb-2');
305 | form.appendChild(bodyGroup);
306 |
307 | bodyGroup.appendChild(createElement('label', '', 'Body'));
308 |
309 | let bodyInput = createElement('textarea', 'form-control');
310 | bodyInput.setAttribute('id', 'ev-body');
311 | bodyInput.setAttribute('rows', '3');
312 | bodyGroup.appendChild(bodyInput);
313 |
314 | let createButton = createElement('button', 'btn btn-primary me-2', 'Create');
315 | createButton.setAttribute('type', 'button');
316 | createButton.setAttribute('onclick', 'createNewEvent();');
317 | form.appendChild(createButton);
318 |
319 | let cancelButton = createElement('button', 'btn btn-secondary', 'Cancel');
320 | cancelButton.setAttribute('type', 'button');
321 | cancelButton.setAttribute('onclick', 'getEvents();');
322 | form.appendChild(cancelButton);
323 |
324 | mainContainer.innerHTML = '';
325 | mainContainer.appendChild(form);
326 | }
327 | //
328 |
329 | updatePage(Views.home);
--------------------------------------------------------------------------------