From d50db0dd80f1c1fda0c9964c63f61d31fb9293a6 Mon Sep 17 00:00:00 2001 From: Joey Orlando Date: Wed, 23 Nov 2022 13:29:58 +0100 Subject: [PATCH] [Hotfix] UI not handling invalid grafana tokens properly (#892) * bug-fix fix issue where frontend would not properly handle scenario where Grafana API token was not yet available/valid --- CHANGELOG.md | 7 +++++++ .../state/plugin/__snapshots__/plugin.test.ts.snap | 11 ----------- grafana-plugin/src/state/plugin/index.ts | 7 +------ grafana-plugin/src/state/plugin/plugin.test.ts | 6 +++--- grafana-plugin/src/state/rootBaseStore/index.ts | 7 +++++-- .../src/state/rootBaseStore/rootBaseStore.test.ts | 8 +++++--- 6 files changed, 21 insertions(+), 25 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5314e6e1..969b7bde 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,13 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## v1.1.4 (2022-11-23) + +### Fixed + +- Bug fix for [#882](https://github.com/grafana/oncall/pull/882) which was causing the OnCall web calendars to not load +- Bug fix which, when installing the plugin, or after removing a Grafana API token, caused the plugin to not load properly + ## v1.1.3 (2022-11-22) - Bug Fixes diff --git a/grafana-plugin/src/state/plugin/__snapshots__/plugin.test.ts.snap b/grafana-plugin/src/state/plugin/__snapshots__/plugin.test.ts.snap index 24cc2f4c..334e4c70 100644 --- a/grafana-plugin/src/state/plugin/__snapshots__/plugin.test.ts.snap +++ b/grafana-plugin/src/state/plugin/__snapshots__/plugin.test.ts.snap @@ -1,16 +1,5 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`PluginState.checkIfPluginIsConnected token_ok: false 1`] = ` -"There was an issue with the communication between your OnCall API and your Grafana instance. -Please ensure that your OnCall API is properly configured to communicate with your Grafana instance." -`; - -exports[`PluginState.checkIfPluginIsConnected token_ok: true 1`] = ` -Object { - "token_ok": true, -} -`; - exports[`PluginState.generateInvalidOnCallApiURLErrorMsg it returns the proper error message - configured through env var: false 1`] = ` "Could not communicate with your OnCall API at http://hello.com. Validate that the URL is correct, your OnCall API is running, and that it is accessible from your Grafana instance." diff --git a/grafana-plugin/src/state/plugin/index.ts b/grafana-plugin/src/state/plugin/index.ts index f4506b5b..c0920900 100644 --- a/grafana-plugin/src/state/plugin/index.ts +++ b/grafana-plugin/src/state/plugin/index.ts @@ -297,14 +297,9 @@ class PluginState { onCallApiUrlIsConfiguredThroughEnvVar = false ): Promise => { try { - const resp = await makeRequest(`${this.ONCALL_BASE_URL}/status`, { + return await makeRequest(`${this.ONCALL_BASE_URL}/status`, { method: 'GET', }); - - if (!resp.token_ok) { - return `There was an issue with the communication between your OnCall API and your Grafana instance.\nPlease ensure that your OnCall API is properly configured to communicate with your Grafana instance.`; - } - return resp; } catch (e) { return this.getHumanReadableErrorFromOnCallError( e, diff --git a/grafana-plugin/src/state/plugin/plugin.test.ts b/grafana-plugin/src/state/plugin/plugin.test.ts index 32b72b66..accde49d 100644 --- a/grafana-plugin/src/state/plugin/plugin.test.ts +++ b/grafana-plugin/src/state/plugin/plugin.test.ts @@ -643,9 +643,9 @@ describe('PluginState.selfHostedInstallPlugin', () => { }); describe('PluginState.checkIfPluginIsConnected', () => { - test.each([true, false])('token_ok: %s', async (tokenOk) => { + test('it returns the API response', async () => { // mocks - const mockedResp = { token_ok: tokenOk }; + const mockedResp = { foo: 'bar' }; const onCallApiUrl = 'http://hello.com'; makeRequest.mockResolvedValueOnce(mockedResp); @@ -653,7 +653,7 @@ describe('PluginState.checkIfPluginIsConnected', () => { const response = await PluginState.checkIfPluginIsConnected(onCallApiUrl); // assertions - expect(response).toMatchSnapshot(); + expect(response).toEqual(mockedResp); expect(makeRequest).toHaveBeenCalledTimes(1); expect(makeRequest).toHaveBeenCalledWith(`${ONCALL_BASE_URL}/status`, { method: 'GET' }); diff --git a/grafana-plugin/src/state/rootBaseStore/index.ts b/grafana-plugin/src/state/rootBaseStore/index.ts index 92b20d5a..17f2f48e 100644 --- a/grafana-plugin/src/state/rootBaseStore/index.ts +++ b/grafana-plugin/src/state/rootBaseStore/index.ts @@ -129,6 +129,9 @@ export class RootBaseStore { * * Otherwise, get the plugin connection status from the OnCall API and check a few pre-conditions: * - plugin must be considered installed by the OnCall API + * - token_ok must be true + * - This represents the status of the Grafana API token. It can be false in the event that either the token + * hasn't been created, or if the API token was revoked in Grafana. * - user must be not "anonymous" (this is determined by the plugin-proxy) * - the OnCall API must be currently allowing signup * - the user must have an Admin role @@ -151,12 +154,12 @@ export class RootBaseStore { return this.setupPluginError(pluginConnectionStatus); } - const { allow_signup, is_installed, is_user_anonymous } = pluginConnectionStatus; + const { allow_signup, is_installed, is_user_anonymous, token_ok } = pluginConnectionStatus; if (is_user_anonymous) { return this.setupPluginError( '😞 Unfortunately Grafana OnCall is available for authorized users only, please sign in to proceed.' ); - } else if (!is_installed) { + } else if (!is_installed || !token_ok) { if (!allow_signup) { return this.setupPluginError('🚫 OnCall has temporarily disabled signup of new users. Please try again later.'); } diff --git a/grafana-plugin/src/state/rootBaseStore/rootBaseStore.test.ts b/grafana-plugin/src/state/rootBaseStore/rootBaseStore.test.ts index ec9999af..3cbc51e2 100644 --- a/grafana-plugin/src/state/rootBaseStore/rootBaseStore.test.ts +++ b/grafana-plugin/src/state/rootBaseStore/rootBaseStore.test.ts @@ -144,16 +144,18 @@ describe('rootBaseStore', () => { ); }); - test('plugin is not installed, signup is allowed, user is an admin, plugin installation is triggered', async () => { + test.each([ + { is_installed: false, token_ok: true }, + { is_installed: true, token_ok: false }, + ])('signup is allowed, user is an admin, plugin installation is triggered', async (scenario) => { // mocks/setup const onCallApiUrl = 'http://asdfasdf.com'; const rootBaseStore = new RootBaseStore(); const mockedLoadCurrentUser = jest.fn(); PluginState.checkIfPluginIsConnected = jest.fn().mockResolvedValueOnce({ + ...scenario, is_user_anonymous: false, - is_installed: false, - token_ok: true, allow_signup: true, version: 'asdfasdf', license: 'asdfasdf',