mirror of
https://github.com/hanzoai/sentinel.git
synced 2026-09-29 22:34:33 +00:00
182 lines
5.2 KiB
TypeScript
182 lines
5.2 KiB
TypeScript
// XXX(epurkhiser): Ensure the LatestContextStore is initialized before we set
|
|
// the active org. Otherwise we will trigger an action that does nothing
|
|
import 'sentry/stores/latestContextStore';
|
|
|
|
import * as Sentry from '@sentry/react';
|
|
|
|
import {addErrorMessage} from 'sentry/actionCreators/indicator';
|
|
import {setActiveOrganization} from 'sentry/actionCreators/organizations';
|
|
import type {ResponseMeta} from 'sentry/api';
|
|
import {Client} from 'sentry/api';
|
|
import OrganizationStore from 'sentry/stores/organizationStore';
|
|
import PageFiltersStore from 'sentry/stores/pageFiltersStore';
|
|
import ProjectsStore from 'sentry/stores/projectsStore';
|
|
import TeamStore from 'sentry/stores/teamStore';
|
|
import type {Organization, Project, Team} from 'sentry/types';
|
|
import {getPreloadedDataPromise} from 'sentry/utils/getPreloadedData';
|
|
import parseLinkHeader from 'sentry/utils/parseLinkHeader';
|
|
|
|
async function fetchOrg(
|
|
api: Client,
|
|
slug: string,
|
|
usePreload?: boolean
|
|
): Promise<Organization> {
|
|
const [org] = await getPreloadedDataPromise(
|
|
'organization',
|
|
slug,
|
|
() =>
|
|
// This data should get preloaded in static/sentry/index.ejs
|
|
// If this url changes make sure to update the preload
|
|
api.requestPromise(`/organizations/${slug}/`, {
|
|
includeAllArgs: true,
|
|
query: {detailed: 0},
|
|
}),
|
|
usePreload
|
|
);
|
|
|
|
if (!org) {
|
|
throw new Error('retrieved organization is falsey');
|
|
}
|
|
|
|
OrganizationStore.onUpdate(org, {replace: true});
|
|
setActiveOrganization(org);
|
|
|
|
Sentry.configureScope(scope => {
|
|
// XXX(dcramer): this is duplicated in sdk.py on the backend
|
|
scope.setTag('organization', org.id);
|
|
scope.setTag('organization.slug', org.slug);
|
|
scope.setContext('organization', {id: org.id, slug: org.slug});
|
|
});
|
|
|
|
return org;
|
|
}
|
|
|
|
async function fetchProjectsAndTeams(
|
|
slug: string,
|
|
usePreload?: boolean
|
|
): Promise<
|
|
[
|
|
[Project[], string | undefined, XMLHttpRequest | ResponseMeta | undefined],
|
|
[Team[], string | undefined, XMLHttpRequest | ResponseMeta | undefined],
|
|
]
|
|
> {
|
|
// Create a new client so the request is not cancelled
|
|
const uncancelableApi = new Client();
|
|
|
|
const projectsPromise = getPreloadedDataPromise(
|
|
'projects',
|
|
slug,
|
|
() =>
|
|
// This data should get preloaded in static/sentry/index.ejs
|
|
// If this url changes make sure to update the preload
|
|
uncancelableApi.requestPromise(`/organizations/${slug}/projects/`, {
|
|
includeAllArgs: true,
|
|
query: {
|
|
all_projects: 1,
|
|
collapse: 'latestDeploys',
|
|
},
|
|
}),
|
|
usePreload
|
|
);
|
|
|
|
const teamsPromise = getPreloadedDataPromise(
|
|
'teams',
|
|
slug,
|
|
// This data should get preloaded in static/sentry/index.ejs
|
|
// If this url changes make sure to update the preload
|
|
() =>
|
|
uncancelableApi.requestPromise(`/organizations/${slug}/teams/`, {
|
|
includeAllArgs: true,
|
|
}),
|
|
usePreload
|
|
);
|
|
|
|
try {
|
|
return await Promise.all([projectsPromise, teamsPromise]);
|
|
} catch (err) {
|
|
// It's possible these requests fail with a 403 if the user has a role with
|
|
// insufficient access to projects and teams, but *can* access org details
|
|
// (e.g. billing). An example of this is in org settings.
|
|
//
|
|
// Ignore 403s and bubble up other API errors
|
|
if (err.status !== 403) {
|
|
throw err;
|
|
}
|
|
}
|
|
|
|
return [
|
|
[[], undefined, undefined],
|
|
[[], undefined, undefined],
|
|
];
|
|
}
|
|
|
|
/**
|
|
* Fetches an organization's details
|
|
*
|
|
* @param api A reference to the api client
|
|
* @param slug The organization slug
|
|
* @param silent Should we silently update the organization (do not clear the
|
|
* current organization in the store)
|
|
* @param usePreload Should the preloaded data be used if available?
|
|
*/
|
|
export function fetchOrganizationDetails(
|
|
api: Client,
|
|
slug: string,
|
|
silent: boolean,
|
|
usePreload?: boolean
|
|
) {
|
|
if (!silent) {
|
|
OrganizationStore.reset();
|
|
ProjectsStore.reset();
|
|
TeamStore.reset();
|
|
PageFiltersStore.onReset();
|
|
}
|
|
|
|
const loadOrganization = async () => {
|
|
try {
|
|
await fetchOrg(api, slug, usePreload);
|
|
} catch (err) {
|
|
if (!err) {
|
|
return;
|
|
}
|
|
|
|
OrganizationStore.onFetchOrgError(err);
|
|
|
|
if (err.status === 403 || err.status === 401) {
|
|
const errMessage =
|
|
typeof err.responseJSON?.detail === 'string'
|
|
? err.responseJSON?.detail
|
|
: typeof err.responseJSON?.detail?.message === 'string'
|
|
? err.responseJSON?.detail.message
|
|
: null;
|
|
|
|
if (errMessage) {
|
|
addErrorMessage(errMessage);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
Sentry.captureException(err);
|
|
}
|
|
};
|
|
|
|
const loadTeamsAndProjects = async () => {
|
|
const [[projects], [teams, , resp]] = await fetchProjectsAndTeams(slug, usePreload);
|
|
|
|
ProjectsStore.loadInitialData(projects ?? []);
|
|
|
|
const teamPageLinks = resp?.getResponseHeader('Link');
|
|
if (teamPageLinks) {
|
|
const paginationObject = parseLinkHeader(teamPageLinks);
|
|
const hasMore = paginationObject?.next?.results ?? false;
|
|
const cursor = paginationObject.next?.cursor;
|
|
TeamStore.loadInitialData(teams, hasMore, cursor);
|
|
} else {
|
|
TeamStore.loadInitialData(teams);
|
|
}
|
|
};
|
|
|
|
return Promise.all([loadOrganization(), loadTeamsAndProjects()]);
|
|
}
|