diff --git a/package-lock.json b/package-lock.json index 904411df..9c595639 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,7 +12,7 @@ "dependencies": { "@fluentui/react-northstar": "^0.50.0", "@hapi/joi": "^17.1.1", - "@microsoft/teams-js": "^2.19.0", + "@microsoft/teams-js": "^1.11.0", "@newrelic/pino-enricher": "^1.1.1", "@sentry/browser": "^5.22.3", "@sentry/node": "^5.22.3", @@ -2810,12 +2810,9 @@ } }, "node_modules/@microsoft/teams-js": { - "version": "2.19.0", - "resolved": "https://registry.npmjs.org/@microsoft/teams-js/-/teams-js-2.19.0.tgz", - "integrity": "sha512-QpAK8JO6s9D5qOiW//fwS4bUgzhLr1GDxHCRw+BEs9Uuw5Z9YhwMClhtFlI5P7HlH5SFC4QSsh44HaV31ORXJA==", - "dependencies": { - "debug": "^4.3.3" - } + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/@microsoft/teams-js/-/teams-js-1.11.0.tgz", + "integrity": "sha512-5utMOMWXdNq0cV8hGIZEUpUVChoasoYjBOItgFIKE2a4vavmzlhra+GNXMdpvlYlv6/r7ORtVCQUDFJvPTVj2Q==" }, "node_modules/@mongodb-js/saslprep": { "version": "1.1.1", @@ -19066,12 +19063,9 @@ "integrity": "sha512-iUKgm52T8HOE/makSxjqoWhe95ZJA1/G1sYsGev2JDKUSS14KAgg1LHb+Ba+IPow0xflbnSkOsZcO08C7w1gYw==" }, "@microsoft/teams-js": { - "version": "2.19.0", - "resolved": "https://registry.npmjs.org/@microsoft/teams-js/-/teams-js-2.19.0.tgz", - "integrity": "sha512-QpAK8JO6s9D5qOiW//fwS4bUgzhLr1GDxHCRw+BEs9Uuw5Z9YhwMClhtFlI5P7HlH5SFC4QSsh44HaV31ORXJA==", - "requires": { - "debug": "^4.3.3" - } + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/@microsoft/teams-js/-/teams-js-1.11.0.tgz", + "integrity": "sha512-5utMOMWXdNq0cV8hGIZEUpUVChoasoYjBOItgFIKE2a4vavmzlhra+GNXMdpvlYlv6/r7ORtVCQUDFJvPTVj2Q==" }, "@mongodb-js/saslprep": { "version": "1.1.1", diff --git a/package.json b/package.json index a92f6439..5561a38b 100644 --- a/package.json +++ b/package.json @@ -19,8 +19,7 @@ "audit-fix": "HUSKY_SKIP_HOOKS=1 dev-tools npm-audit-fix --production --team-reviewers dx", "prepare": "./scripts/install_husky.sh", "pre-commit": "lint-staged", - "pre-push": "npm run test", - "clean": "rm -rf dist" + "pre-push": "npm run test" }, "repository": { "type": "git", @@ -35,7 +34,7 @@ "dependencies": { "@fluentui/react-northstar": "^0.50.0", "@hapi/joi": "^17.1.1", - "@microsoft/teams-js": "^2.19.0", + "@microsoft/teams-js": "^1.11.0", "@newrelic/pino-enricher": "^1.1.1", "@sentry/browser": "^5.22.3", "@sentry/node": "^5.22.3", diff --git a/src/client/containers/ConfigurationCreateContainer/components/ConfigurationCreate.tsx b/src/client/containers/ConfigurationCreateContainer/components/ConfigurationCreate.tsx index 839233de..d11fa450 100644 --- a/src/client/containers/ConfigurationCreateContainer/components/ConfigurationCreate.tsx +++ b/src/client/containers/ConfigurationCreateContainer/components/ConfigurationCreate.tsx @@ -135,7 +135,7 @@ export const ConfigurationCreate: FunctionComponent = {errorMessage && ()} - Select the events you would like to get a message for: + Select the events you want to get a message for:
{ if (isInitialized) { - app.getContext().then(({ - channel, - user - }: app.Context) => { - const { displayName: channelName, id: channelId } = channel ?? {}; - const { tenant: { id: tenantId } = { id: undefined } } = user ?? {}; - pages.getConfig().then(settings => { - pages.config.registerOnSaveHandler(async saveEvent => { + microsoftTeams.getContext(({ + channelId, + channelName, + tid: tenantId + }) => { + microsoftTeams.settings.getSettings(settings => { + microsoftTeams.settings.registerOnSaveHandler(async saveEvent => { if (tenantId === undefined || channelId === undefined || channelName === undefined || @@ -100,8 +99,7 @@ export const useConfigurationCreate = ({ } }); - // Although there is no 'configName' in the interface, not using it results in empty config name in edit connector menu - await pages.config.setConfig({ + microsoftTeams.settings.setSettings({ entityId: configurationId, configName: resource.name, contentUrl: decodeURI(`${window.location.origin}${url.getHomeUrl({ @@ -111,7 +109,7 @@ export const useConfigurationCreate = ({ channel: "{channelName}", theme: "{theme}" })}`) - } as pages.InstanceConfig); + } as microsoftTeams.settings.Settings); saveEvent.notifySuccess(); } catch (error) { diff --git a/src/client/containers/ConfigurationCreateContainer/hooks/useResources.ts b/src/client/containers/ConfigurationCreateContainer/hooks/useResources.ts index 2609e9a6..ecd21adc 100644 --- a/src/client/containers/ConfigurationCreateContainer/hooks/useResources.ts +++ b/src/client/containers/ConfigurationCreateContainer/hooks/useResources.ts @@ -1,6 +1,6 @@ import { useQuery } from "react-query"; import { INTERNAL_SERVER_ERROR, UNAUTHORIZED } from "http-status-codes"; -import { app } from "@microsoft/teams-js"; +import * as microsoftTeams from "@microsoft/teams-js"; import { requester } from "../../../lib"; import { Project, Styleguide } from "../../../constants"; @@ -25,13 +25,8 @@ interface UseWorkspacesResultParams { onStyleguidesSuccess: (styleguides: Styleguide[]) => void; } -const getChannelId = (): Promise => new Promise((resolve, reject) => { - app.getContext().then(({ channel }) => { - if (channel) { - resolve(channel.id); - } - reject(new Error("Channel is not defined")); - }); +const getChannelId = (): Promise => new Promise(resolve => { + microsoftTeams.getContext(({ channelId }) => resolve(channelId as string)); }); export const useResources = ({ diff --git a/src/client/containers/ConfigurationCreateContainer/hooks/useValidate.ts b/src/client/containers/ConfigurationCreateContainer/hooks/useValidate.ts index 80afbe63..474aeb0c 100644 --- a/src/client/containers/ConfigurationCreateContainer/hooks/useValidate.ts +++ b/src/client/containers/ConfigurationCreateContainer/hooks/useValidate.ts @@ -1,5 +1,5 @@ import { useEffect } from "react"; -import { pages } from "@microsoft/teams-js"; +import * as microsoftTeams from "@microsoft/teams-js"; import { Resource, resourceBasedEvents, WebhookEventType } from "../../../constants"; @@ -24,7 +24,7 @@ export const useValidate = (params: UseValidateParams): void => { const valid = isValid(params); useEffect(() => { if (params.enabled) { - pages.config.setValidityState(valid); + microsoftTeams.settings.setValidityState(valid); } }, [valid, params.enabled]); }; diff --git a/src/client/containers/ConfigurationUpdateContainer/hooks/useConfigurationDelete.ts b/src/client/containers/ConfigurationUpdateContainer/hooks/useConfigurationDelete.ts index 33585d1b..e4bf7b17 100644 --- a/src/client/containers/ConfigurationUpdateContainer/hooks/useConfigurationDelete.ts +++ b/src/client/containers/ConfigurationUpdateContainer/hooks/useConfigurationDelete.ts @@ -1,6 +1,6 @@ import { useEffect } from "react"; import { useMutation } from "react-query"; -import { pages } from "@microsoft/teams-js"; +import * as microsoftTeams from "@microsoft/teams-js"; import { requester } from "../../../lib"; @@ -14,7 +14,7 @@ export const useConfigurationDelete = ({ configurationId, isInitialized }: UseCo useEffect(() => { if (isInitialized) { - pages.config.registerOnRemoveHandler(async removeEvent => { + microsoftTeams.settings.registerOnRemoveHandler(async removeEvent => { try { await deleteConfiguration(configurationId); removeEvent.notifySuccess(); diff --git a/src/client/containers/ConfigurationUpdateContainer/hooks/useConfigurationUpdate.ts b/src/client/containers/ConfigurationUpdateContainer/hooks/useConfigurationUpdate.ts index 95abebf6..a04302c3 100644 --- a/src/client/containers/ConfigurationUpdateContainer/hooks/useConfigurationUpdate.ts +++ b/src/client/containers/ConfigurationUpdateContainer/hooks/useConfigurationUpdate.ts @@ -1,6 +1,6 @@ import { useEffect } from "react"; import { useMutation } from "react-query"; -import { app, pages } from "@microsoft/teams-js"; +import * as microsoftTeams from "@microsoft/teams-js"; import { requester, url } from "../../../lib"; import { Resource, WebhookEventType } from "../../../constants"; @@ -61,13 +61,12 @@ export const useConfigurationUpdate = ({ useEffect(() => { if (isInitialized) { - app.getContext().then(({ - channel, - user + microsoftTeams.getContext(({ + channelId, + channelName, + tid: tenantId }) => { - const { id: channelId, displayName: channelName } = channel ?? {}; - const { tenant: { id: tenantId } = { id: undefined } } = user ?? {}; - pages.config.registerOnSaveHandler(async saveEvent => { + microsoftTeams.settings.registerOnSaveHandler(async saveEvent => { if (tenantId === undefined || channelId === undefined || channelName === undefined || @@ -91,8 +90,7 @@ export const useConfigurationUpdate = ({ } }); - // Although there is no 'configName' in the interface, not using it results in empty config name in edit connector menu - await pages.config.setConfig({ + microsoftTeams.settings.setSettings({ entityId: configurationId, configName: resource.name, contentUrl: decodeURI(`${window.location.origin}${url.getHomeUrl({ @@ -102,7 +100,7 @@ export const useConfigurationUpdate = ({ channel: "{channelName}", theme: "{theme}" })}`) - } as pages.InstanceConfig); + } as microsoftTeams.settings.Settings); saveEvent.notifySuccess(); } catch (error) { diff --git a/src/client/containers/ConfigurationUpdateContainer/hooks/useValidate.ts b/src/client/containers/ConfigurationUpdateContainer/hooks/useValidate.ts index 43de2b3c..4e5e5f63 100644 --- a/src/client/containers/ConfigurationUpdateContainer/hooks/useValidate.ts +++ b/src/client/containers/ConfigurationUpdateContainer/hooks/useValidate.ts @@ -1,5 +1,5 @@ import { useEffect } from "react"; -import { pages } from "@microsoft/teams-js"; +import * as microsoftTeams from "@microsoft/teams-js"; import { Resource, resourceBasedEvents, WebhookEventType } from "../../../constants"; interface UseValidateParams { @@ -30,7 +30,7 @@ export const useValidate = (params: UseValidateParams): void => { const valid = isValid(params); useEffect(() => { if (params.enabled) { - pages.config.setValidityState(valid); + microsoftTeams.settings.setValidityState(valid); } }, [valid, params.enabled]); }; diff --git a/src/client/containers/LoginContainer/LoginContainer.tsx b/src/client/containers/LoginContainer/LoginContainer.tsx index 32bf595a..3d7e7201 100644 --- a/src/client/containers/LoginContainer/LoginContainer.tsx +++ b/src/client/containers/LoginContainer/LoginContainer.tsx @@ -1,22 +1,12 @@ -import React, { FunctionComponent, useState } from "react"; +import React, { FunctionComponent } from "react"; import { useInitialize } from "../../hooks"; -import { authentication } from "@microsoft/teams-js"; +import { useLogin } from "./hooks"; import { Login } from "./components"; import { Loader } from "@fluentui/react-northstar"; import { useRouter } from "next/router"; import { url, requester, storage } from "../../lib"; -const errorToText = (error?: string): string => { - switch (error) { - case "CancelledByUser": - case "access_denied": - return "You need to authorize Microsoft Teams app to connect your Zeplin projects and styleguides."; - default: - return "Authorization failed due to an API related connectivity issue. Please retry logging in."; - } -}; - export const LoginContainer: FunctionComponent = () => { const { query: { @@ -30,30 +20,15 @@ export const LoginContainer: FunctionComponent = () => { } = useRouter(); const { isInitializeLoading } = useInitialize(); - const [loginError, setLoginError] = useState(); - - async function authenticate() { - try { - const code = await authentication.authenticate({ - height: 476, - url: "/api/auth/authorize" - }); - return code; - } catch (err) { - setLoginError(errorToText((err as unknown as Error).message)); - } - } - - async function login() { - try { - const code = await authenticate(); - if (!code) { - throw Error("Authentication code is missing"); + const [login, { loginError }] = useLogin({ + onSuccess: async (code?: string) => { + try { + const { accessToken, refreshToken } = await requester.createAuthToken(String(code)); + storage.setAccessToken(accessToken); + storage.setRefreshToken(refreshToken); + } catch (err) { + // TODO: log to sentry } - const { accessToken, refreshToken } = await requester.createAuthToken(String(code)); - storage.setAccessToken(accessToken); - storage.setRefreshToken(refreshToken); - replace(id ? url.getConfigurationUpdateUrl({ channel: channel as string, @@ -63,13 +38,12 @@ export const LoginContainer: FunctionComponent = () => { theme: theme as string }) : url.getConfigurationCreateUrl({ + channel: channel as string, theme: theme as string })); - } catch (err) { - // TODO: log to sentry } - } + }); if (isInitializeLoading) { return ; diff --git a/src/client/containers/LoginContainer/hooks/index.ts b/src/client/containers/LoginContainer/hooks/index.ts new file mode 100644 index 00000000..c07ce0b2 --- /dev/null +++ b/src/client/containers/LoginContainer/hooks/index.ts @@ -0,0 +1 @@ +export * from "./useLogin"; diff --git a/src/client/containers/LoginContainer/hooks/useLogin.ts b/src/client/containers/LoginContainer/hooks/useLogin.ts new file mode 100644 index 00000000..12bee1e0 --- /dev/null +++ b/src/client/containers/LoginContainer/hooks/useLogin.ts @@ -0,0 +1,39 @@ +import * as microsoftTeams from "@microsoft/teams-js"; +import { useCallback, useState } from "react"; + +interface UseLoginParams { + onSuccess: (code?: string) => Promise; +} + +type UseLoginResult = [ + () => void, + { + loginError?: string; + } +] + +const errorToText = (error?: string): string => { + switch (error) { + case "CancelledByUser": + case "access_denied": + return "You need to authorize Microsoft Teams app to connect your Zeplin projects and styleguides."; + default: + return "Authorization failed due to an API related connectivity issue. Please retry logging in."; + } +}; + +export const useLogin = ({ onSuccess }: UseLoginParams): UseLoginResult => { + const [loginError, setError] = useState(); + + const login = useCallback( + () => microsoftTeams.authentication.authenticate({ + height: 476, + successCallback: onSuccess, + failureCallback: value => setError(errorToText(value)), + url: "/api/auth/authorize" + }), + [] + ); + + return [login, { loginError }]; +}; diff --git a/src/client/containers/ZeplinAuthEndContainer/ZeplinAuthEndContainer.tsx b/src/client/containers/ZeplinAuthEndContainer/ZeplinAuthEndContainer.tsx index f6320a1b..cabbb0fe 100644 --- a/src/client/containers/ZeplinAuthEndContainer/ZeplinAuthEndContainer.tsx +++ b/src/client/containers/ZeplinAuthEndContainer/ZeplinAuthEndContainer.tsx @@ -1,6 +1,6 @@ import React, { FunctionComponent, useEffect } from "react"; import { useRouter } from "next/router"; -import { app, authentication } from "@microsoft/teams-js"; +import * as microsoftTeams from "@microsoft/teams-js"; import { Loader } from "@fluentui/react-northstar"; export const ZeplinAuthEndContainer: FunctionComponent = () => { @@ -12,13 +12,13 @@ export const ZeplinAuthEndContainer: FunctionComponent = () => { } = useRouter(); useEffect(() => { - app.initialize().then(() => { + microsoftTeams.initialize(() => { if (error) { - authentication.notifyFailure(String(error)); + microsoftTeams.authentication.notifyFailure(String(error)); return; } - authentication.notifySuccess(code as string); + microsoftTeams.authentication.notifySuccess(code as string); }); }, []); diff --git a/src/client/hooks/useInitialize.ts b/src/client/hooks/useInitialize.ts index eddc2c1d..58c5b228 100644 --- a/src/client/hooks/useInitialize.ts +++ b/src/client/hooks/useInitialize.ts @@ -1,5 +1,5 @@ import { useEffect, useState } from "react"; -import { app } from "@microsoft/teams-js"; +import * as microsoftTeams from "@microsoft/teams-js"; interface UseInitializeParams { onSuccess?: () => void; @@ -12,8 +12,8 @@ interface UseInitializeResult { export const useInitialize = ({ onSuccess }: UseInitializeParams = {}): UseInitializeResult => { const [isInitializeLoading, setIsInitializeLoading] = useState(true); useEffect(() => { - app.initialize().then(() => { - app.notifySuccess(); + microsoftTeams.initialize(() => { + microsoftTeams.appInitialization.notifySuccess(); setIsInitializeLoading(false); onSuccess?.(); }); diff --git a/src/package/manifest.template.json b/src/package/manifest.template.json index 4d8e72b1..2e85d40a 100644 --- a/src/package/manifest.template.json +++ b/src/package/manifest.template.json @@ -1,6 +1,6 @@ { - "$schema": "https://developer.microsoft.com/en-us/json-schemas/teams/v1.12/MicrosoftTeams.schema.json", - "manifestVersion": "1.12", + "$schema": "https://developer.microsoft.com/en-us/json-schemas/teams/v1.6/MicrosoftTeams.schema.json", + "manifestVersion": "1.6", "id": "${NEXT_PRIVATE_APPLICATION_ID}", "version": "${NEXT_PUBLIC_VERSION}", "packageName": "zeplin", diff --git a/src/server/services/webhookEventService/webhookEventService.test.ts b/src/server/services/webhookEventService/webhookEventService.test.ts index 488f80dd..693a01bd 100644 --- a/src/server/services/webhookEventService/webhookEventService.test.ts +++ b/src/server/services/webhookEventService/webhookEventService.test.ts @@ -52,18 +52,16 @@ interface EventArrivedParams { payload: unknown; } -const getExampleEvent = ({ resourceId = "resource-id", timestamp = 1 } = {}): WebhookEvent => (({ +const getExampleEvent = ({ resourceId = "resource-id", timestamp = 1 } = {}): WebhookEvent => ({ event: "project.color", timestamp, - resource: { id: resourceId } -}) as WebhookEvent); +}) as WebhookEvent; -const getExampleArrivedEventParams = ({ resourceId = "resource-id", timestamp = 1 } = {}): EventArrivedParams => (({ +const getExampleArrivedEventParams = ({ resourceId = "resource-id", timestamp = 1 } = {}): EventArrivedParams => ({ deliveryId: "delivery-id", - payload: { event: "project.color", timestamp, @@ -71,7 +69,7 @@ const getExampleArrivedEventParams = ({ resourceId = "resource-id", timestamp = id: resourceId } } -}) as EventArrivedParams); +}) as EventArrivedParams; const expectedGroupingKey = `webhook-id:others`; const expectedJobId = "delivery-id";