-
Notifications
You must be signed in to change notification settings - Fork 232
/
AzureFunctions.tsx
108 lines (103 loc) · 4 KB
/
AzureFunctions.tsx
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
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
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
import { useContext, useState } from "react";
import { Button, Spinner } from "@fluentui/react-components";
import { useData } from "@microsoft/teamsfx-react";
import * as axios from "axios";
import { BearerTokenAuthProvider, createApiClient, TeamsUserCredential } from "@microsoft/teamsfx";
import { TeamsFxContext } from "../Context";
import config from "./lib/config";
const functionName = config.apiName || "myFunc";
async function callFunction(teamsUserCredential: TeamsUserCredential) {
try {
const apiBaseUrl = config.apiEndpoint + "/api/";
// createApiClient(...) creates an Axios instance which uses BearerTokenAuthProvider to inject token to request header
const apiClient = createApiClient(
apiBaseUrl,
new BearerTokenAuthProvider(async () => (await teamsUserCredential.getToken(""))!.token)
);
const response = await apiClient.get(functionName);
return response.data;
} catch (err: unknown) {
if (axios.default.isAxiosError(err)) {
let funcErrorMsg = "";
if (err?.response?.status === 404) {
funcErrorMsg = `There may be a problem with the deployment of Azure Function App, please deploy Azure Function (Run command palette "Teams: Deploy") first before running this App`;
} else if (err.message === "Network Error") {
funcErrorMsg =
"Cannot call Azure Function due to network error, please check your network connection status and ";
if (err.config?.url && err.config.url.indexOf("localhost") >= 0) {
funcErrorMsg += `make sure to start Azure Function locally (Run "npm run start" command inside api folder from terminal) first before running this App`;
} else {
funcErrorMsg += `make sure to provision and deploy Azure Function (Run command palette "Teams: Provision" and "Teams: Deploy") first before running this App`;
}
} else {
funcErrorMsg = err.message;
if (err.response?.data?.error) {
funcErrorMsg += ": " + err.response.data.error;
}
}
throw new Error(funcErrorMsg);
}
throw err;
}
}
export function AzureFunctions(props: { codePath?: string; docsUrl?: string }) {
const [needConsent, setNeedConsent] = useState(false);
const { codePath, docsUrl } = {
codePath: `api/${functionName}/index.ts`,
docsUrl: "https://aka.ms/teamsfx-azure-functions",
...props,
};
const teamsUserCredential = useContext(TeamsFxContext).teamsUserCredential;
const { loading, data, error, reload } = useData(async () => {
if (!teamsUserCredential) {
throw new Error("TeamsFx SDK is not initialized.");
}
if (needConsent) {
await teamsUserCredential!.login(["User.Read"]);
setNeedConsent(false);
}
try {
const functionRes = await callFunction(teamsUserCredential);
return functionRes;
} catch (error: any) {
if (error.message.includes("The application may not be authorized.")) {
setNeedConsent(true);
}
}
});
return (
<div>
<h2>Call your Azure Function</h2>
<p>
An Azure Functions app is running. Authorize this app and click below to call it for a
response:
</p>
{!loading && (
<Button appearance="primary" disabled={loading} onClick={reload}>
Authorize and call Azure Function
</Button>
)}
{loading && (
<pre className="fixed">
<Spinner />
</pre>
)}
{!loading && !!data && !error && <pre className="fixed">{JSON.stringify(data, null, 2)}</pre>}
{!loading && !data && !error && <pre className="fixed"></pre>}
{!loading && !!error && <div className="error fixed">{(error as any).toString()}</div>}
<h4>How to edit the Azure Function</h4>
<p>
See the code in <code>{codePath}</code> to add your business logic.
</p>
{!!docsUrl && (
<p>
For more information, see the{" "}
<a href={docsUrl} target="_blank" rel="noreferrer">
docs
</a>
.
</p>
)}
</div>
);
}