mirror of
https://github.com/Azure/cosmos-explorer.git
synced 2025-03-13 05:15:30 +00:00
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).
This commit is contained in:
parent
9116c7172f
commit
a91858242e
@ -232,6 +232,10 @@ export class SavedQueries {
|
|||||||
public static readonly PartitionKeyProperty: string = "id";
|
public static readonly PartitionKeyProperty: string = "id";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class RegionSelectionOptions {
|
||||||
|
public static readonly Global: string = "Global";
|
||||||
|
}
|
||||||
|
|
||||||
export class DocumentsGridMetrics {
|
export class DocumentsGridMetrics {
|
||||||
public static DocumentsPerPage: number = 100;
|
public static DocumentsPerPage: number = 100;
|
||||||
public static IndividualRowHeight: number = 34;
|
public static IndividualRowHeight: number = 34;
|
||||||
|
@ -119,7 +119,11 @@ export const endpoint = () => {
|
|||||||
const location = _global.parent ? _global.parent.location : _global.location;
|
const location = _global.parent ? _global.parent.location : _global.location;
|
||||||
return configContext.EMULATOR_ENDPOINT || location.origin;
|
return configContext.EMULATOR_ENDPOINT || location.origin;
|
||||||
}
|
}
|
||||||
return userContext.endpoint || userContext?.databaseAccount?.properties?.documentEndpoint;
|
return (
|
||||||
|
userContext.endpoint ||
|
||||||
|
userContext.selectedRegionalEndpoint ||
|
||||||
|
userContext?.databaseAccount?.properties?.documentEndpoint
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export async function getTokenFromAuthService(
|
export async function getTokenFromAuthService(
|
||||||
@ -253,13 +257,15 @@ export function client(): Cosmos.CosmosClient {
|
|||||||
|
|
||||||
const currentWriteRegion = await client.getWriteEndpoint();
|
const currentWriteRegion = await client.getWriteEndpoint();
|
||||||
console.log(`Current write endpoint: ${JSON.stringify(currentWriteRegion)}`);
|
console.log(`Current write endpoint: ${JSON.stringify(currentWriteRegion)}`);
|
||||||
console.log(`Current userContext endpoint: ${JSON.stringify(userContext?.endpoint)}`);
|
console.log(
|
||||||
|
`Current userContext.selectedRegionalEndpoint: ${JSON.stringify(userContext?.selectedRegionalEndpoint)}`,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const options: Cosmos.CosmosClientOptions = {
|
const options: Cosmos.CosmosClientOptions = {
|
||||||
endpoint: endpoint() || "https://cosmos.azure.com", // CosmosClient gets upset if we pass a bad URL. This should never actually get called
|
// endpoint: endpoint() || "https://cosmos.azure.com", // CosmosClient gets upset if we pass a bad URL. This should never actually get called
|
||||||
// endpoint: "https://test-craig-nosql-westus3.documents.azure.com:443/",
|
// endpoint: "https://test-craig-nosql-westus3.documents.azure.com:443/",
|
||||||
// endpoint: "https://test-craig-nosql-eastus2.documents.azure.com:443/",
|
endpoint: "https://test-craig-nosql-eastus2.documents.azure.com:443/",
|
||||||
key: userContext.dataPlaneRbacEnabled ? "" : userContext.masterKey,
|
key: userContext.dataPlaneRbacEnabled ? "" : userContext.masterKey,
|
||||||
tokenProvider,
|
tokenProvider,
|
||||||
userAgentSuffix: "Azure Portal",
|
userAgentSuffix: "Azure Portal",
|
||||||
|
@ -144,10 +144,10 @@ export const SettingsPane: FunctionComponent<{ explorer: Explorer }> = ({
|
|||||||
? LocalStorageUtility.getEntryString(StorageKey.IsGraphAutoVizDisabled)
|
? LocalStorageUtility.getEntryString(StorageKey.IsGraphAutoVizDisabled)
|
||||||
: "false",
|
: "false",
|
||||||
);
|
);
|
||||||
const [readRegion, setReadRegion] = useState<string>(
|
const [selectedRegion, setSelectedRegion] = useState<string>(
|
||||||
LocalStorageUtility.hasItem(StorageKey.ReadRegion)
|
LocalStorageUtility.hasItem(StorageKey.SelectedRegion)
|
||||||
? LocalStorageUtility.getEntryString(StorageKey.ReadRegion)
|
? LocalStorageUtility.getEntryString(StorageKey.SelectedRegion)
|
||||||
: userContext?.databaseAccount?.properties?.readLocations?.[0]?.locationName,
|
: Constants.RegionSelectionOptions.Global,
|
||||||
);
|
);
|
||||||
const [retryAttempts, setRetryAttempts] = useState<number>(
|
const [retryAttempts, setRetryAttempts] = useState<number>(
|
||||||
LocalStorageUtility.hasItem(StorageKey.RetryAttempts)
|
LocalStorageUtility.hasItem(StorageKey.RetryAttempts)
|
||||||
@ -186,10 +186,44 @@ export const SettingsPane: FunctionComponent<{ explorer: Explorer }> = ({
|
|||||||
const shouldShowCrossPartitionOption = userContext.apiType !== "Gremlin";
|
const shouldShowCrossPartitionOption = userContext.apiType !== "Gremlin";
|
||||||
const shouldShowParallelismOption = userContext.apiType !== "Gremlin";
|
const shouldShowParallelismOption = userContext.apiType !== "Gremlin";
|
||||||
const shouldShowPriorityLevelOption = PriorityBasedExecutionUtils.isFeatureEnabled();
|
const shouldShowPriorityLevelOption = PriorityBasedExecutionUtils.isFeatureEnabled();
|
||||||
const readRegionOptions = userContext?.databaseAccount?.properties?.readLocations?.map((location) => ({
|
|
||||||
key: location.locationName,
|
const uniqueAccountRegions = new Set<string>();
|
||||||
text: location.locationName,
|
const regionOptions: IDropdownOption[] = [];
|
||||||
}));
|
regionOptions.push({
|
||||||
|
key: Constants.RegionSelectionOptions.Global,
|
||||||
|
text: `${Constants.RegionSelectionOptions.Global} (Default)`,
|
||||||
|
data: {
|
||||||
|
endpoint: userContext?.databaseAccount?.properties?.documentEndpoint,
|
||||||
|
writeEnabled: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
userContext?.databaseAccount?.properties?.writeLocations?.forEach((loc) => {
|
||||||
|
if (!uniqueAccountRegions.has(loc.locationName)) {
|
||||||
|
uniqueAccountRegions.add(loc.locationName);
|
||||||
|
regionOptions.push({
|
||||||
|
key: loc.locationName,
|
||||||
|
text: `${loc.locationName} (Read/Write)`,
|
||||||
|
data: {
|
||||||
|
endpoint: loc.documentEndpoint,
|
||||||
|
writeEnabled: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
userContext?.databaseAccount?.properties?.readLocations?.forEach((loc) => {
|
||||||
|
if (!uniqueAccountRegions.has(loc.locationName)) {
|
||||||
|
uniqueAccountRegions.add(loc.locationName);
|
||||||
|
regionOptions.push({
|
||||||
|
key: loc.locationName,
|
||||||
|
text: `${loc.locationName} (Read)`,
|
||||||
|
data: {
|
||||||
|
endpoint: loc.documentEndpoint,
|
||||||
|
writeEnabled: false,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
const shouldShowCopilotSampleDBOption =
|
const shouldShowCopilotSampleDBOption =
|
||||||
userContext.apiType === "SQL" &&
|
userContext.apiType === "SQL" &&
|
||||||
useQueryCopilot.getState().copilotEnabled &&
|
useQueryCopilot.getState().copilotEnabled &&
|
||||||
@ -273,20 +307,12 @@ export const SettingsPane: FunctionComponent<{ explorer: Explorer }> = ({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if region selection has been updated. Update database account in user context accordingly.
|
// TODO: Check if region selection has been updated. Update database account in user context accordingly.
|
||||||
const updatedDatabaseAccount = {
|
|
||||||
...userContext.databaseAccount,
|
|
||||||
properties: {
|
|
||||||
...userContext.databaseAccount.properties,
|
|
||||||
documentEndpoint: userContext?.databaseAccount?.properties?.readLocations?.find(
|
|
||||||
(loc) => loc.locationName === readRegion,
|
|
||||||
)?.documentEndpoint,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
updateUserContext({
|
updateUserContext({
|
||||||
databaseAccount: updatedDatabaseAccount,
|
selectedRegionalEndpoint: regionOptions.find((option) => option.key === selectedRegion)?.data?.endpoint,
|
||||||
hasCosmosClientRegionSettingChanged: true,
|
hasCosmosClientRegionSettingChanged: true,
|
||||||
});
|
});
|
||||||
|
// TODO: If Global selected, then clear out region selection, but keep change variable enabled.
|
||||||
console.log(
|
console.log(
|
||||||
`userContext?.databaseAccount?.properties?.documentEndpoint details: ${JSON.stringify(
|
`userContext?.databaseAccount?.properties?.documentEndpoint details: ${JSON.stringify(
|
||||||
userContext?.databaseAccount?.properties?.documentEndpoint,
|
userContext?.databaseAccount?.properties?.documentEndpoint,
|
||||||
@ -295,7 +321,7 @@ export const SettingsPane: FunctionComponent<{ explorer: Explorer }> = ({
|
|||||||
|
|
||||||
LocalStorageUtility.setEntryBoolean(StorageKey.RUThresholdEnabled, ruThresholdEnabled);
|
LocalStorageUtility.setEntryBoolean(StorageKey.RUThresholdEnabled, ruThresholdEnabled);
|
||||||
LocalStorageUtility.setEntryBoolean(StorageKey.QueryTimeoutEnabled, queryTimeoutEnabled);
|
LocalStorageUtility.setEntryBoolean(StorageKey.QueryTimeoutEnabled, queryTimeoutEnabled);
|
||||||
LocalStorageUtility.setEntryString(StorageKey.ReadRegion, readRegion);
|
LocalStorageUtility.setEntryString(StorageKey.SelectedRegion, selectedRegion);
|
||||||
LocalStorageUtility.setEntryNumber(StorageKey.RetryAttempts, retryAttempts);
|
LocalStorageUtility.setEntryNumber(StorageKey.RetryAttempts, retryAttempts);
|
||||||
LocalStorageUtility.setEntryNumber(StorageKey.RetryInterval, retryInterval);
|
LocalStorageUtility.setEntryNumber(StorageKey.RetryInterval, retryInterval);
|
||||||
LocalStorageUtility.setEntryNumber(StorageKey.MaxWaitTimeInSeconds, MaxWaitTimeInSeconds);
|
LocalStorageUtility.setEntryNumber(StorageKey.MaxWaitTimeInSeconds, MaxWaitTimeInSeconds);
|
||||||
@ -443,9 +469,8 @@ export const SettingsPane: FunctionComponent<{ explorer: Explorer }> = ({
|
|||||||
setDefaultQueryResultsView(option.key as SplitterDirection);
|
setDefaultQueryResultsView(option.key as SplitterDirection);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleOnReadRegionOptionChange = (ev: React.FormEvent<HTMLInputElement>, option: IDropdownOption): void => {
|
const handleOnSelectedRegionOptionChange = (ev: React.FormEvent<HTMLInputElement>, option: IDropdownOption): void => {
|
||||||
// TODO: Region validation?
|
setSelectedRegion(option.key as string);
|
||||||
setReadRegion(option.text);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleOnQueryRetryAttemptsSpinButtonChange = (ev: React.MouseEvent<HTMLElement>, newValue?: string): void => {
|
const handleOnQueryRetryAttemptsSpinButtonChange = (ev: React.MouseEvent<HTMLElement>, newValue?: string): void => {
|
||||||
@ -723,9 +748,9 @@ export const SettingsPane: FunctionComponent<{ explorer: Explorer }> = ({
|
|||||||
</InfoTooltip>
|
</InfoTooltip>
|
||||||
</div>
|
</div>
|
||||||
<Dropdown
|
<Dropdown
|
||||||
placeholder={readRegion}
|
placeholder={regionOptions.find((option) => option.key === selectedRegion)?.text}
|
||||||
onChange={handleOnReadRegionOptionChange}
|
onChange={handleOnSelectedRegionOptionChange}
|
||||||
options={readRegionOptions}
|
options={regionOptions}
|
||||||
styles={{ root: { marginBottom: "10px" } }}
|
styles={{ root: { marginBottom: "10px" } }}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
@ -11,7 +11,7 @@ export enum StorageKey {
|
|||||||
RUThreshold,
|
RUThreshold,
|
||||||
QueryTimeoutEnabled,
|
QueryTimeoutEnabled,
|
||||||
QueryTimeout,
|
QueryTimeout,
|
||||||
ReadRegion,
|
SelectedRegion,
|
||||||
WriteRegion,
|
WriteRegion,
|
||||||
RetryAttempts,
|
RetryAttempts,
|
||||||
RetryInterval,
|
RetryInterval,
|
||||||
|
@ -101,6 +101,7 @@ export interface UserContext {
|
|||||||
readonly isReplica?: boolean;
|
readonly isReplica?: boolean;
|
||||||
collectionCreationDefaults: CollectionCreationDefaults;
|
collectionCreationDefaults: CollectionCreationDefaults;
|
||||||
sampleDataConnectionInfo?: ParsedResourceTokenConnectionString;
|
sampleDataConnectionInfo?: ParsedResourceTokenConnectionString;
|
||||||
|
readonly selectedRegionalEndpoint?: string;
|
||||||
readonly vcoreMongoConnectionParams?: VCoreMongoConnectionParams;
|
readonly vcoreMongoConnectionParams?: VCoreMongoConnectionParams;
|
||||||
readonly feedbackPolicies?: AdminFeedbackPolicySettings;
|
readonly feedbackPolicies?: AdminFeedbackPolicySettings;
|
||||||
readonly dataPlaneRbacEnabled?: boolean;
|
readonly dataPlaneRbacEnabled?: boolean;
|
||||||
|
@ -73,11 +73,10 @@ export async function acquireMsalTokenForAccount(
|
|||||||
if (userContext.databaseAccount.properties?.documentEndpoint === undefined) {
|
if (userContext.databaseAccount.properties?.documentEndpoint === undefined) {
|
||||||
throw new Error("Database account has no document endpoint defined");
|
throw new Error("Database account has no document endpoint defined");
|
||||||
}
|
}
|
||||||
// const hrefEndpoint = new URL(userContext.databaseAccount.properties.documentEndpoint).href.replace(
|
const hrefEndpoint = new URL(userContext.databaseAccount.properties.documentEndpoint).href.replace(
|
||||||
// /\/+$/,
|
/\/+$/,
|
||||||
// "/.default",
|
"/.default",
|
||||||
// );
|
);
|
||||||
const hrefEndpoint = new URL("https://test-craig-nosql.documents.azure.com").href.replace(/\/+$/, "/.default");
|
|
||||||
const msalInstance = await getMsalInstance();
|
const msalInstance = await getMsalInstance();
|
||||||
const knownAccounts = msalInstance.getAllAccounts();
|
const knownAccounts = msalInstance.getAllAccounts();
|
||||||
// If user_hint is provided, we will try to use it to find the account.
|
// If user_hint is provided, we will try to use it to find the account.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user