mirror of
https://github.com/Azure/cosmos-explorer.git
synced 2025-05-04 07:24:52 +01:00
* Add standin region selection to settings menu. * Retrieve read and write regions from user context and populate dropdown menu. Update local storage value. Need to now connect with updating read region of primary cosmos client. * Change to only selecting region for cosmos client. Not setting up separate read and write clients. * Add read and write endpoint logging to cosmos client. * Pass changing endpoint from settings menu to client. Encountered token issues using new endpoint in client. * Rough implementation of region selection of endpoint for cosmos client. Still need to: 1 - Use separate context var to track selected region. Directly updating database account context throws off token generation by acquireMSALTokenForAccount 2 - Remove href overrides in acquireMSALTokenForAccount. * Update region selection to include global endpoint and generate a unique list of read and write endpoints. Need to continue with clearing out selected endpoint when global is selected again. Write operations stall when read region is selected even though 403 returned when region rejects operation. Need to limit feature availablility to nosql, table, gremlin (maybe). * Update cosmos client to fix bug. Clients continuously generate after changing RBAC setting. * Swapping back to default endpoint value. * Rebase on client refresh bug fix. * Enable region selection for NoSql, Table, Gremlin * Add logic to reset regional endpoint when global is selected. * Fix state changing when selecting region or resetting to global. * Rough implementation of configuring regional endpoint when DE is loaded in portal or hosted with AAD/Entra auth. * Ininitial attempt at adding error handling, but still having issues with errors caught at proxy plugin. * Added rough error handling in local requestPlugin used in local environments. Passes new error to calling code. Might need to add specific error handling for request plugin to the handleError class. * Change how request plugin returns error so existing error handling utility can process and present error. * Only enable region selection for nosql accounts. * Limit region selection to portal and hosted AAD auth. SQL accounts only. Could possibly enable on table and gremlin later. * Update error handling to account for generic error code. * Refactor error code extraction. * Update test snapshots and remove unneeded logging. * Change error handling to use only the message rather than casting to any. * Clean up debug logging in cosmos client. * Remove unused storage keys. * Use endpoint instead of region name to track selected region. Prevents having to do endpoint lookups. * Add initial button state update depending on region selection. Need to update with the API and react to user context changes. * Disable CRUD buttons when read region selected. * Default to write enabled in react. * Disable query saving when read region is selected. * Patch clientWidth error on conflicts tab. * Resolve merge conflicts from rebase. * Make sure proxy endpoints return in all cases. * Remove excess client logging and match main for ConflictsTab. * Cleaning up logging and fixing endpoint discovery bug. * Fix formatting. * Reformatting if statements with preferred formatting. * Migrate region selection to local persistence. Fixes account swapping bug. TODO: Inspect better way to reset interface elements when deleteAllStates is called. Need to react to regional endpoint being reset. * Relocate resetting interface context to helper function. * Remove legacy state storage for regional endpoint selection. * Laurent suggestion updates.
211 lines
6.7 KiB
TypeScript
211 lines
6.7 KiB
TypeScript
import { CosmosDbArtifactType, ResourceTokenInfo } from "Contracts/FabricMessagesContract";
|
|
import { ParsedResourceTokenConnectionString } from "Platform/Hosted/Helpers/ResourceTokenUtils";
|
|
import { Action } from "Shared/Telemetry/TelemetryConstants";
|
|
import { traceOpen } from "Shared/Telemetry/TelemetryProcessor";
|
|
import { useCarousel } from "hooks/useCarousel";
|
|
import { usePostgres } from "hooks/usePostgres";
|
|
import { AuthType } from "./AuthType";
|
|
import { DatabaseAccount } from "./Contracts/DataModels";
|
|
import { SubscriptionType } from "./Contracts/SubscriptionType";
|
|
import { Features, extractFeatures } from "./Platform/Hosted/extractFeatures";
|
|
import { CollectionCreation, CollectionCreationDefaults } from "./Shared/Constants";
|
|
|
|
interface ThroughputDefaults {
|
|
fixed: number;
|
|
unlimited:
|
|
| number
|
|
| {
|
|
collectionThreshold: number;
|
|
lessThanOrEqualToThreshold: number;
|
|
greatThanThreshold: number;
|
|
};
|
|
unlimitedmax: number;
|
|
unlimitedmin: number;
|
|
shared: number;
|
|
}
|
|
export interface CollectionCreationDefaults {
|
|
storage: string;
|
|
throughput: ThroughputDefaults;
|
|
}
|
|
|
|
export interface Node {
|
|
text: string;
|
|
value: string;
|
|
ariaLabel: string;
|
|
}
|
|
|
|
export interface PostgresConnectionStrParams {
|
|
adminLogin: string;
|
|
enablePublicIpAccess: boolean;
|
|
nodes: Node[];
|
|
isMarlinServerGroup: boolean;
|
|
isFreeTier: boolean;
|
|
}
|
|
|
|
export interface VCoreMongoConnectionParams {
|
|
adminLogin: string;
|
|
connectionString: string;
|
|
}
|
|
|
|
export interface FabricArtifactInfo {
|
|
[CosmosDbArtifactType.MIRRORED_KEY]: {
|
|
connectionId: string;
|
|
resourceTokenInfo: ResourceTokenInfo | undefined;
|
|
};
|
|
[CosmosDbArtifactType.MIRRORED_AAD]: undefined;
|
|
[CosmosDbArtifactType.NATIVE]: undefined;
|
|
}
|
|
export interface FabricContext<T extends CosmosDbArtifactType> {
|
|
fabricClientRpcVersion: string;
|
|
isReadOnly: boolean;
|
|
isVisible: boolean;
|
|
databaseName: string;
|
|
artifactType: CosmosDbArtifactType;
|
|
artifactInfo: FabricArtifactInfo[T];
|
|
}
|
|
|
|
export type AdminFeedbackControlPolicy =
|
|
| "connectedExperiences"
|
|
| "policyAllowFeedback"
|
|
| "policyAllowSurvey"
|
|
| "policyAllowScreenshot"
|
|
| "policyAllowContact"
|
|
| "policyAllowContent"
|
|
| "policyEmailCollectionDefault"
|
|
| "policyScreenshotDefault"
|
|
| "policyContentSamplesDefault";
|
|
|
|
export type AdminFeedbackPolicySettings = {
|
|
[key in AdminFeedbackControlPolicy]: boolean;
|
|
};
|
|
|
|
export interface UserContext {
|
|
readonly fabricContext?: FabricContext<CosmosDbArtifactType>;
|
|
readonly authType?: AuthType;
|
|
readonly masterKey?: string;
|
|
readonly subscriptionId?: string;
|
|
readonly tenantId?: string;
|
|
readonly userName?: string;
|
|
readonly resourceGroup?: string;
|
|
readonly databaseAccount?: DatabaseAccount;
|
|
readonly endpoint?: string;
|
|
readonly aadToken?: string;
|
|
readonly accessToken?: string;
|
|
readonly authorizationToken?: string;
|
|
readonly resourceToken?: string;
|
|
readonly subscriptionType?: SubscriptionType;
|
|
readonly quotaId?: string;
|
|
// API Type is not yet provided by ARM. You need to manually inspect all the capabilities+kind so we abstract that logic in userContext
|
|
// This is coming in a future Cosmos ARM API version as a prperty on databaseAccount
|
|
apiType: ApiType;
|
|
readonly isTryCosmosDBSubscription?: boolean;
|
|
readonly portalEnv?: PortalEnv;
|
|
readonly features: Features;
|
|
readonly hasWriteAccess: boolean;
|
|
readonly parsedResourceToken?: {
|
|
databaseId: string;
|
|
collectionId: string;
|
|
partitionKey?: string;
|
|
};
|
|
readonly postgresConnectionStrParams?: PostgresConnectionStrParams;
|
|
readonly isReplica?: boolean;
|
|
collectionCreationDefaults: CollectionCreationDefaults;
|
|
sampleDataConnectionInfo?: ParsedResourceTokenConnectionString;
|
|
readonly selectedRegionalEndpoint?: string;
|
|
readonly writeEnabledInSelectedRegion?: boolean;
|
|
readonly vcoreMongoConnectionParams?: VCoreMongoConnectionParams;
|
|
readonly feedbackPolicies?: AdminFeedbackPolicySettings;
|
|
readonly dataPlaneRbacEnabled?: boolean;
|
|
readonly refreshCosmosClient?: boolean;
|
|
}
|
|
|
|
export type ApiType = "SQL" | "Mongo" | "Gremlin" | "Tables" | "Cassandra" | "Postgres" | "VCoreMongo";
|
|
export type PortalEnv = "localhost" | "blackforest" | "fairfax" | "mooncake" | "prod1" | "rx" | "ex" | "prod" | "dev";
|
|
|
|
const ONE_WEEK_IN_MS = 604800000;
|
|
|
|
const features = extractFeatures();
|
|
|
|
const userContext: UserContext = {
|
|
apiType: "SQL",
|
|
hasWriteAccess: true,
|
|
isTryCosmosDBSubscription: false,
|
|
portalEnv: "prod",
|
|
features,
|
|
subscriptionType: CollectionCreation.DefaultSubscriptionType,
|
|
collectionCreationDefaults: CollectionCreationDefaults,
|
|
};
|
|
|
|
export function isAccountNewerThanThresholdInMs(createdAt: string, threshold: number) {
|
|
let createdAtMs: number = Date.parse(createdAt);
|
|
if (isNaN(createdAtMs)) {
|
|
createdAtMs = 0;
|
|
}
|
|
|
|
const nowMs: number = Date.now();
|
|
const millisecsSinceAccountCreation = nowMs - createdAtMs;
|
|
return threshold > millisecsSinceAccountCreation;
|
|
}
|
|
|
|
function updateUserContext(newContext: Partial<UserContext>): void {
|
|
if (newContext.databaseAccount) {
|
|
newContext.apiType = apiType(newContext.databaseAccount);
|
|
|
|
const isNewAccount = isAccountNewerThanThresholdInMs(
|
|
newContext.databaseAccount?.systemData?.createdAt || "",
|
|
ONE_WEEK_IN_MS,
|
|
);
|
|
|
|
if (!localStorage.getItem(newContext.databaseAccount.id)) {
|
|
if (newContext.isTryCosmosDBSubscription || isNewAccount) {
|
|
if (newContext.apiType === "Postgres" && !newContext.isReplica) {
|
|
usePostgres.getState().setShowResetPasswordBubble(true);
|
|
usePostgres.getState().setShowPostgreTeachingBubble(true);
|
|
} else {
|
|
useCarousel.getState().setShouldOpen(true);
|
|
localStorage.setItem(newContext.databaseAccount.id, "true");
|
|
traceOpen(Action.OpenCarousel);
|
|
}
|
|
} else if (newContext.apiType === "Postgres") {
|
|
usePostgres.getState().setShowPostgreTeachingBubble(true);
|
|
localStorage.setItem(newContext.databaseAccount.id, "true");
|
|
}
|
|
}
|
|
}
|
|
Object.assign(userContext, newContext);
|
|
}
|
|
|
|
function apiType(account: DatabaseAccount | undefined): ApiType {
|
|
if (!account) {
|
|
return "SQL";
|
|
}
|
|
|
|
const capabilities = account.properties?.capabilities;
|
|
if (capabilities) {
|
|
if (capabilities.find((c) => c.name === "EnableCassandra")) {
|
|
return "Cassandra";
|
|
}
|
|
if (capabilities.find((c) => c.name === "EnableGremlin")) {
|
|
return "Gremlin";
|
|
}
|
|
if (capabilities.find((c) => c.name === "EnableMongo")) {
|
|
return "Mongo";
|
|
}
|
|
if (capabilities.find((c) => c.name === "EnableTable")) {
|
|
return "Tables";
|
|
}
|
|
}
|
|
if (account.kind === "MongoDB" || account.kind === "Parse") {
|
|
return "Mongo";
|
|
}
|
|
if (account.kind === "Postgres") {
|
|
return "Postgres";
|
|
}
|
|
if (account.kind === "VCoreMongo") {
|
|
return "VCoreMongo";
|
|
}
|
|
return "SQL";
|
|
}
|
|
|
|
export { updateUserContext, userContext };
|