Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature: Add flighting support #2621

Merged
merged 28 commits into from
Jun 29, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
ab1c9f9
add variant assignment package
ElinorW Jun 12, 2023
4b220a5
Add variant service
ElinorW Jun 12, 2023
4709352
initialize variant service
ElinorW Jun 12, 2023
c91b549
add getUserId function
ElinorW Jun 13, 2023
3c57a74
Merge branch 'dev' into feature/feature-flags-demo
ElinorW Jun 13, 2023
4ec23ba
remove uneccessary code
ElinorW Jun 14, 2023
b1e6c14
Merge branch 'feature/feature-flags-demo' of https://github.com/micro…
ElinorW Jun 14, 2023
281b9f9
collect assignment context telemetry
ElinorW Jun 15, 2023
003dac5
code cleanup
ElinorW Jun 15, 2023
3243d1e
update experiment
ElinorW Jun 16, 2023
f2b180a
code refactor
ElinorW Jun 16, 2023
bdb5407
Merge branch 'dev' into feature/feature-flags-demo
ElinorW Jun 16, 2023
4499e48
Update local storage function
ElinorW Jun 21, 2023
66031d9
add function to interface
ElinorW Jun 21, 2023
e628099
simplify condition
ElinorW Jun 21, 2023
8a5979e
Merge branch 'feature/feature-flags-demo' of https://github.com/micro…
ElinorW Jun 21, 2023
2d42d00
rename file
ElinorW Jun 21, 2023
e10e981
check for response
ElinorW Jun 21, 2023
badaf02
create a variant constants file
ElinorW Jun 21, 2023
d2518ac
restore function as is
ElinorW Jun 21, 2023
2b4376a
restore value check
ElinorW Jun 21, 2023
ad40202
Merge branch 'dev' into feature/feature-flags-demo
ElinorW Jun 22, 2023
e78ded7
Merge branch 'dev' into feature/feature-flags-demo
ElinorW Jun 22, 2023
6063483
add assignment context to telemetry data
ElinorW Jun 22, 2023
17e489e
remove unused import
ElinorW Jun 22, 2023
7fc2d29
return to previous state
ElinorW Jun 26, 2023
42b832b
Merge branch 'dev' into feature/feature-flags-demo
ElinorW Jun 26, 2023
f26c0ff
remove unused variable
ElinorW Jun 29, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
"eslint-plugin-react": "7.32.2",
"eslint-webpack-plugin": "4.0.1",
"express": "4.18.2",
"expvariantassignmentsdk": "file:packages/expvariantassignmentsdk-1.0.0.tgz",
"file-loader": "6.2.0",
"fork-ts-checker-webpack-plugin": "8.0.0",
"fs-extra": "11.1.1",
Expand Down
Binary file added packages/expvariantassignmentsdk-1.0.0.tgz
Binary file not shown.
5 changes: 3 additions & 2 deletions src/app/middleware/localStorageMiddleware.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,21 @@
import { collectionsCache } from '../../modules/cache/collections.cache';
import { resourcesCache } from '../../modules/cache/resources.cache';
import { samplesCache } from '../../modules/cache/samples.cache';
import { saveTheme } from '../../themes/theme-utils';
import { AppAction } from '../../types/action';
import { ResourcePath } from '../../types/resources';
import { addResourcePaths } from '../services/actions/collections-action-creators';
import { CURRENT_THEME } from '../services/graph-constants';
import { getUniquePaths } from '../services/reducers/collections-reducer.util';
import {
CHANGE_THEME_SUCCESS, COLLECTION_CREATE_SUCCESS, FETCH_RESOURCES_ERROR, FETCH_RESOURCES_SUCCESS,
RESOURCEPATHS_ADD_SUCCESS, RESOURCEPATHS_DELETE_SUCCESS, SAMPLES_FETCH_SUCCESS
} from '../services/redux-constants';
import { saveToLocalStorage } from '../utils/local-storage';

const localStorageMiddleware = (store: any) => (next: any) => async (action: AppAction) => {
switch (action.type) {
case CHANGE_THEME_SUCCESS:
saveTheme(action.response);
saveToLocalStorage(CURRENT_THEME,action.response);
break;

case SAMPLES_FETCH_SUCCESS:
Expand Down
2 changes: 2 additions & 0 deletions src/app/services/graph-constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,5 @@ export const REVOKING_PERMISSIONS_REQUIRED_SCOPES = 'DelegatedPermissionGrant.Re
export const ADMIN_CONSENT_DOC_LINK = 'https://learn.microsoft.com/en-us/graph/security-authorization#:~:text=If%20you%27re%20calling%20the%20Microsoft%20Graph%20Security%20API%20from%20Graph%20Explorer'
// eslint-disable-next-line max-len
export const CONSENT_TYPE_DOC_LINK = 'https://learn.microsoft.com/en-us/graph/api/resources/oauth2permissiongrant?view=graph-rest-1.0#:~:text=(eq%20only).-,consentType,-String'
export const CURRENT_THEME='CURRENT_THEME';
export const EXP_URL='https://default.exp-tas.com/exptas76/9b835cbf-9742-40db-84a7-7a323a77f3eb-gedev/api/v1/tas'
1 change: 1 addition & 0 deletions src/app/services/variant-constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const ALWAYSSHOWBUTTONS = 'alwaysShowButtons';
68 changes: 68 additions & 0 deletions src/app/services/variant-service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/* eslint-disable max-len */
import { VariantAssignmentRequest } from 'expvariantassignmentsdk/src/interfaces/VariantAssignmentRequest';
import {VariantAssignmentServiceClient} from 'expvariantassignmentsdk/src/contracts/VariantAssignmentServiceClient';
import { VariantAssignmentClientSettings } from 'expvariantassignmentsdk/src/contracts/VariantAssignmentClientSettings';
import { errorTypes, telemetry } from '../../telemetry';
import { readFromLocalStorage, saveToLocalStorage } from '../utils/local-storage';
import { EXP_URL } from './graph-constants';
import { SeverityLevel } from '@microsoft/applicationinsights-web';


interface TasResponse {
Id: string;
Parameters: Parameters;
}
interface Parameters {
[key: string]: string | boolean | number;
}
class VariantService {

private endpoint = EXP_URL;
private expResponse: TasResponse[] | null = [];
private assignmentContext: string = '';

public async initialize() {
const settings: VariantAssignmentClientSettings = { endpoint: this.endpoint };
this.createUser();
const request: VariantAssignmentRequest =
{
parameters: this.getParameters()
};

const client = new VariantAssignmentServiceClient(settings);
const response = await client.getVariantAssignments(request);
Promise.resolve(response).then((r) => {
if (r){
this.expResponse = r.featureVariables as TasResponse[] | null;
this.assignmentContext = r.assignmentContext;
}
})
.catch((error) => {
telemetry.trackException(new Error(errorTypes.UNHANDLED_ERROR), SeverityLevel.Error, error);
});
}

public createUser() {
const userid = telemetry.getUserId();
saveToLocalStorage('userid', userid.toString());
}

public getAssignmentContext() {
return this.assignmentContext;
}

public async getFeatureVariables(namespace: string, flagname: string) {
const defaultConfig = this.expResponse?.find(c => c.Id === namespace);
return defaultConfig?.Parameters[flagname];
}

// Parameters will include randomization units (you can have more than one in a single call!)
// and audience filters like market/region, browser, ismsft etc.,
private getParameters(): Map<string, string[]> {
const map: Map<string, string[]> = new Map<string, string[]>();
map.set('userid', [readFromLocalStorage('userid')]);
return map;
}
}

export default new VariantService();
17 changes: 17 additions & 0 deletions src/app/utils/local-storage.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
export const saveToLocalStorage = (key: string, value: Object|string) => {
if (typeof value === 'string') {
localStorage.setItem(key, value);
} else {
localStorage.setItem(key, JSON.stringify(value));
}
ElinorW marked this conversation as resolved.
Show resolved Hide resolved
};

export const readFromLocalStorage = (key: string) => {
const value = localStorage.getItem(key);

if (value && typeof value === 'object') {
return JSON.parse(value);
} else{
return value;
}
};
9 changes: 6 additions & 3 deletions src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,16 +26,18 @@ import './styles/index.scss';
import { telemetry } from './telemetry';
import ITelemetry from './telemetry/ITelemetry';
import { loadGETheme } from './themes';
import { readTheme } from './themes/theme-utils';
import { readFromLocalStorage } from './app/utils/local-storage';
import { IDevxAPI } from './types/devx-api';
import { Mode } from './types/enums';
import { Collection } from './types/resources';
import variantService from './app/services/variant-service';
import { CURRENT_THEME } from './app/services/graph-constants';


const appRoot: HTMLElement = document.getElementById('root')!;
initializeIcons();

let currentTheme = readTheme() || 'light';
let currentTheme = readFromLocalStorage(CURRENT_THEME) || 'light';
export function removeSpinners() {
// removes the loading spinner from GE html after the app is loaded
const spinner = document.getElementById('spinner');
Expand All @@ -54,7 +56,7 @@ export function removeSpinners() {
}

function setCurrentSystemTheme(): void {
const themeFromLocalStorage = readTheme();
const themeFromLocalStorage = readFromLocalStorage(CURRENT_THEME);

if (themeFromLocalStorage) {
currentTheme = themeFromLocalStorage;
Expand Down Expand Up @@ -161,6 +163,7 @@ function loadResources() {
}
loadResources();

variantService.initialize();
const telemetryProvider: ITelemetry = telemetry;
telemetryProvider.initialize();

Expand Down
1 change: 1 addition & 0 deletions src/telemetry/ITelemetry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,5 @@ export default interface ITelemetry {
severityLevel: SeverityLevel,
properties: {}
): void;
getUserId():string
}
16 changes: 14 additions & 2 deletions src/telemetry/telemetry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import {
getBrowserScreenSize,
getDeviceScreenScale
} from '../app/utils/device-characteristics-telemetry';
import variantService from '../app/services/variant-service';

class Telemetry implements ITelemetry {
private appInsights: ApplicationInsights;
Expand Down Expand Up @@ -66,8 +67,10 @@ class Telemetry implements ITelemetry {
this.appInsights.context.application.ver = getVersion().toString();
}

public trackEvent(name: string, properties: {}) {
this.appInsights.trackEvent({ name, properties });
public trackEvent(name: string, properties:{ AssignmentContext?: string, [key: string]: any } = {}) {
const defaultProperties = { AssignmentContext: variantService.getAssignmentContext() };
const mergedProperties = { ...defaultProperties, ...properties };
this.appInsights.trackEvent({ name, properties: mergedProperties });
}

public trackException(
Expand Down Expand Up @@ -140,6 +143,15 @@ class Telemetry implements ITelemetry {
''
);
}

public getUserId(){
ElinorW marked this conversation as resolved.
Show resolved Hide resolved
try {
const userId = document.cookie.split(';').filter((item) => item.trim().startsWith('ai_user')).map((item) => item.split('=')[1])[0];
return userId.split('|')[0];
} catch (error) {
return '';
}
}
}

export const telemetry = new Telemetry();
7 changes: 4 additions & 3 deletions src/themes/theme-utils.spec.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import { saveTheme, readTheme } from './theme-utils';
import { CURRENT_THEME } from '../app/services/graph-constants';
import { readFromLocalStorage, saveToLocalStorage } from '../app/utils/local-storage';

describe('Tests theme utils should', () => {
it('save theme to local storage then retrieve the saved theme', () => {
const theme = 'dark';
saveTheme(theme);
expect(readTheme()).toEqual(theme);
saveToLocalStorage(CURRENT_THEME,theme);
expect(readFromLocalStorage(CURRENT_THEME)).toEqual(theme);
})
})
10 changes: 0 additions & 10 deletions src/themes/theme-utils.ts

This file was deleted.