diff --git a/openapi-specs/component-catalog-v1.0.0.yaml b/openapi-specs/component-catalog-v1.0.0.yaml index cd5ddb8..351f28b 100644 --- a/openapi-specs/component-catalog-v1.0.0.yaml +++ b/openapi-specs/component-catalog-v1.0.0.yaml @@ -35,6 +35,56 @@ tags: - name: ProvisionerActions description: Provisioning notifications from AWX/Provisioner paths: + /project/components: + get: + operationId: getAllProjectComponents + parameters: + - name: page + in: query + description: Page number (from 0 until limit) + required: false + schema: + type: integer + default: 0 + + - name: size + in: query + description: Page size + required: false + schema: + type: integer + default: 20 + responses: + "200": + content: + application/json: + schema: + $ref: "#/components/schemas/ProjectComponentsMetrics" + description: A paginated list of all the provisioned project components + "401": + content: + application/json: + schema: + $ref: "#/components/schemas/RestErrorMessage" + description: Invalid client token on the request. + "403": + content: + application/json: + schema: + $ref: "#/components/schemas/RestErrorMessage" + description: Insufficient permissions for the client to access the resource. + "500": + content: + application/json: + schema: + $ref: "#/components/schemas/RestErrorMessage" + description: Server error. + summary: Returns the information of the project's components in the Bitbucket + repository. + tags: + - Project-components + x-accepts: + - application/json /project/{projectKey}/components: get: tags: @@ -279,7 +329,7 @@ paths: - name: catalogId in: query description: id for the Catalog. - required: true + required: false schema: type: string - name: sortByTitle @@ -996,6 +1046,11 @@ components: type: string format: date-time example: '2021-07-01T00:00:00Z' + updatedAt: + type: integer + format: int64 + example: 1625097600000 + description: Timestamp in milliseconds since Unix epoch userActions: type: array items: @@ -1350,3 +1405,111 @@ components: example: - "production" - "staging" + + ProjectComponentMetrics: + type: object + example: + projectKey: SOMEPROJECT + componentId: any-component-id-from-backend + caller: some-person@example.com + catalogItemSlug: some_technology-name + createdAt: 1707043200000 + updatedAt: 1707043200000 + properties: + projectKey: + description: The projectKey which the component is provisioned for. + example: SOMEPROJECT + type: string + componentId: + description: The componentId set by the user. + example: any-component-id-from-backend + minLength: 1 + pattern: ^(?!\s*$).+ + type: string + caller: + description: The email of who provisioned the component. + example: some-person@example.com + type: string + catalogItemSlug: + description: The provisioned catalog item slug. + example: some_technology-name + type: string + createdAt: + description: The timestamp of the provision action. + example: 1707043200000 + type: number + updatedAt: + description: The timestamp of the last change of the provisioned component. + example: 1707043200000 + type: number + + Pagination: + type: object + example: + page: 0 + size: 20 + totalElements: 117 + totalPages: 6 + next: "https://api.example.com/resources?page=1&size=20" + previous: null + properties: + page: + type: integer + example: 0 + description: Current page of the response. + size: + type: integer + example: 20 + description: Current page size of the response. + totalElements: + type: integer + format: integer + example: 117 + description: Total number of elements. + totalPages: + type: integer + example: 6 + description: Total number of pages of this exact size. + next: + type: string + format: uri + nullable: true + example: "https://api.example.com/resources?page=1&size=20" + description: URL of the next page (or null if the current is the last one) + previous: + type: string + format: uri + nullable: true + example: "https://api.example.com/resources?page=0&size=20" + description: URL of the previous page (or null if the current is the first one) + + ProjectComponentsMetrics: + type: object + example: + data: + - projectKey: SOMEPROJECT + componentId: any-component-id-from-backend + caller: some-person@example.com + catalogItemSlug: some_technology-name + createdAt: 1707043200000 + updatedAt: 1707043200000 + - projectKey: ANOTHERPROJECT + componentId: another-component-id-from-backend + caller: some-person2@example.com + catalogItemSlug: another_technology-name + createdAt: 1707043200001 + updatedAt: 1707043200002 + pagination: + page: 0 + size: 20 + totalElements: 117 + totalPages: 6 + next: https://api.example.com/resources?page=1&size=20 + previous: null + properties: + data: + type: array + items: + $ref: '#/components/schemas/ProjectComponentMetrics' + pagination: + $ref: '#/components/schemas/Pagination' \ No newline at end of file diff --git a/openapi-specs/component-provisioner-v1.0.0.yaml b/openapi-specs/component-provisioner-v1.0.0.yaml index 2d22b76..3939346 100644 --- a/openapi-specs/component-provisioner-v1.0.0.yaml +++ b/openapi-specs/component-provisioner-v1.0.0.yaml @@ -13,7 +13,7 @@ info: url: https://confluence.biscrum.com/pages/viewpage.action?spaceKey=EDP&title=Welcome servers: - url: http://{baseurl}/v1 - variables: + variables: baseurl: default: localhost:8080 description: Default address for a Component Provisioner's backend REST API instance. @@ -336,6 +336,57 @@ paths: application/json: schema: $ref: '#/components/schemas/RestErrorMessage' + + /project/components: + get: + operationId: getAllProjectComponents + parameters: + - name: page + in: query + description: Page number (from 0 until limit) + required: false + schema: + type: integer + default: 0 + + - name: size + in: query + description: Page size + required: false + schema: + type: integer + default: 20 + responses: + "200": + content: + application/json: + schema: + $ref: "#/components/schemas/ProjectComponentsMetrics" + description: A paginated list of all the provisioned project components + "401": + content: + application/json: + schema: + $ref: "#/components/schemas/RestErrorMessage" + description: Invalid client token on the request. + "403": + content: + application/json: + schema: + $ref: "#/components/schemas/RestErrorMessage" + description: Insufficient permissions for the client to access the resource. + "500": + content: + application/json: + schema: + $ref: "#/components/schemas/RestErrorMessage" + description: Server error. + summary: Returns the information of the project's components in the Bitbucket + repository. + tags: + - Project-components-with-provision-status + x-accepts: + - application/json components: securitySchemes: bearerAuth: @@ -582,4 +633,109 @@ components: parameters: type: array items: - $ref: '#/components/schemas/ProjectComponentStatusParameter' \ No newline at end of file + $ref: '#/components/schemas/ProjectComponentStatusParameter' + ProjectComponentMetrics: + type: object + example: + projectKey: SOMEPROJECT + componentId: any-component-id-from-backend + caller: some-person@email.com + catalogItemSlug: some_technology-name + createdAt: 1707043200000 + updatedAt: 1707043200000 + properties: + projectKey: + description: The projectKey which the component is provisioned for. + example: SOMEPROJECT + type: string + componentId: + description: The componentId set by the user. + example: any-component-id-from-backend + minLength: 1 + pattern: ^(?!\s*$).+ + type: string + caller: + description: The email of who provisioned the component. + example: some-person@email.com + type: string + catalogItemSlug: + description: The provisioned catalog item slug. + example: some_technology-name + type: string + createdAt: + description: The timestamp of the provision action. + example: 1707043200000 + type: number + updatedAt: + description: The timestamp of the last change of the provisioned component. + example: 1707043200000 + type: number + Pagination: + type: object + example: + page: 0 + size: 20 + totalElements: 117 + totalPages: 6 + next: "https://api.example.com/resources?page=1&size=20" + previous: null + properties: + page: + type: integer + example: 0 + description: Current page of the response. + size: + type: integer + example: 20 + description: Current page size of the response. + totalElements: + type: integer + format: integer + example: 117 + description: Total number of elements. + totalPages: + type: integer + example: 6 + description: Total number of pages of this exact size. + next: + type: string + format: uri + nullable: true + example: "https://api.example.com/resources?page=1&size=20" + description: URL of the next page (or null if the current is the last one) + previous: + type: string + format: uri + nullable: true + example: "https://api.example.com/resources?page=0&size=20" + description: URL of the previous page (or null if the current is the first one) + ProjectComponentsMetrics: + type: object + example: + data: + - projectKey: SOMEPROJECT + componentId: any-component-id-from-backend + caller: some-person@email.com + catalogItemSlug: some_technology-name + createdAt: 1707043200000 + updatedAt: 1707043200000 + - projectKey: ANOTHERPROJECT + componentId: another-component-id-from-backend + caller: some-person2@email.com + catalogItemSlug: another_technology-name + createdAt: 1707043200001 + updatedAt: 1707043200002 + pagination: + page: 0 + size: 20 + totalElements: 117 + totalPages: 6 + next: https://api.example.com/resources?page=1&size=20 + previous: null + properties: + data: + type: array + items: + $ref: '#/components/schemas/ProjectComponentMetrics' + pagination: + $ref: '#/components/schemas/Pagination' \ No newline at end of file diff --git a/public/config/config.json b/public/config/config.json index 8d51ab9..382f75f 100644 --- a/public/config/config.json +++ b/public/config/config.json @@ -12,5 +12,13 @@ "natsUrl": "YOUR_NATS_SERVER_URL", "natsUser": "YOUR_NATS_USERNAME", "natsPassword": "YOUR_NATS_PASSWORD", - "platformSelectorServiceUrl": "YOUR_PLATFORM_SELECTOR_SERVICE_URL/api/v1/projects/${project}/platforms" + "platformSelectorServiceUrl": "YOUR_PLATFORM_SELECTOR_SERVICE_URL/api/v1/projects/${project}/platforms", + "chatbotConfig": { + "widgetConfig": { + "baseUrl": "YOUR_CHATBOT_PLATFORM_BASE_URL", + "embedToken": "YOUR_CHATBOT_TOKEN", + "theme": "light" + }, + "scriptSrc": "YOUR_CHATBOT_SCRIPT_SOURCE" + } } diff --git a/src/app/app.component.spec.ts b/src/app/app.component.spec.ts index aae626b..a5764c8 100644 --- a/src/app/app.component.spec.ts +++ b/src/app/app.component.spec.ts @@ -77,7 +77,7 @@ describe('AppComponent', () => { mockCatalogService.getCatalog.and.returnValue(of({ slug: 'test-catalog', id: '1', links: [] } as Catalog)); mockCatalogService.getSelectedCatalogSlug.and.returnValue(null); mockCatalogService.getSelectedCatalogDescriptor.and.returnValue({ slug: 'test-catalog', id: '1' }); - mockAppConfigService.getConfig.and.returnValue({ natsUrl: 'nats://localhost:4222' }); + mockAppConfigService.getConfig.and.returnValue({ natsUrl: 'nats://localhost:4222', chatbotConfig: { widgetConfig: { baseUrl: 'https://example.com', theme: 'light' }, scriptSrc: 'https://example.com/chat-widget.js' } }); mockAzureService.getAccessToken.and.returnValue(Promise.resolve('new-token')); mockProjectService.getUserProjects.and.returnValue(of([])); mockDialogRef.afterClosed.and.returnValue(dialogSubject.asObservable()); diff --git a/src/app/app.component.ts b/src/app/app.component.ts index e3bee97..6c95639 100644 --- a/src/app/app.component.ts +++ b/src/app/app.component.ts @@ -69,6 +69,8 @@ export class AppComponent implements OnInit, OnDestroy { private readonly _destroying$ = new Subject(); + private _script?: HTMLScriptElement; + constructor( private readonly catalogService: CatalogService, private readonly router: Router, @@ -168,6 +170,14 @@ export class AppComponent implements OnInit, OnDestroy { }); } }); + + const chatbotConfig = this.appConfigService.getConfig()?.chatbotConfig; + (window as Window & { ONB_CHAT_CONFIG?: object }).ONB_CHAT_CONFIG = chatbotConfig.widgetConfig; + + this._script = document.createElement('script'); + this._script.src = chatbotConfig.scriptSrc; + document.body.appendChild(this._script); + } async initializeNats(user: AppUser | null) { @@ -266,6 +276,7 @@ export class AppComponent implements OnInit, OnDestroy { this._destroying$.complete(); this.liveMessageSubscription?.unsubscribe(); this.unreadMessagesCountSubscription?.unsubscribe(); + this._script?.remove(); } private listenForProjectInUrl(): void { diff --git a/src/app/services/catalog.service.ts b/src/app/services/catalog.service.ts index f3f0bd1..33db845 100644 --- a/src/app/services/catalog.service.ts +++ b/src/app/services/catalog.service.ts @@ -96,7 +96,7 @@ export class CatalogService { } getProductsList(catalogDescriptor: CatalogDescriptor): Observable { - return this.catalogItemsService.getCatalogItems(catalogDescriptor.id!, 'asc').pipe( + return this.catalogItemsService.getCatalogItems('asc', catalogDescriptor.id!).pipe( switchMap(items => this.mapItemsToProductListItems(items, catalogDescriptor.slug!)) ); }