diff --git a/README.md b/README.md index 03e0ddb..1737898 100644 --- a/README.md +++ b/README.md @@ -25,6 +25,7 @@ to build and run the source code: # Getting started, Download and Installation Checkout the [how-to.md](./docs/how-to.md) quick guide in the `/docs`-folder. +HTTP requests may be found in ``/workbench/backend/http_requests`` directory. You will need to [set an environment](https://www.jetbrains.com/help/idea/http-client-in-product-code-editor.html) with with several variables in order to execute the requests. ## Running pre build docker container locally ```bash @@ -51,7 +52,7 @@ d -> deploy - Refer to [constraints and limitations](https://help.sap.com/viewer/fsm_ai/Cloud/en-US/constraints-limitations.html) documentation # Known Issues -- There are no known issues for the moment. +- Maintainers of the project have to observe changes in the DTO Model and make sure the [fsm-sdk dependency is updated](https://github.com/SAP/fsm-sdk/blob/master/src/test/update-dto-versions.ts) accordingly, otherwise the query API will fail. The update in fsm-sdk has to be manually executed. # Supplements On top of the workbench application, you can also configure Business Rules to trigger reoptimization and avoid scenarios like overlapping jobs for a Technician. Refer to [business-rules](/business-rules) folder. diff --git a/workbench/backend/http_requests/fetch_plugins.http b/workbench/backend/http_requests/fetch_plugins.http new file mode 100644 index 0000000..1d3d4d5 --- /dev/null +++ b/workbench/backend/http_requests/fetch_plugins.http @@ -0,0 +1,12 @@ +GET https://qt.fsm-dev.cloud.sap/optimization/api/v1/plugins +accept: application/json +Authorization: {{Token}} +X-Request-Id: {{X-Request-Id}} +X-Client-Id: {{X-Client-Id}} +X-Client-Version: 0.0.0 +X-Account-Id: {{X-Account-Id}} +X-Account-Name: {{X-Account-Name}} +X-Company-Id: {{X-Company-Id}} +X-Company-Name: {{X-Company-Name}} +X-User-Id: {{X-User-Id}} +X-User-Name: {{X-User-Name}} diff --git a/workbench/backend/src/app/plugin/ai-data-api.dao.ts b/workbench/backend/src/app/plugin/ai-data-api.dao.ts index bac59ad..77682ba 100644 --- a/workbench/backend/src/app/plugin/ai-data-api.dao.ts +++ b/workbench/backend/src/app/plugin/ai-data-api.dao.ts @@ -3,17 +3,22 @@ import { Context } from '../../ctx.decorator'; import { AxiosRequestConfig, AxiosError } from 'axios'; import { tap, catchError } from 'rxjs/operators'; import { throwError } from 'rxjs'; -import { FSM_HOSTS_CORESUITE_TO_COREINFRA } from 'src/common/constants'; +import { FSM_HOSTS_CORESUITE_TO_COREINFRA, FSM_HOSTS_CORESUITE_TO_SAPCLOUD } from 'src/common/constants'; export type PluginDto = { - is: string, + id: string, name: string; description: string; defaultPlugin: boolean; + standardPlugin: boolean; pluginCode: string; scheduleConfigId: string; } +export type PluginFetchResultDTO = { + results: PluginDto[] +} + @Injectable() export class AiDataAPIDAO { @@ -23,6 +28,10 @@ export class AiDataAPIDAO { return `https://${FSM_HOSTS_CORESUITE_TO_COREINFRA.get(host.toLowerCase()) || ''}`; } + private resolveSAPCloudHost(host: string) { + return `https://${FSM_HOSTS_CORESUITE_TO_SAPCLOUD.get(host.toLowerCase()) || ''}`; + } + private getParams(ctx: Context) { return { companyId: ctx.companyId, @@ -71,9 +80,9 @@ export class AiDataAPIDAO { } getAll(ctx: Context) { - return this.request({ + return this.request({ method: 'GET', - url: `${this.resolveHost(ctx.cloudHost)}/cloud-ai-policy-designer/api/optimization/v1/policies`, + url: `${this.resolveSAPCloudHost(ctx.cloudHost)}/optimization/api/v1/plugins`, headers: this.getHeaders(ctx), params: this.getParams(ctx), responseType: 'json', diff --git a/workbench/backend/src/common/constants.ts b/workbench/backend/src/common/constants.ts index b9d33cd..271688f 100644 --- a/workbench/backend/src/common/constants.ts +++ b/workbench/backend/src/common/constants.ts @@ -26,4 +26,14 @@ export const FSM_HOSTS_CORESUITE_TO_COREINFRA = new Map() .set('de.coresuite.com', 'ingress.de-1.coreinfra.io') .set('us.coresuite.com', 'ingress.us-1.coreinfra.io') .set('au.coresuite.com', 'ingress.au-1.coreinfra.io') - .set('cn.coresuite.com', 'ingress.cn-1.coreinfra.io'); \ No newline at end of file + .set('cn.coresuite.com', 'ingress.cn-1.coreinfra.io'); + +export const FSM_HOSTS_CORESUITE_TO_SAPCLOUD = new Map() + .set('et.dev.coresuite.com', 'et.fsm-dev.cloud.sap') + .set('qt.dev.coresuite.com', 'qt.fsm-dev.cloud.sap') + .set('dt.dev.coresuite.com', 'dt.fsm-dev.cloud.sap') + .set('us.coresuite.com', 'us.fsm-dev.cloud.sap') + .set('au.coresuite.com', 'au.fsm-dev.cloud.sap') + .set('de.coresuite.com', 'de.fsm-dev.cloud.sap') + .set('eu.coresuite.com', 'eu.fsm-dev.cloud.sap') + .set('cn.coresuite.com', 'cn.fsm-dev.cloud.sap'); diff --git a/workbench/frontend/src/app/common/components/plugin-editor/plugin-editor.component.ts b/workbench/frontend/src/app/common/components/plugin-editor/plugin-editor.component.ts index e7a6c27..7052deb 100644 --- a/workbench/frontend/src/app/common/components/plugin-editor/plugin-editor.component.ts +++ b/workbench/frontend/src/app/common/components/plugin-editor/plugin-editor.component.ts @@ -6,7 +6,7 @@ import { BehaviorSubject, merge, Observable, of, Subject } from 'rxjs'; import { catchError, filter, map, mergeMap, switchMap, take, takeUntil, tap } from 'rxjs/operators'; import { SaveDialog } from './save-dialog/save-dialog.component'; import { pluginTemplate } from './plugin-template'; -import { PluginDto, PluginService, PolicyObjectiveDto } from '../../services/plugin.service'; +import { PluginDto, PluginFetchResultDTO, PluginService, PolicyObjectiveDto } from '../../services/plugin.service'; import { MatSnackBar, MatSnackBarRef, TextOnlySnackBar } from '@angular/material/snack-bar'; export interface PluginEditorData { @@ -36,11 +36,6 @@ export class PluginEditorComponent implements OnInit, OnDestroy, AfterContentIni private onDestroy$ = new Subject(); private refresh = new BehaviorSubject(false); - public editorOptions = { - theme: 'vs-light', - language: 'java' - }; - @Output() changePlugin = new EventEmitter(); @ViewChild('editorInstance') editorInstance: EditorComponent; @@ -55,29 +50,6 @@ export class PluginEditorComponent implements OnInit, OnDestroy, AfterContentIni return this.snackBar.open(msg, 'ok', { duration: 3000 }); } - public onEditorInit(editor): void { - // how to key bind - // https://microsoft.github.io/monaco-editor/playground.html#interacting-with-the-editor-adding-an-action-to-an-editor-instance - editor.addAction({ - id: 'cmd+s-to-save', - label: 'Save (cmd+s)', - keybindings: [ - monaco.KeyMod.CtrlCmd || monaco.KeyCode.KEY_S, - ], - precondition: null, - keybindingContext: null, - contextMenuGroupId: 'navigation', - contextMenuOrder: 1.5, - run: _ed => { - if (this.form.invalid) { - return null; - } - this.save(); - return null; - } - }); - } - public ngAfterContentInit(): void { this.disableEditor$.pipe( filter((value) => this.editorInstance && value === true), @@ -95,13 +67,14 @@ export class PluginEditorComponent implements OnInit, OnDestroy, AfterContentIni console.error(error); this.infoMessage(`[❌ ERROR ❌] 'could not read plugins, disabled editor'`); this.disableEditor$.next(true); - return of([] as PluginDto[]); + return of({} as PluginFetchResultDTO); }) ); this.selectList$ = pluginList$.pipe( - map((list) => { - const defaultPlugin = list.find(x => x.name === DEFAULT_BUILD_IN) || list.find(x => !!x.defaultPlugin); + map((pluginFetch) => { + const defaultPlugin = pluginFetch.results.find(x => x.name === DEFAULT_BUILD_IN) || + pluginFetch.results.find(x => !!x.defaultPlugin); if (defaultPlugin) { // select first [real] plugin setTimeout(() => this.selectedPlugin.patchValue(defaultPlugin.name), 500); @@ -109,7 +82,7 @@ export class PluginEditorComponent implements OnInit, OnDestroy, AfterContentIni return [] .concat( - list + pluginFetch.results .map(it => ({ text: it.name, value: it.name })) .sort((a, b) => a.value > b.value ? 0 : 1) ); diff --git a/workbench/frontend/src/app/common/services/plugin.service.ts b/workbench/frontend/src/app/common/services/plugin.service.ts index 79398f4..81b49b7 100644 --- a/workbench/frontend/src/app/common/services/plugin.service.ts +++ b/workbench/frontend/src/app/common/services/plugin.service.ts @@ -7,13 +7,17 @@ import { CLIENT_IDENTIFIER } from '../contants'; import { AuthService, GlobalContext } from './auth.service'; export type PluginDto = { - id: string; + id: string, name: string; description: string; defaultPlugin: boolean; - pluginCode?: string; - scheduleConfigId?: string; - objective: PolicyObjectiveDto; + standardPlugin: boolean; + pluginCode: string; + scheduleConfigId: string; +}; + +export type PluginFetchResultDTO = { + results: PluginDto[] }; export type PolicyObjectiveDto = { @@ -70,9 +74,9 @@ export class PluginService { } - fetchAll(): Observable { + fetchAll(): Observable { return this.auth.globalContextWithAuth$.pipe( - mergeMap(ctx => this.http.get(`${this.config.getApiUri()}/plugin`, { headers: this.getHeaders(ctx) })), + mergeMap(ctx => this.http.get(`${this.config.getApiUri()}/plugin`, { headers: this.getHeaders(ctx) })), ); }