import '../viewparts/monitoring-summary.js' import '../viewparts/pending-q-monitor.js' import '../viewparts/scenarios-monitor.js' import '../viewparts/connections-monitor.js' import gql from 'graphql-tag' import { css, html } from 'lit' import { customElement, property, state } from 'lit/decorators.js' import { client, subscribe } from '@operato/graphql' import { i18next, localize } from '@operato/i18n' import { PageView, InheritedValueType } from '@operato/shell' import { ScrollbarStyles } from '@operato/styles' function IS_SCENARIO_RUNNING(state) { return state && state !== 'UNLOADED' } function toColor(string) { var hash = 0 if (string.length === 0) return hash for (var i = 0; i < string.length; i++) { hash = string.charCodeAt(i) + ((hash << 5) - hash) hash = hash & hash } var color = '#' for (var i = 0; i < 3; i++) { var value = (hash >> (i * 8)) & 255 color += ('00' + value.toString(16)).substr(-2) } return color } @customElement('integration-monitor') export class IntegrationMonitor extends localize(i18next)(PageView) { static ScenarioInstanceStatus = ['READY', 'STARTED', 'STOPPED', 'HALTED'] static styles = [ ScrollbarStyles, css` :host { display: flex; flex-direction: column; overflow: hidden; background-color: var(--md-sys-color-background); padding: var(--spacing-large); } integration-summary { margin-bottom: var(--spacing-large); } content { flex: 1; display: flex; flex-direction: row; overflow: hidden; } connections-monitor { width: 180px; } scenarios-monitor { flex: 1; margin: 0 var(--spacing-large) 0 0; } @media screen and (max-width: 480px) { :host { padding: var(--spacing-medium); } integration-summary { margin-bottom: var(--spacing-medium); } content { display: block; overflow: auto; } scenarios-monitor { min-height: 350px; margin: 0 0 var(--spacing-medium) 0; } connections-monitor { width: initial; } } ` ] @property({ type: Array }) scenarios: any @property({ type: Array }) pendings: any @property({ type: Array }) connections: any @property({ type: Object }) colorIndex: any scenarioInstanceStateSubscription: any scenarioQueueStateSubscription: any connectionStateSubscription: any get context() { return { title: i18next.t('text.integration monitor'), help: 'integration/ui/integration-monitor' } } render() { return html` ` } async pageUpdated(changes) { if ('active' in changes) { if (this.active) { await this.fetchScenarios() await this.fetchConnections() await this.startSubscribe() } else { await this.stopSubscribe() } } } async fetchScenarios() { const response = await client.query({ query: gql` query ($inherited: InheritedValueType) { responses: scenarios(inherited: $inherited) { items { id name description active state schedule timezone instances { instanceName scenarioName state progress { rate steps step rounds } variables data message } updater { id name } updatedAt domain { id name } } total } } `, variables: { inherited: InheritedValueType.Include } }) var colorIndex = {} this.scenarios = (response.data.responses.items || []).map(scenario => { var color = toColor(scenario.id) colorIndex[scenario.id] = color return { ...scenario, color } }) this.colorIndex = colorIndex } async fetchConnections() { const response = await client.query({ query: gql` query ($inherited: InheritedValueType) { responses: connections(inherited: $inherited) { items { id name description type state domain { id name } } total } } `, variables: { inherited: InheritedValueType.Include } }) this.connections = response.data.responses.items || [] // .map(connection => { // var color = toColor(scenario.id) // colorIndex[scenario.id] = color // return { // ...scenario, // color // } // }) // this.colorIndex = colorIndex } async startSubscribe() { if (this.scenarioInstanceStateSubscription) { return } this.scenarioInstanceStateSubscription = await subscribe( { query: gql` subscription { scenarioInstanceState { instanceName scenarioName state progress { rate steps step rounds } } } ` }, { next: async ({ data }) => { if (data) { var { scenarioName, instanceName, state } = data.scenarioInstanceState this.scenarios = this.scenarios || [] var scenario = this.scenarios.find(scenario => scenario.name === scenarioName) if (scenario) { var idx = scenario.instances.findIndex(instance => instance.instanceName === instanceName) if (idx == -1) { if (IS_SCENARIO_RUNNING(state)) { scenario.instances.push(data.scenarioInstanceState) } } else { if (!IS_SCENARIO_RUNNING(state)) { scenario.instances.splice(idx, 1) } else { scenario.instances.splice(idx, 1, data.scenarioInstanceState) } } } else { this.scenarios = [] await this.stopSubscribe() await this.fetchScenarios() await this.startSubscribe() return } /* change object intentionally to force to refresh scenario */ this.scenarios.splice(this.scenarios.indexOf(scenario), 1, { ...scenario }) this.scenarios = [...this.scenarios] } }, start: subscription => { console.log(subscription) }, error: error => { console.log(error) }, complete: () => { console.log('complete') } } ) this.scenarioQueueStateSubscription = await subscribe( { query: gql` subscription { scenarioQueueState { queue { stuff due priority tag } } } ` }, { next: ({ data }) => { if (data) { this.pendings = data.scenarioQueueState.queue } } } ) this.connectionStateSubscription = await subscribe( { query: gql` subscription { connectionState { id name description type state domain { id name } } } ` }, { next: async ({ data }) => { if (data) { var state = data.connectionState this.connections = this.connections || [] var idx = this.connections.findIndex( connection => connection.id === state.id && connection.domain.id === state.domain.id ) if (idx !== -1) { this.connections[idx] = data.connectionState this.connections = [...this.connections] } else { this.connections = [...this.connections, data.connectionState] } } } } ) } async stopSubscribe() { await this.scenarioInstanceStateSubscription?.unsubscribe() await this.scenarioQueueStateSubscription?.unsubscribe() await this.connectionStateSubscription?.unsubscribe() delete this.scenarioInstanceStateSubscription delete this.scenarioQueueStateSubscription delete this.connectionStateSubscription } }