Add Session Id (#2263)

* adding sessionId to UserContext

* add session id

* add session id to settings pane and fix npm run compile

* Add conditional for Portal

* set default session id on userContext init

* fix tests

---------

Co-authored-by: Asier Isayas <aisayas@microsoft.com>
This commit is contained in:
asier-isayas
2025-11-26 13:07:18 -05:00
committed by GitHub
parent 784dadce30
commit a33429fd85
11 changed files with 148 additions and 9 deletions

88
package-lock.json generated
View File

@@ -116,6 +116,7 @@
"tinykeys": "2.1.0",
"underscore": "1.12.1",
"utility-types": "3.10.0",
"uuid": "9.0.0",
"zustand": "3.5.0"
},
"devDependencies": {
@@ -626,6 +627,14 @@
}
}
},
"node_modules/@azure/ms-rest-js/node_modules/uuid": {
"version": "8.3.2",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
"integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==",
"bin": {
"uuid": "dist/bin/uuid"
}
},
"node_modules/@azure/ms-rest-js/node_modules/xml2js": {
"version": "0.5.0",
"license": "MIT",
@@ -685,6 +694,14 @@
"node": ">=0.8.0"
}
},
"node_modules/@azure/msal-node/node_modules/uuid": {
"version": "8.3.2",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
"integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==",
"bin": {
"uuid": "dist/bin/uuid"
}
},
"node_modules/@babel/code-frame": {
"version": "7.24.7",
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.7.tgz",
@@ -7595,6 +7612,14 @@
"uuid": "^8.0.0"
}
},
"node_modules/@nteract/commutable/node_modules/uuid": {
"version": "8.3.2",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
"integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==",
"bin": {
"uuid": "dist/bin/uuid"
}
},
"node_modules/@nteract/connected-components": {
"version": "6.8.2",
"license": "BSD-3-Clause",
@@ -9125,6 +9150,14 @@
"uuid": "^8.0.0"
}
},
"node_modules/@nteract/fixtures/node_modules/uuid": {
"version": "8.3.2",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
"integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==",
"bin": {
"uuid": "dist/bin/uuid"
}
},
"node_modules/@nteract/iron-icons": {
"version": "1.0.0",
"license": "BSD-3-Clause",
@@ -9282,6 +9315,14 @@
"uuid": "^8.0.0"
}
},
"node_modules/@nteract/messaging/node_modules/uuid": {
"version": "8.3.2",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
"integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==",
"bin": {
"uuid": "dist/bin/uuid"
}
},
"node_modules/@nteract/monaco-editor": {
"version": "3.2.2",
"license": "BSD-3-Clause",
@@ -9397,6 +9438,14 @@
"version": "0.18.1",
"license": "MIT"
},
"node_modules/@nteract/monaco-editor/node_modules/uuid": {
"version": "8.3.2",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
"integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==",
"bin": {
"uuid": "dist/bin/uuid"
}
},
"node_modules/@nteract/mythic-configuration": {
"version": "1.0.12",
"license": "BSD-3-Clause",
@@ -9665,6 +9714,14 @@
"uuid": "^8.0.0"
}
},
"node_modules/@nteract/reducers/node_modules/uuid": {
"version": "8.3.2",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
"integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==",
"bin": {
"uuid": "dist/bin/uuid"
}
},
"node_modules/@nteract/selectors": {
"version": "3.2.0",
"license": "BSD-3-Clause",
@@ -9888,6 +9945,14 @@
"uuid": "^8.0.0"
}
},
"node_modules/@nteract/types/node_modules/uuid": {
"version": "8.3.2",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
"integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==",
"bin": {
"uuid": "dist/bin/uuid"
}
},
"node_modules/@octokit/auth-token": {
"version": "4.0.0",
"license": "MIT",
@@ -26419,6 +26484,15 @@
"xmlbuilder": "^15.1.0"
}
},
"node_modules/jest-trx-results-processor/node_modules/uuid": {
"version": "8.3.2",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
"integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==",
"dev": true,
"bin": {
"uuid": "dist/bin/uuid"
}
},
"node_modules/jest-util": {
"version": "24.9.0",
"license": "MIT",
@@ -33753,6 +33827,15 @@
"websocket-driver": "^0.7.4"
}
},
"node_modules/sockjs/node_modules/uuid": {
"version": "8.3.2",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
"integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==",
"dev": true,
"bin": {
"uuid": "dist/bin/uuid"
}
},
"node_modules/source-map": {
"version": "0.5.7",
"license": "BSD-3-Clause",
@@ -35619,8 +35702,9 @@
}
},
"node_modules/uuid": {
"version": "8.3.2",
"license": "MIT",
"version": "9.0.0",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.0.tgz",
"integrity": "sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==",
"bin": {
"uuid": "dist/bin/uuid"
}

View File

@@ -46,8 +46,8 @@
"@types/mkdirp": "1.0.1",
"@types/node-fetch": "2.5.7",
"@xmldom/xmldom": "0.7.13",
"@xterm/xterm": "5.5.0",
"@xterm/addon-fit": "0.10.0",
"@xterm/xterm": "5.5.0",
"allotment": "1.20.2",
"applicationinsights": "1.8.0",
"bootstrap": "3.4.1",
@@ -111,6 +111,7 @@
"tinykeys": "2.1.0",
"underscore": "1.12.1",
"utility-types": "3.10.0",
"uuid": "9.0.0",
"zustand": "3.5.0"
},
"devDependencies": {

View File

@@ -297,6 +297,7 @@ export class HttpHeaders {
public static migrateOfferToManualThroughput: string = "x-ms-cosmos-migrate-offer-to-manual-throughput";
public static migrateOfferToAutopilot: string = "x-ms-cosmos-migrate-offer-to-autopilot";
public static xAPIKey: string = "X-API-Key";
public static sessionId: string = "x-ms-client-session-id";
}
export class ContentType {

View File

@@ -17,6 +17,7 @@ const defaultHeaders = {
[HttpHeaders.apiType]: ApiType.MongoDB.toString(),
[CosmosSDKConstants.HttpHeaders.MaxEntityCount]: "100",
[CosmosSDKConstants.HttpHeaders.Version]: "2017-11-15",
[HttpHeaders.sessionId]: userContext.sessionId,
};
function authHeaders() {

View File

@@ -446,6 +446,7 @@ export interface DataExplorerInputsFrame {
feedbackPolicies?: any;
aadToken?: string;
containerCopyEnabled?: boolean;
sessionId?: string;
}
export interface SelfServeFrameInputs {

View File

@@ -5,6 +5,12 @@ import { updateUserContext } from "../../../UserContext";
import { SettingsPane } from "./SettingsPane";
describe("Settings Pane", () => {
beforeEach(() => {
updateUserContext({
sessionId: "1234-5678",
});
});
it("should render Default properly", () => {
const wrapper = shallow(<SettingsPane explorer={null} />);
expect(wrapper).toMatchSnapshot();

View File

@@ -212,6 +212,7 @@ export const SettingsPane: FunctionComponent<{ explorer: Explorer }> = ({
const styles = useStyles();
const explorerVersion = configContext.gitSha;
const sessionId: string = userContext.sessionId;
const isEmulator = configContext.platform === Platform.Emulator;
const shouldShowQueryPageOptions = userContext.apiType === "SQL";
const showRetrySettings =
@@ -1227,6 +1228,12 @@ export const SettingsPane: FunctionComponent<{ explorer: Explorer }> = ({
<div>{explorerVersion}</div>
</div>
</div>
<div className="settingsSection">
<div className="settingsSectionPart">
<div className="settingsSectionLabel">Session ID</div>
<div>{sessionId}</div>
</div>
</div>
</div>
</RightPaneForm>
);

View File

@@ -649,6 +649,22 @@ exports[`Settings Pane should render Default properly 1`] = `
<div />
</div>
</div>
<div
className="settingsSection"
>
<div
className="settingsSectionPart"
>
<div
className="settingsSectionLabel"
>
Session ID
</div>
<div>
1234-5678
</div>
</div>
</div>
</div>
</RightPaneForm>
`;
@@ -958,6 +974,22 @@ exports[`Settings Pane should render Gremlin properly 1`] = `
<div />
</div>
</div>
<div
className="settingsSection"
>
<div
className="settingsSectionPart"
>
<div
className="settingsSectionLabel"
>
Session ID
</div>
<div>
1234-5678
</div>
</div>
</div>
</div>
</RightPaneForm>
`;

View File

@@ -286,7 +286,7 @@ export class CassandraAPIDataClient extends TableDataClient {
query,
paginationToken,
}),
beforeSend: this.setAuthorizationHeader as any,
beforeSend: this.setCommonHeaders as any,
cache: false,
});
shouldNotify &&
@@ -440,7 +440,7 @@ export class CassandraAPIDataClient extends TableDataClient {
keyspaceId: collection.databaseId,
tableId: collection.id(),
}),
beforeSend: this.setAuthorizationHeader as any,
beforeSend: this.setCommonHeaders as any,
cache: false,
})
.then(
@@ -482,7 +482,7 @@ export class CassandraAPIDataClient extends TableDataClient {
keyspaceId: collection.databaseId,
tableId: collection.id(),
}),
beforeSend: this.setAuthorizationHeader as any,
beforeSend: this.setCommonHeaders as any,
cache: false,
})
.then(
@@ -518,7 +518,7 @@ export class CassandraAPIDataClient extends TableDataClient {
resourceId: resourceId,
query: query,
}),
beforeSend: this.setAuthorizationHeader as any,
beforeSend: this.setCommonHeaders as any,
cache: false,
}).then(
(data: any) => {
@@ -547,7 +547,7 @@ export class CassandraAPIDataClient extends TableDataClient {
return cassandraEndpoint;
}
private setAuthorizationHeader: (xhr: XMLHttpRequest) => boolean = (xhr: XMLHttpRequest): boolean => {
private setCommonHeaders: (xhr: XMLHttpRequest) => boolean = (xhr: XMLHttpRequest): boolean => {
const authorizationHeaderMetadata: ViewModels.AuthorizationTokenHeaderMetadata = getAuthorizationHeader();
xhr.setRequestHeader(authorizationHeaderMetadata.header, authorizationHeaderMetadata.token);
@@ -555,6 +555,7 @@ export class CassandraAPIDataClient extends TableDataClient {
xhr.setRequestHeader(Constants.HttpHeaders.entraIdToken, userContext.aadToken);
}
xhr.setRequestHeader(Constants.HttpHeaders.sessionId, userContext.sessionId);
return true;
};

View File

@@ -4,6 +4,7 @@ import { Action } from "Shared/Telemetry/TelemetryConstants";
import { traceOpen } from "Shared/Telemetry/TelemetryProcessor";
import { useCarousel } from "hooks/useCarousel";
import { usePostgres } from "hooks/usePostgres";
import { v4 as uuidv4 } from "uuid";
import { AuthType } from "./AuthType";
import { DatabaseAccount } from "./Contracts/DataModels";
import { SubscriptionType } from "./Contracts/SubscriptionType";
@@ -118,6 +119,7 @@ export interface UserContext {
readonly dataPlaneRbacEnabled?: boolean;
readonly refreshCosmosClient?: boolean;
throughputBucketsEnabled?: boolean;
readonly sessionId: string;
}
export type ApiType = "SQL" | "Mongo" | "Gremlin" | "Tables" | "Cassandra" | "Postgres" | "VCoreMongo";
@@ -135,6 +137,7 @@ const userContext: UserContext = {
features,
subscriptionType: CollectionCreation.DefaultSubscriptionType,
collectionCreationDefaults: CollectionCreationDefaults,
sessionId: uuidv4(), // Default sessionId - will be overwritten if provided by host
};
export function isAccountNewerThanThresholdInMs(createdAt: string, threshold: number) {

View File

@@ -85,6 +85,7 @@ export function useKnockoutExplorer(platform: Platform): Explorer {
userContext.features.phoenixNotebooks = true;
userContext.features.phoenixFeatures = true;
}
let explorer: Explorer;
if (platform === Platform.Hosted) {
explorer = await configureHosted();
@@ -927,6 +928,7 @@ function updateContextsFromPortalMessage(inputs: DataExplorerInputsFrame) {
collectionCreationDefaults: inputs.defaultCollectionThroughput,
isTryCosmosDBSubscription: inputs.isTryCosmosDBSubscription,
feedbackPolicies: inputs.feedbackPolicies,
...(inputs.sessionId && { sessionId: inputs.sessionId }), // Remove conditional once Portal sends sessionId
});
if (inputs.isPostgresAccount) {