Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'app/assets/javascripts/jira_connect/subscriptions')
-rw-r--r--app/assets/javascripts/jira_connect/subscriptions/api.js64
-rw-r--r--app/assets/javascripts/jira_connect/subscriptions/components/app.vue6
-rw-r--r--app/assets/javascripts/jira_connect/subscriptions/components/compatibility_alert.vue15
-rw-r--r--app/assets/javascripts/jira_connect/subscriptions/components/sign_in_oauth_button.vue111
-rw-r--r--app/assets/javascripts/jira_connect/subscriptions/constants.js25
-rw-r--r--app/assets/javascripts/jira_connect/subscriptions/pages/sign_in/sign_in_gitlab_multiversion/index.vue38
-rw-r--r--app/assets/javascripts/jira_connect/subscriptions/pages/sign_in/sign_in_gitlab_multiversion/version_select_form.vue12
-rw-r--r--app/assets/javascripts/jira_connect/subscriptions/store/actions.js8
-rw-r--r--app/assets/javascripts/jira_connect/subscriptions/store/state.js8
-rw-r--r--app/assets/javascripts/jira_connect/subscriptions/utils.js41
10 files changed, 277 insertions, 51 deletions
diff --git a/app/assets/javascripts/jira_connect/subscriptions/api.js b/app/assets/javascripts/jira_connect/subscriptions/api.js
index de67703356f..c79d7002111 100644
--- a/app/assets/javascripts/jira_connect/subscriptions/api.js
+++ b/app/assets/javascripts/jira_connect/subscriptions/api.js
@@ -1,10 +1,25 @@
import axios from 'axios';
+import { buildApiUrl } from '~/api/api_utils';
+
+import { GITLAB_COM_BASE_PATH } from '~/jira_connect/subscriptions/constants';
import { getJwt } from './utils';
+const CURRENT_USER_PATH = '/api/:version/user';
+const JIRA_CONNECT_SUBSCRIPTIONS_PATH = '/api/:version/integrations/jira_connect/subscriptions';
+const JIRA_CONNECT_INSTALLATIONS_PATH = '/-/jira_connect/installations';
+const JIRA_CONNECT_OAUTH_APPLICATION_ID_PATH = '/-/jira_connect/oauth_application_id';
+
+// This export is only used for testing purposes
+export const axiosInstance = axios.create();
+
+export const setApiBaseURL = (baseURL = null) => {
+ axiosInstance.defaults.baseURL = baseURL;
+};
+
export const addSubscription = async (addPath, namespace) => {
const jwt = await getJwt();
- return axios.post(addPath, {
+ return axiosInstance.post(addPath, {
jwt,
namespace_path: namespace,
});
@@ -13,7 +28,7 @@ export const addSubscription = async (addPath, namespace) => {
export const removeSubscription = async (removePath) => {
const jwt = await getJwt();
- return axios.delete(removePath, {
+ return axiosInstance.delete(removePath, {
params: {
jwt,
},
@@ -21,7 +36,7 @@ export const removeSubscription = async (removePath) => {
};
export const fetchGroups = async (groupsPath, { page, perPage, search }) => {
- return axios.get(groupsPath, {
+ return axiosInstance.get(groupsPath, {
params: {
page,
per_page: perPage,
@@ -33,9 +48,50 @@ export const fetchGroups = async (groupsPath, { page, perPage, search }) => {
export const fetchSubscriptions = async (subscriptionsPath) => {
const jwt = await getJwt();
- return axios.get(subscriptionsPath, {
+ return axiosInstance.get(subscriptionsPath, {
params: {
jwt,
},
});
};
+
+export const getCurrentUser = (options) => {
+ const url = buildApiUrl(CURRENT_USER_PATH);
+ return axiosInstance.get(url, { ...options });
+};
+
+export const addJiraConnectSubscription = (namespacePath, { jwt, accessToken }) => {
+ const url = buildApiUrl(JIRA_CONNECT_SUBSCRIPTIONS_PATH);
+
+ return axiosInstance.post(
+ url,
+ {
+ jwt,
+ namespace_path: namespacePath,
+ },
+ {
+ headers: {
+ Authorization: `Bearer ${accessToken}`,
+ },
+ },
+ );
+};
+
+export const updateInstallation = async (instanceUrl) => {
+ const jwt = await getJwt();
+
+ return axiosInstance.put(JIRA_CONNECT_INSTALLATIONS_PATH, {
+ jwt,
+ installation: {
+ instance_url: instanceUrl === GITLAB_COM_BASE_PATH ? null : instanceUrl,
+ },
+ });
+};
+
+export const fetchOAuthApplicationId = () => {
+ return axiosInstance.get(JIRA_CONNECT_OAUTH_APPLICATION_ID_PATH);
+};
+
+export const fetchOAuthToken = (oauthTokenPath, data = {}) => {
+ return axiosInstance.post(oauthTokenPath, data);
+};
diff --git a/app/assets/javascripts/jira_connect/subscriptions/components/app.vue b/app/assets/javascripts/jira_connect/subscriptions/components/app.vue
index 66aea60c5b5..22a6c0751f4 100644
--- a/app/assets/javascripts/jira_connect/subscriptions/components/app.vue
+++ b/app/assets/javascripts/jira_connect/subscriptions/components/app.vue
@@ -83,7 +83,7 @@ export default {
* if the jiraConnectOauth flag is enabled.
*/
fetchSubscriptionsOauth() {
- if (!this.isOauthEnabled) return;
+ if (!this.isOauthEnabled || !this.userSignedIn) return;
this.fetchSubscriptions(this.subscriptionsPath);
},
@@ -146,12 +146,12 @@ export default {
<div class="gl-layout-w-limited gl-mx-auto gl-px-5 gl-mb-7">
<sign-in-page
- v-if="!userSignedIn"
+ v-show="!userSignedIn"
:has-subscriptions="hasSubscriptions"
@sign-in-oauth="onSignInOauth"
@error="onSignInError"
/>
- <subscriptions-page v-else :has-subscriptions="hasSubscriptions" />
+ <subscriptions-page v-if="userSignedIn" :has-subscriptions="hasSubscriptions" />
</div>
</div>
</main>
diff --git a/app/assets/javascripts/jira_connect/subscriptions/components/compatibility_alert.vue b/app/assets/javascripts/jira_connect/subscriptions/components/compatibility_alert.vue
index c5b56535247..9b50681515e 100644
--- a/app/assets/javascripts/jira_connect/subscriptions/components/compatibility_alert.vue
+++ b/app/assets/javascripts/jira_connect/subscriptions/components/compatibility_alert.vue
@@ -3,6 +3,7 @@ import { GlAlert, GlSprintf, GlLink } from '@gitlab/ui';
import { s__ } from '~/locale';
import { helpPagePath } from '~/helpers/help_page_helper';
import LocalStorageSync from '~/vue_shared/components/local_storage_sync.vue';
+import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
const COMPATIBILITY_ALERT_STATE_KEY = 'compatibility_alert_dismissed';
@@ -14,6 +15,7 @@ export default {
GlLink,
LocalStorageSync,
},
+ mixins: [glFeatureFlagMixin()],
data() {
return {
alertDismissed: false,
@@ -23,6 +25,14 @@ export default {
shouldShowAlert() {
return !this.alertDismissed;
},
+ isOauthSelfManagedEnabled() {
+ return this.glFeatures.jiraConnectOauth && this.glFeatures.jiraConnectOauthSelfManaged;
+ },
+ alertBody() {
+ return this.isOauthSelfManagedEnabled
+ ? this.$options.i18n.body
+ : this.$options.i18n.bodyDotCom;
+ },
},
methods: {
dismissAlert() {
@@ -32,6 +42,9 @@ export default {
i18n: {
title: s__('Integrations|Known limitations'),
body: s__(
+ 'Integrations|Adding a namespace only works in browsers that allow cross-site cookies. %{linkStart}Learn more%{linkEnd}.',
+ ),
+ bodyDotCom: s__(
'Integrations|This integration only works with GitLab.com. Adding a namespace only works in browsers that allow cross-site cookies. %{linkStart}Learn more%{linkEnd}.',
),
},
@@ -50,7 +63,7 @@ export default {
:title="$options.i18n.title"
@dismiss="dismissAlert"
>
- <gl-sprintf :message="$options.i18n.body">
+ <gl-sprintf :message="alertBody">
<template #link="{ content }">
<gl-link :href="$options.DOCS_LINK_URL" target="_blank">{{ content }}</gl-link>
</template>
diff --git a/app/assets/javascripts/jira_connect/subscriptions/components/sign_in_oauth_button.vue b/app/assets/javascripts/jira_connect/subscriptions/components/sign_in_oauth_button.vue
index ad3e70bcb5f..4cf3a1a0279 100644
--- a/app/assets/javascripts/jira_connect/subscriptions/components/sign_in_oauth_button.vue
+++ b/app/assets/javascripts/jira_connect/subscriptions/components/sign_in_oauth_button.vue
@@ -1,30 +1,53 @@
<script>
import { mapActions, mapMutations } from 'vuex';
import { GlButton } from '@gitlab/ui';
-import axios from '~/lib/utils/axios_utils';
+import { sprintf } from '~/locale';
+
import {
I18N_DEFAULT_SIGN_IN_BUTTON_TEXT,
+ I18N_CUSTOM_SIGN_IN_BUTTON_TEXT,
+ I18N_OAUTH_APPLICATION_ID_ERROR_MESSAGE,
+ I18N_OAUTH_FAILED_TITLE,
+ I18N_OAUTH_FAILED_MESSAGE,
+ OAUTH_SELF_MANAGED_DOC_LINK,
OAUTH_WINDOW_OPTIONS,
PKCE_CODE_CHALLENGE_DIGEST_ALGORITHM,
} from '~/jira_connect/subscriptions/constants';
+import { fetchOAuthApplicationId, fetchOAuthToken } from '~/jira_connect/subscriptions/api';
import { setUrlParams } from '~/lib/utils/url_utility';
import AccessorUtilities from '~/lib/utils/accessor';
import { createCodeVerifier, createCodeChallenge } from '../pkce';
-import { SET_ACCESS_TOKEN } from '../store/mutation_types';
+import { SET_ACCESS_TOKEN, SET_ALERT } from '../store/mutation_types';
export default {
components: {
GlButton,
},
inject: ['oauthMetadata'],
+ props: {
+ gitlabBasePath: {
+ type: String,
+ required: false,
+ default: undefined,
+ },
+ },
data() {
return {
- token: null,
loading: false,
codeVerifier: null,
+ clientId: null,
canUseCrypto: AccessorUtilities.canUseCrypto(),
};
},
+ computed: {
+ buttonText() {
+ if (!this.gitlabBasePath) {
+ return I18N_DEFAULT_SIGN_IN_BUTTON_TEXT;
+ }
+
+ return sprintf(I18N_CUSTOM_SIGN_IN_BUTTON_TEXT, { url: this.gitlabBasePath });
+ },
+ },
created() {
window.addEventListener('message', this.handleWindowMessage);
},
@@ -35,30 +58,72 @@ export default {
...mapActions(['loadCurrentUser']),
...mapMutations({
setAccessToken: SET_ACCESS_TOKEN,
+ setAlert: SET_ALERT,
}),
- async startOAuthFlow() {
- this.loading = true;
-
+ async fetchOauthClientId() {
+ const {
+ data: { application_id: clientId },
+ } = await fetchOAuthApplicationId();
+ return clientId;
+ },
+ async getOauthAuthorizeURL() {
// Generate state necessary for PKCE OAuth flow
this.codeVerifier = createCodeVerifier();
const codeChallenge = await createCodeChallenge(this.codeVerifier);
+ try {
+ this.clientId = this.gitlabBasePath
+ ? await this.fetchOauthClientId()
+ : this.oauthMetadata?.oauth_token_payload?.client_id;
+ } catch {
+ throw new Error(I18N_OAUTH_APPLICATION_ID_ERROR_MESSAGE);
+ }
// Build the initial OAuth authorization URL
const { oauth_authorize_url: oauthAuthorizeURL } = this.oauthMetadata;
-
- const oauthAuthorizeURLWithChallenge = setUrlParams(
- {
- code_challenge: codeChallenge,
- code_challenge_method: PKCE_CODE_CHALLENGE_DIGEST_ALGORITHM.short,
- },
- oauthAuthorizeURL,
+ const oauthAuthorizeURLWithChallenge = new URL(
+ setUrlParams(
+ {
+ code_challenge: codeChallenge,
+ code_challenge_method: PKCE_CODE_CHALLENGE_DIGEST_ALGORITHM.short,
+ client_id: this.clientId,
+ },
+ oauthAuthorizeURL,
+ ),
);
- window.open(
- oauthAuthorizeURLWithChallenge,
- this.$options.i18n.defaultButtonText,
- OAUTH_WINDOW_OPTIONS,
- );
+ // Rebase URL on the specified GitLab base path (if specified).
+ if (this.gitlabBasePath) {
+ const gitlabBasePathURL = new URL(this.gitlabBasePath);
+ oauthAuthorizeURLWithChallenge.hostname = gitlabBasePathURL.hostname;
+ oauthAuthorizeURLWithChallenge.pathname = `${
+ gitlabBasePathURL.pathname === '/' ? '' : gitlabBasePathURL.pathname
+ }${oauthAuthorizeURLWithChallenge.pathname}`;
+ }
+
+ return oauthAuthorizeURLWithChallenge.toString();
+ },
+ async startOAuthFlow() {
+ try {
+ this.loading = true;
+ const oauthAuthorizeURL = await this.getOauthAuthorizeURL();
+
+ window.open(oauthAuthorizeURL, I18N_DEFAULT_SIGN_IN_BUTTON_TEXT, OAUTH_WINDOW_OPTIONS);
+ } catch (e) {
+ if (e.message) {
+ this.setAlert({
+ message: e.message,
+ variant: 'danger',
+ });
+ } else {
+ this.setAlert({
+ linkUrl: OAUTH_SELF_MANAGED_DOC_LINK,
+ title: I18N_OAUTH_FAILED_TITLE,
+ message: this.gitlabBasePath ? I18N_OAUTH_FAILED_MESSAGE : '',
+ variant: 'danger',
+ });
+ }
+ this.loading = false;
+ }
},
async handleWindowMessage(event) {
if (window.origin !== event.origin) {
@@ -94,20 +159,18 @@ export default {
async getOAuthToken(code) {
const {
oauth_token_payload: oauthTokenPayload,
- oauth_token_url: oauthTokenURL,
+ oauth_token_path: oauthTokenPath,
} = this.oauthMetadata;
- const { data } = await axios.post(oauthTokenURL, {
+ const { data } = await fetchOAuthToken(oauthTokenPath, {
...oauthTokenPayload,
code,
code_verifier: this.codeVerifier,
+ client_id: this.clientId,
});
return data.access_token;
},
},
- i18n: {
- defaultButtonText: I18N_DEFAULT_SIGN_IN_BUTTON_TEXT,
- },
};
</script>
<template>
@@ -119,7 +182,7 @@ export default {
@click="startOAuthFlow"
>
<slot>
- {{ $options.i18n.defaultButtonText }}
+ {{ buttonText }}
</slot>
</gl-button>
</template>
diff --git a/app/assets/javascripts/jira_connect/subscriptions/constants.js b/app/assets/javascripts/jira_connect/subscriptions/constants.js
index 8faafb1b0d0..fc365746b54 100644
--- a/app/assets/javascripts/jira_connect/subscriptions/constants.js
+++ b/app/assets/javascripts/jira_connect/subscriptions/constants.js
@@ -3,11 +3,13 @@ import { helpPagePath } from '~/helpers/help_page_helper';
export const DEFAULT_GROUPS_PER_PAGE = 10;
export const ALERT_LOCALSTORAGE_KEY = 'gitlab_alert';
+export const BASE_URL_LOCALSTORAGE_KEY = 'gitlab_base_url';
export const MINIMUM_SEARCH_TERM_LENGTH = 3;
export const ADD_NAMESPACE_MODAL_ID = 'add-namespace-modal';
export const I18N_DEFAULT_SIGN_IN_BUTTON_TEXT = s__('Integrations|Sign in to GitLab');
+export const I18N_CUSTOM_SIGN_IN_BUTTON_TEXT = s__('Integrations|Sign in to %{url}');
export const I18N_DEFAULT_SIGN_IN_ERROR_MESSAGE = s__('Integrations|Failed to sign in to GitLab.');
export const I18N_DEFAULT_SUBSCRIPTIONS_ERROR_MESSAGE = s__(
'Integrations|Failed to load subscriptions.',
@@ -18,13 +20,28 @@ export const I18N_ADD_SUBSCRIPTION_SUCCESS_ALERT_TITLE = s__(
export const I18N_ADD_SUBSCRIPTION_SUCCESS_ALERT_MESSAGE = s__(
'Integrations|You should now see GitLab.com activity inside your Jira Cloud issues. %{linkStart}Learn more%{linkEnd}',
);
-export const INTEGRATIONS_DOC_LINK = helpPagePath('integration/jira_development_panel', {
- anchor: 'use-the-integration',
-});
-
export const I18N_ADD_SUBSCRIPTIONS_ERROR_MESSAGE = s__(
'Integrations|Failed to link namespace. Please try again.',
);
+export const I18N_UPDATE_INSTALLATION_ERROR_MESSAGE = s__(
+ 'Integrations|Failed to update GitLab version. Please try again.',
+);
+export const I18N_OAUTH_APPLICATION_ID_ERROR_MESSAGE = s__(
+ 'Integrations|Failed to load Jira Connect Application ID. Please try again.',
+);
+export const I18N_OAUTH_FAILED_TITLE = s__('Integrations|Failed to sign in to GitLab.');
+export const I18N_OAUTH_FAILED_MESSAGE = s__(
+ 'Integrations|Ensure your instance URL is correct and your instance is configured correctly. %{linkStart}Learn more%{linkEnd}.',
+);
+
+export const INTEGRATIONS_DOC_LINK = helpPagePath('integration/jira/development_panel', {
+ anchor: 'use-the-integration',
+});
+export const OAUTH_SELF_MANAGED_DOC_LINK = helpPagePath('integration/jira/connect-app', {
+ anchor: 'install-the-gitlabcom-for-jira-cloud-app-for-self-managed-instances',
+});
+
+export const GITLAB_COM_BASE_PATH = 'https://gitlab.com';
const OAUTH_WINDOW_SIZE = 800;
export const OAUTH_WINDOW_OPTIONS = [
diff --git a/app/assets/javascripts/jira_connect/subscriptions/pages/sign_in/sign_in_gitlab_multiversion/index.vue b/app/assets/javascripts/jira_connect/subscriptions/pages/sign_in/sign_in_gitlab_multiversion/index.vue
index 4f5aa4c255c..5ff75e19425 100644
--- a/app/assets/javascripts/jira_connect/subscriptions/pages/sign_in/sign_in_gitlab_multiversion/index.vue
+++ b/app/assets/javascripts/jira_connect/subscriptions/pages/sign_in/sign_in_gitlab_multiversion/index.vue
@@ -1,6 +1,13 @@
<script>
+import { mapMutations } from 'vuex';
import { GlButton } from '@gitlab/ui';
import { s__ } from '~/locale';
+
+import { reloadPage, persistBaseUrl, retrieveBaseUrl } from '~/jira_connect/subscriptions/utils';
+import { updateInstallation, setApiBaseURL } from '~/jira_connect/subscriptions/api';
+import { I18N_UPDATE_INSTALLATION_ERROR_MESSAGE } from '~/jira_connect/subscriptions/constants';
+import { SET_ALERT } from '~/jira_connect/subscriptions/store/mutation_types';
+
import SignInOauthButton from '../../../components/sign_in_oauth_button.vue';
import VersionSelectForm from './version_select_form.vue';
@@ -14,6 +21,7 @@ export default {
data() {
return {
gitlabBasePath: null,
+ loadingVersionSelect: false,
};
},
computed: {
@@ -26,12 +34,32 @@ export default {
: this.$options.i18n.versionSelectSubtitle;
},
},
+ mounted() {
+ this.gitlabBasePath = retrieveBaseUrl();
+ setApiBaseURL(this.gitlabBasePath);
+ },
methods: {
+ ...mapMutations({
+ setAlert: SET_ALERT,
+ }),
resetGitlabBasePath() {
this.gitlabBasePath = null;
+ setApiBaseURL();
},
onVersionSelect(gitlabBasePath) {
- this.gitlabBasePath = gitlabBasePath;
+ this.loadingVersionSelect = true;
+ updateInstallation(gitlabBasePath)
+ .then(() => {
+ persistBaseUrl(gitlabBasePath);
+ reloadPage();
+ })
+ .catch(() => {
+ this.setAlert({
+ message: I18N_UPDATE_INSTALLATION_ERROR_MESSAGE,
+ variant: 'danger',
+ });
+ this.loadingVersionSelect = false;
+ });
},
onSignInError() {
this.$emit('error');
@@ -53,11 +81,17 @@ export default {
<p data-testid="subtitle">{{ subtitle }}</p>
</div>
- <version-select-form v-if="!hasSelectedVersion" class="gl-mt-7" @submit="onVersionSelect" />
+ <version-select-form
+ v-if="!hasSelectedVersion"
+ class="gl-mt-7"
+ :loading="loadingVersionSelect"
+ @submit="onVersionSelect"
+ />
<div v-else class="gl-text-center">
<sign-in-oauth-button
class="gl-mb-5"
+ :gitlab-base-path="gitlabBasePath"
@sign-in="$emit('sign-in-oauth', $event)"
@error="onSignInError"
/>
diff --git a/app/assets/javascripts/jira_connect/subscriptions/pages/sign_in/sign_in_gitlab_multiversion/version_select_form.vue b/app/assets/javascripts/jira_connect/subscriptions/pages/sign_in/sign_in_gitlab_multiversion/version_select_form.vue
index 0fa745ed7e3..6b32225ed11 100644
--- a/app/assets/javascripts/jira_connect/subscriptions/pages/sign_in/sign_in_gitlab_multiversion/version_select_form.vue
+++ b/app/assets/javascripts/jira_connect/subscriptions/pages/sign_in/sign_in_gitlab_multiversion/version_select_form.vue
@@ -9,13 +9,14 @@ import {
} from '@gitlab/ui';
import { __, s__ } from '~/locale';
+import { GITLAB_COM_BASE_PATH } from '~/jira_connect/subscriptions/constants';
+
const RADIO_OPTIONS = {
saas: 'saas',
selfManaged: 'selfManaged',
};
const DEFAULT_RADIO_OPTION = RADIO_OPTIONS.saas;
-const GITLAB_COM_BASE_PATH = 'https://gitlab.com';
export default {
name: 'VersionSelectForm',
@@ -27,6 +28,13 @@ export default {
GlFormRadio,
GlButton,
},
+ props: {
+ loading: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ },
data() {
return {
selected: DEFAULT_RADIO_OPTION,
@@ -82,7 +90,7 @@ export default {
</gl-form-group>
<div class="gl-display-flex gl-justify-content-end">
- <gl-button variant="confirm" type="submit">{{ __('Save') }}</gl-button>
+ <gl-button variant="confirm" type="submit" :loading="loading">{{ __('Save') }}</gl-button>
</div>
</gl-form>
</template>
diff --git a/app/assets/javascripts/jira_connect/subscriptions/store/actions.js b/app/assets/javascripts/jira_connect/subscriptions/store/actions.js
index 4a83ee8671d..fff34e1d75d 100644
--- a/app/assets/javascripts/jira_connect/subscriptions/store/actions.js
+++ b/app/assets/javascripts/jira_connect/subscriptions/store/actions.js
@@ -1,6 +1,8 @@
-import { fetchSubscriptions as fetchSubscriptionsREST } from '~/jira_connect/subscriptions/api';
-import { getCurrentUser } from '~/rest_api';
-import { addJiraConnectSubscription } from '~/api/integrations_api';
+import {
+ fetchSubscriptions as fetchSubscriptionsREST,
+ getCurrentUser,
+ addJiraConnectSubscription,
+} from '~/jira_connect/subscriptions/api';
import {
I18N_ADD_SUBSCRIPTION_SUCCESS_ALERT_TITLE,
I18N_ADD_SUBSCRIPTION_SUCCESS_ALERT_MESSAGE,
diff --git a/app/assets/javascripts/jira_connect/subscriptions/store/state.js b/app/assets/javascripts/jira_connect/subscriptions/store/state.js
index 03a83f18b4c..82a8517b511 100644
--- a/app/assets/javascripts/jira_connect/subscriptions/store/state.js
+++ b/app/assets/javascripts/jira_connect/subscriptions/store/state.js
@@ -1,4 +1,8 @@
-export default function createState({ subscriptions = [], subscriptionsLoading = false } = {}) {
+export default function createState({
+ subscriptions = [],
+ subscriptionsLoading = false,
+ currentUser = null,
+} = {}) {
return {
alert: undefined,
@@ -9,7 +13,7 @@ export default function createState({ subscriptions = [], subscriptionsLoading =
addSubscriptionLoading: false,
addSubscriptionError: false,
- currentUser: null,
+ currentUser,
currentUserError: null,
accessToken: null,
diff --git a/app/assets/javascripts/jira_connect/subscriptions/utils.js b/app/assets/javascripts/jira_connect/subscriptions/utils.js
index b2d03a1fbba..6db8b62d692 100644
--- a/app/assets/javascripts/jira_connect/subscriptions/utils.js
+++ b/app/assets/javascripts/jira_connect/subscriptions/utils.js
@@ -1,32 +1,45 @@
import AccessorUtilities from '~/lib/utils/accessor';
import { objectToQuery } from '~/lib/utils/url_utility';
-import { ALERT_LOCALSTORAGE_KEY } from './constants';
+import { ALERT_LOCALSTORAGE_KEY, BASE_URL_LOCALSTORAGE_KEY } from './constants';
const isFunction = (fn) => typeof fn === 'function';
+const { canUseLocalStorage } = AccessorUtilities;
+
+const persistToStorage = (key, payload) => {
+ localStorage.setItem(key, payload);
+};
+
+const retrieveFromStorage = (key) => {
+ return localStorage.getItem(key);
+};
+
+const removeFromStorage = (key) => {
+ localStorage.removeItem(key);
+};
/**
* Persist alert data to localStorage.
*/
export const persistAlert = ({ title, message, linkUrl, variant } = {}) => {
- if (!AccessorUtilities.canUseLocalStorage()) {
+ if (!canUseLocalStorage()) {
return;
}
const payload = JSON.stringify({ title, message, linkUrl, variant });
- localStorage.setItem(ALERT_LOCALSTORAGE_KEY, payload);
+ persistToStorage(ALERT_LOCALSTORAGE_KEY, payload);
};
/**
* Return alert data from localStorage.
*/
export const retrieveAlert = () => {
- if (!AccessorUtilities.canUseLocalStorage()) {
+ if (!canUseLocalStorage()) {
return null;
}
- const initialAlertJSON = localStorage.getItem(ALERT_LOCALSTORAGE_KEY);
+ const initialAlertJSON = retrieveFromStorage(ALERT_LOCALSTORAGE_KEY);
// immediately clean up
- localStorage.removeItem(ALERT_LOCALSTORAGE_KEY);
+ removeFromStorage(ALERT_LOCALSTORAGE_KEY);
if (!initialAlertJSON) {
return null;
@@ -35,6 +48,22 @@ export const retrieveAlert = () => {
return JSON.parse(initialAlertJSON);
};
+export const persistBaseUrl = (baseUrl) => {
+ if (!canUseLocalStorage()) {
+ return;
+ }
+
+ persistToStorage(BASE_URL_LOCALSTORAGE_KEY, baseUrl);
+};
+
+export const retrieveBaseUrl = () => {
+ if (!canUseLocalStorage()) {
+ return null;
+ }
+
+ return retrieveFromStorage(BASE_URL_LOCALSTORAGE_KEY);
+};
+
export const getJwt = () => {
return new Promise((resolve) => {
if (isFunction(AP?.context?.getToken)) {