mirror of
https://github.com/Azure/cosmos-explorer.git
synced 2025-05-24 17:24:55 +01:00
Added AFEC check in userContext (#2140)
* Added AFEC check in userContext * Update unit tests and fix Group to Bucket
This commit is contained in:
parent
44d815454c
commit
1081432bbd
@ -1,7 +1,6 @@
|
|||||||
import { AuthType } from "AuthType";
|
import { AuthType } from "AuthType";
|
||||||
import { shallow } from "enzyme";
|
import { shallow } from "enzyme";
|
||||||
import ko from "knockout";
|
import ko from "knockout";
|
||||||
import { Features } from "Platform/Hosted/extractFeatures";
|
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { updateCollection } from "../../../Common/dataAccess/updateCollection";
|
import { updateCollection } from "../../../Common/dataAccess/updateCollection";
|
||||||
import { updateOffer } from "../../../Common/dataAccess/updateOffer";
|
import { updateOffer } from "../../../Common/dataAccess/updateOffer";
|
||||||
@ -253,7 +252,7 @@ describe("SettingsComponent", () => {
|
|||||||
it("should save throughput bucket changes when Save button is clicked", async () => {
|
it("should save throughput bucket changes when Save button is clicked", async () => {
|
||||||
updateUserContext({
|
updateUserContext({
|
||||||
apiType: "SQL",
|
apiType: "SQL",
|
||||||
features: { enableThroughputBuckets: true } as Features,
|
throughputBucketsEnabled: true,
|
||||||
authType: AuthType.AAD,
|
authType: AuthType.AAD,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -191,10 +191,7 @@ export class SettingsComponent extends React.Component<SettingsComponentProps, S
|
|||||||
this.isFullTextSearchEnabled = isFullTextSearchEnabled() && !hasDatabaseSharedThroughput(this.collection);
|
this.isFullTextSearchEnabled = isFullTextSearchEnabled() && !hasDatabaseSharedThroughput(this.collection);
|
||||||
|
|
||||||
this.changeFeedPolicyVisible = userContext.features.enableChangeFeedPolicy;
|
this.changeFeedPolicyVisible = userContext.features.enableChangeFeedPolicy;
|
||||||
this.throughputBucketsEnabled =
|
this.throughputBucketsEnabled = userContext.throughputBucketsEnabled;
|
||||||
userContext.apiType === "SQL" &&
|
|
||||||
userContext.features.enableThroughputBuckets &&
|
|
||||||
userContext.authType === AuthType.AAD;
|
|
||||||
|
|
||||||
// Mongo container with system partition key still treat as "Fixed"
|
// Mongo container with system partition key still treat as "Fixed"
|
||||||
this.isFixedContainer =
|
this.isFixedContainer =
|
||||||
|
@ -26,7 +26,7 @@ describe("ThroughputBucketsComponent", () => {
|
|||||||
|
|
||||||
it("renders the correct number of buckets", () => {
|
it("renders the correct number of buckets", () => {
|
||||||
render(<ThroughputBucketsComponent {...defaultProps} />);
|
render(<ThroughputBucketsComponent {...defaultProps} />);
|
||||||
expect(screen.getAllByText(/Group \d+/)).toHaveLength(5);
|
expect(screen.getAllByText(/Bucket \d+/)).toHaveLength(5);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("renders buckets in the correct order even if input is unordered", () => {
|
it("renders buckets in the correct order even if input is unordered", () => {
|
||||||
@ -36,8 +36,14 @@ describe("ThroughputBucketsComponent", () => {
|
|||||||
];
|
];
|
||||||
render(<ThroughputBucketsComponent {...defaultProps} currentBuckets={unorderedBuckets} />);
|
render(<ThroughputBucketsComponent {...defaultProps} currentBuckets={unorderedBuckets} />);
|
||||||
|
|
||||||
const bucketLabels = screen.getAllByText(/Group \d+/).map((el) => el.textContent);
|
const bucketLabels = screen.getAllByText(/Bucket \d+/).map((el) => el.textContent);
|
||||||
expect(bucketLabels).toEqual(["Group 1 (Data Explorer Query Bucket)", "Group 2", "Group 3", "Group 4", "Group 5"]);
|
expect(bucketLabels).toEqual([
|
||||||
|
"Bucket 1 (Data Explorer Query Bucket)",
|
||||||
|
"Bucket 2",
|
||||||
|
"Bucket 3",
|
||||||
|
"Bucket 4",
|
||||||
|
"Bucket 5",
|
||||||
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("renders all provided buckets even if they exceed the max default bucket count", () => {
|
it("renders all provided buckets even if they exceed the max default bucket count", () => {
|
||||||
@ -53,7 +59,7 @@ describe("ThroughputBucketsComponent", () => {
|
|||||||
|
|
||||||
render(<ThroughputBucketsComponent {...defaultProps} currentBuckets={oversizedBuckets} />);
|
render(<ThroughputBucketsComponent {...defaultProps} currentBuckets={oversizedBuckets} />);
|
||||||
|
|
||||||
expect(screen.getAllByText(/Group \d+/)).toHaveLength(7);
|
expect(screen.getAllByText(/Bucket \d+/)).toHaveLength(7);
|
||||||
|
|
||||||
expect(screen.getByDisplayValue("50")).toBeInTheDocument();
|
expect(screen.getByDisplayValue("50")).toBeInTheDocument();
|
||||||
expect(screen.getByDisplayValue("60")).toBeInTheDocument();
|
expect(screen.getByDisplayValue("60")).toBeInTheDocument();
|
||||||
@ -171,7 +177,7 @@ describe("ThroughputBucketsComponent", () => {
|
|||||||
|
|
||||||
it("ensures default buckets are used when no buckets are provided", () => {
|
it("ensures default buckets are used when no buckets are provided", () => {
|
||||||
render(<ThroughputBucketsComponent {...defaultProps} currentBuckets={[]} />);
|
render(<ThroughputBucketsComponent {...defaultProps} currentBuckets={[]} />);
|
||||||
expect(screen.getAllByText(/Group \d+/)).toHaveLength(5);
|
expect(screen.getAllByText(/Bucket \d+/)).toHaveLength(5);
|
||||||
expect(screen.getAllByDisplayValue("100")).toHaveLength(5);
|
expect(screen.getAllByDisplayValue("100")).toHaveLength(5);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -76,7 +76,7 @@ export const ThroughputBucketsComponent: FC<ThroughputBucketsComponentProps> = (
|
|||||||
value={bucket.maxThroughputPercentage}
|
value={bucket.maxThroughputPercentage}
|
||||||
onChange={(newValue) => handleBucketChange(bucket.id, newValue)}
|
onChange={(newValue) => handleBucketChange(bucket.id, newValue)}
|
||||||
showValue={false}
|
showValue={false}
|
||||||
label={`Group ${bucket.id}${bucket.id === 1 ? " (Data Explorer Query Bucket)" : ""}`}
|
label={`Bucket ${bucket.id}${bucket.id === 1 ? " (Data Explorer Query Bucket)" : ""}`}
|
||||||
styles={{ root: { flex: 2, maxWidth: 400 } }}
|
styles={{ root: { flex: 2, maxWidth: 400 } }}
|
||||||
disabled={bucket.maxThroughputPercentage === 100}
|
disabled={bucket.maxThroughputPercentage === 100}
|
||||||
/>
|
/>
|
||||||
|
@ -12,6 +12,7 @@ import { isFabricMirrored, isFabricMirroredKey, scheduleRefreshFabricToken } fro
|
|||||||
import { LocalStorageUtility, StorageKey } from "Shared/StorageUtility";
|
import { LocalStorageUtility, StorageKey } from "Shared/StorageUtility";
|
||||||
import { acquireMsalTokenForAccount } from "Utils/AuthorizationUtils";
|
import { acquireMsalTokenForAccount } from "Utils/AuthorizationUtils";
|
||||||
import { allowedNotebookServerUrls, validateEndpoint } from "Utils/EndpointUtils";
|
import { allowedNotebookServerUrls, validateEndpoint } from "Utils/EndpointUtils";
|
||||||
|
import { featureRegistered } from "Utils/FeatureRegistrationUtils";
|
||||||
import { update } from "Utils/arm/generatedClients/cosmos/databaseAccounts";
|
import { update } from "Utils/arm/generatedClients/cosmos/databaseAccounts";
|
||||||
import { useQueryCopilot } from "hooks/useQueryCopilot";
|
import { useQueryCopilot } from "hooks/useQueryCopilot";
|
||||||
import * as ko from "knockout";
|
import * as ko from "knockout";
|
||||||
@ -1196,6 +1197,11 @@ export default class Explorer {
|
|||||||
await this.initNotebooks(userContext.databaseAccount);
|
await this.initNotebooks(userContext.databaseAccount);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (userContext.authType === AuthType.AAD && userContext.apiType === "SQL") {
|
||||||
|
const throughputBucketsEnabled = await featureRegistered(userContext.subscriptionId, "ThroughputBucketing");
|
||||||
|
updateUserContext({ throughputBucketsEnabled });
|
||||||
|
}
|
||||||
|
|
||||||
this.refreshSampleData();
|
this.refreshSampleData();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -117,6 +117,7 @@ export interface UserContext {
|
|||||||
readonly feedbackPolicies?: AdminFeedbackPolicySettings;
|
readonly feedbackPolicies?: AdminFeedbackPolicySettings;
|
||||||
readonly dataPlaneRbacEnabled?: boolean;
|
readonly dataPlaneRbacEnabled?: boolean;
|
||||||
readonly refreshCosmosClient?: boolean;
|
readonly refreshCosmosClient?: boolean;
|
||||||
|
throughputBucketsEnabled?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type ApiType = "SQL" | "Mongo" | "Gremlin" | "Tables" | "Cassandra" | "Postgres" | "VCoreMongo";
|
export type ApiType = "SQL" | "Mongo" | "Gremlin" | "Tables" | "Cassandra" | "Postgres" | "VCoreMongo";
|
||||||
|
48
src/Utils/FeatureRegistrationUtils.ts
Normal file
48
src/Utils/FeatureRegistrationUtils.ts
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
import { configContext } from "ConfigContext";
|
||||||
|
import { FeatureRegistration } from "Contracts/DataModels";
|
||||||
|
import { AuthorizationTokenHeaderMetadata } from "Contracts/ViewModels";
|
||||||
|
import { getAuthorizationHeader } from "Utils/AuthorizationUtils";
|
||||||
|
|
||||||
|
export const featureRegistered = async (subscriptionId: string, feature: string) => {
|
||||||
|
const api_version = "2021-07-01";
|
||||||
|
const url = `${configContext.ARM_ENDPOINT}/subscriptions/${subscriptionId}/providers/Microsoft.Features/featureProviders/Microsoft.DocumentDB/subscriptionFeatureRegistrations/${feature}?api-version=${api_version}`;
|
||||||
|
const authorizationHeader: AuthorizationTokenHeaderMetadata = getAuthorizationHeader();
|
||||||
|
const headers = { [authorizationHeader.header]: authorizationHeader.token };
|
||||||
|
|
||||||
|
let response;
|
||||||
|
|
||||||
|
try {
|
||||||
|
response = await _fetchWithTimeout(url, headers);
|
||||||
|
} catch (error) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!response?.ok) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const featureRegistration = (await response?.json()) as FeatureRegistration;
|
||||||
|
return featureRegistration?.properties?.state === "Registered";
|
||||||
|
};
|
||||||
|
|
||||||
|
async function _fetchWithTimeout(
|
||||||
|
url: string,
|
||||||
|
headers: {
|
||||||
|
[x: string]: string;
|
||||||
|
},
|
||||||
|
) {
|
||||||
|
const timeout = 10000;
|
||||||
|
const options = { timeout };
|
||||||
|
|
||||||
|
const controller = new AbortController();
|
||||||
|
const id = setTimeout(() => controller.abort(), timeout);
|
||||||
|
|
||||||
|
const response = await window.fetch(url, {
|
||||||
|
headers,
|
||||||
|
...options,
|
||||||
|
signal: controller.signal,
|
||||||
|
});
|
||||||
|
clearTimeout(id);
|
||||||
|
|
||||||
|
return response;
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user