Compare commits

...

14 Commits

Author SHA1 Message Date
Asier Isayas
228f412406 debug 2025-03-24 16:49:21 -04:00
Asier Isayas
cad718acc4 debug 2025-03-24 16:45:58 -04:00
Asier Isayas
0559ec5cb1 debug 2025-03-24 16:23:48 -04:00
Asier Isayas
ca641b2ff5 debug 2025-03-24 16:03:02 -04:00
Asier Isayas
53836a93cd debug 2025-03-24 15:18:20 -04:00
Asier Isayas
c38e42e44b debug 2025-03-24 14:50:42 -04:00
Asier Isayas
6032b39058 debug 2025-03-24 14:06:15 -04:00
Asier Isayas
23852dcd69 debug 2025-03-24 13:03:42 -04:00
Asier Isayas
81bd0f635e decorator debug 2025-03-20 15:32:44 -04:00
Asier Isayas
3efbc57617 npm run format 2025-03-20 13:44:15 -04:00
Asier Isayas
aee8249ffa fix self serve tests 2025-03-20 13:38:51 -04:00
Asier Isayas
14db9e819a fix tests 2025-03-20 13:09:44 -04:00
Asier Isayas
f9e18cf28c Merge branch 'master' of https://github.com/Azure/cosmos-explorer into users/aisayas/self-serve-fix 2025-03-20 12:56:29 -04:00
Asier Isayas
4708722d1a explicitly set className instead of inferring from constructor 2025-03-20 12:56:00 -04:00
8 changed files with 84 additions and 20 deletions

View File

@@ -2,8 +2,9 @@
* @module SelfServe/Decorators
*/
import { TFunction } from "i18next";
import { ChoiceItem, Description, Info, NumberUiType, OnChangeCallback, RefreshParams } from "./SelfServeTypes";
import { addPropertyToMap, buildSmartUiDescriptor, DecoratorProperties } from "./SelfServeUtils";
import { addPropertyToMap, buildSmartUiDescriptor, DecoratorProperties, SelfServeType } from "./SelfServeUtils";
type ValueOf<T> = T[keyof T];
interface Decorator {
@@ -128,8 +129,9 @@ const isDescriptionDisplayOptions = (inputOptions: InputOptions): inputOptions i
};
const addToMap = (...decorators: Decorator[]): PropertyDecorator => {
return (target, property) => {
let className = target.constructor.name;
console.log(decorators);
return async (target, property) => {
let className: string = getTargetName(target);
const propertyName = property.toString();
if (className === "Function") {
//eslint-disable-next-line @typescript-eslint/ban-types
@@ -138,6 +140,7 @@ const addToMap = (...decorators: Decorator[]): PropertyDecorator => {
}
const propertyType = (Reflect.getMetadata("design:type", target, property)?.name as string)?.toLowerCase();
console.log(propertyType);
addPropertyToMap(target, propertyName, className, "type", propertyType);
addPropertyToMap(target, propertyName, className, "dataFieldName", propertyName);
@@ -205,7 +208,8 @@ export const Values = (inputOptions: InputOptions): PropertyDecorator => {
*/
export const IsDisplayable = (): ClassDecorator => {
return (target) => {
buildSmartUiDescriptor(target.name, target.prototype);
let targetName: string = getTargetName(target);
buildSmartUiDescriptor(targetName, target.prototype);
};
};
@@ -215,7 +219,26 @@ export const IsDisplayable = (): ClassDecorator => {
* how often the auto refresh of the page occurs.
*/
export const RefreshOptions = (refreshParams: RefreshParams): ClassDecorator => {
console.log(refreshParams);
return (target) => {
addPropertyToMap(target.prototype, "root", target.name, "refreshParams", refreshParams);
let targetName: string = getTargetName(target);
addPropertyToMap(target.prototype, "root", targetName, "refreshParams", refreshParams);
};
};
const getTargetName = (target: TFunction | Object): string => {
const targetString: string = target.toString();
let targetName: string;
if (targetString.includes(SelfServeType.example)) {
targetName = SelfServeType.example;
} else if (targetString.includes(SelfServeType.graphapicompute)) {
targetName = SelfServeType.graphapicompute;
} else if (targetString.includes(SelfServeType.materializedviewsbuilder)) {
targetName = SelfServeType.materializedviewsbuilder;
} else if (targetString.includes(SelfServeType.sqlx)) {
targetName = SelfServeType.sqlx;
} else {
targetName = target.constructor.name;
}
return targetName;
};

View File

@@ -1,3 +1,4 @@
import { SelfServeType } from "SelfServe/SelfServeUtils";
import { IsDisplayable, OnChange, PropertyInfo, RefreshOptions, Values } from "../Decorators";
import { selfServeTraceStart, selfServeTraceSuccess } from "../SelfServeTelemetryProcessor";
import {
@@ -168,6 +169,10 @@ export default class SelfServeExample extends SelfServeBaseClass {
return defaults;
};
public getSelfServeType = (): SelfServeType => {
return SelfServeType.example;
};
@Values({
labelTKey: "DescriptionLabel",
description: {

View File

@@ -14,7 +14,7 @@ import {
import type { ChoiceItem } from "../SelfServeTypes";
import { BladeType, generateBladeLink } from "../SelfServeUtils";
import { BladeType, generateBladeLink, SelfServeType } from "../SelfServeUtils";
import {
deleteComputeResource,
getCurrentProvisioningState,
@@ -360,6 +360,10 @@ export default class GraphAPICompute extends SelfServeBaseClass {
return defaults;
};
public getSelfServeType = (): SelfServeType => {
return SelfServeType.graphapicompute;
};
@Values({
isDynamicDescription: true,
})

View File

@@ -19,7 +19,7 @@ import {
import type { ChoiceItem } from "../SelfServeTypes";
import { BladeType, generateBladeLink } from "../SelfServeUtils";
import { BladeType, generateBladeLink, SelfServeType } from "../SelfServeUtils";
import {
deleteMaterializedViewsBuilderResource,
getCurrentProvisioningState,
@@ -359,6 +359,10 @@ export default class MaterializedViewsBuilder extends SelfServeBaseClass {
return defaults;
};
public getSelfServeType = (): SelfServeType => {
return SelfServeType.materializedviewsbuilder;
};
@Values({
isDynamicDescription: true,
})

View File

@@ -2,6 +2,7 @@
* @module SelfServe/SelfServeTypes
*/
import { SelfServeType } from "SelfServe/SelfServeUtils";
import { TelemetryData } from "../Shared/Telemetry/TelemetryProcessor";
interface BaseInput {
@@ -120,9 +121,11 @@ export abstract class SelfServeBaseClass {
*/
public abstract onRefresh: () => Promise<RefreshResult>;
public abstract getSelfServeType: () => SelfServeType;
public test: string = "hello";
/**@internal */
public toSelfServeDescriptor(): SelfServeDescriptor {
const className = this.constructor.name;
const className: string = this.getSelfServeType();
const selfServeDescriptor = Reflect.getMetadata(className, this) as SelfServeDescriptor;
if (!this.initialize) {

View File

@@ -1,42 +1,60 @@
import { NumberUiType, OnSaveResult, RefreshResult, SelfServeBaseClass, SmartUiInput } from "./SelfServeTypes";
import { DecoratorProperties, mapToSmartUiDescriptor, updateContextWithDecorator } from "./SelfServeUtils";
import {
DecoratorProperties,
mapToSmartUiDescriptor,
SelfServeType,
updateContextWithDecorator,
} from "./SelfServeUtils";
describe("SelfServeUtils", () => {
const getSelfServeTypeExample = (): SelfServeType => {
return SelfServeType.example;
};
it("initialize should be declared for self serve classes", () => {
class Test extends SelfServeBaseClass {
class SelfServeExample extends SelfServeBaseClass {
public initialize: () => Promise<Map<string, SmartUiInput>>;
public onSave: (currentValues: Map<string, SmartUiInput>) => Promise<OnSaveResult>;
public onRefresh: () => Promise<RefreshResult>;
public getSelfServeType = (): SelfServeType => getSelfServeTypeExample();
}
expect(() => new Test().toSelfServeDescriptor()).toThrow("initialize() was not declared for the class 'Test'");
expect(() => new SelfServeExample().toSelfServeDescriptor()).toThrow(
"initialize() was not declared for the class 'SelfServeExample'",
);
});
it("onSave should be declared for self serve classes", () => {
class Test extends SelfServeBaseClass {
class SelfServeExample extends SelfServeBaseClass {
public initialize = jest.fn();
public onSave: () => Promise<OnSaveResult>;
public onRefresh: () => Promise<RefreshResult>;
public getSelfServeType = (): SelfServeType => getSelfServeTypeExample();
}
expect(() => new Test().toSelfServeDescriptor()).toThrow("onSave() was not declared for the class 'Test'");
expect(() => new SelfServeExample().toSelfServeDescriptor()).toThrow(
"onSave() was not declared for the class 'SelfServeExample'",
);
});
it("onRefresh should be declared for self serve classes", () => {
class Test extends SelfServeBaseClass {
class SelfServeExample extends SelfServeBaseClass {
public initialize = jest.fn();
public onSave = jest.fn();
public onRefresh: () => Promise<RefreshResult>;
public getSelfServeType = (): SelfServeType => getSelfServeTypeExample();
}
expect(() => new Test().toSelfServeDescriptor()).toThrow("onRefresh() was not declared for the class 'Test'");
expect(() => new SelfServeExample().toSelfServeDescriptor()).toThrow(
"onRefresh() was not declared for the class 'SelfServeExample'",
);
});
it("@IsDisplayable decorator must be present for self serve classes", () => {
class Test extends SelfServeBaseClass {
class SelfServeExample extends SelfServeBaseClass {
public initialize = jest.fn();
public onSave = jest.fn();
public onRefresh = jest.fn();
public getSelfServeType = (): SelfServeType => getSelfServeTypeExample();
}
expect(() => new Test().toSelfServeDescriptor()).toThrow(
"@IsDisplayable decorator was not declared for the class 'Test'",
expect(() => new SelfServeExample().toSelfServeDescriptor()).toThrow(
"@IsDisplayable decorator was not declared for the class 'SelfServeExample'",
);
});

View File

@@ -141,6 +141,9 @@ export const updateContextWithDecorator = <T extends keyof DecoratorProperties,
descriptorName: keyof DecoratorProperties,
descriptorValue: K,
): void => {
console.log(context);
console.log(propertyName);
console.log(className);
if (!(context instanceof Map)) {
throw new Error(`@IsDisplayable should be the first decorator for the class '${className}'.`);
}

View File

@@ -20,7 +20,7 @@ import {
import type { ChoiceItem } from "../SelfServeTypes";
import { BladeType, generateBladeLink } from "../SelfServeUtils";
import { BladeType, generateBladeLink, SelfServeType } from "../SelfServeUtils";
import {
deleteDedicatedGatewayResource,
getCurrentProvisioningState,
@@ -396,6 +396,10 @@ export default class SqlX extends SelfServeBaseClass {
return defaults;
};
public getSelfServeType = (): SelfServeType => {
return SelfServeType.sqlx;
};
@Values({
isDynamicDescription: true,
})