Skip to content
This repository has been archived by the owner on Jan 28, 2022. It is now read-only.

Commit

Permalink
Added the discovery API call in
Browse files Browse the repository at this point in the history
  • Loading branch information
Shepless committed May 11, 2020
1 parent 0d75387 commit 5871e05
Show file tree
Hide file tree
Showing 10 changed files with 205 additions and 50 deletions.
7 changes: 6 additions & 1 deletion src/components/drop-down/styles.scss
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@
}

.selected-tick {
position: relative;
float: right;
width: 12px;
height: 12px;
Expand All @@ -88,7 +89,11 @@
line-height: 1.5;

&:after {
content: ''
content: '';
transform: translate(-50%, -50%);
top: 50%;
left: 50%;
position: absolute;
}
}
}
3 changes: 2 additions & 1 deletion src/pages/integrations/script.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ import AddIntegration from '../../components/sub-menus/add-integration/index.vue
subscriptions(this: IntegrationsPage) {
return {
integrations: this.store.integrations.configured$,
supportedIntegrations: this.store.integrations.supported$
supportedIntegrations: this.store.integrations.supported$,
discoveredIntegrations: this.store.integrations.discovered$
};
}
})
Expand Down
6 changes: 6 additions & 0 deletions src/pages/integrations/styles.scss
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,12 @@
height: 100%;
}

.configured, .discovered {
display: flex;
flex-direction: column;
height: 50%;
}

.title {
font-family: OpenSans;
}
Expand Down
80 changes: 52 additions & 28 deletions src/pages/integrations/template.html
Original file line number Diff line number Diff line change
@@ -1,30 +1,54 @@
<div class="integrations">
<h1 class="title">
{{$t('pages.integrations.configuredIntegrations')}}
</h1>
<yio-table ref="table" :items="integrations" max-height="525px" @onItemSelected="onItemSelected" @onItemsDeselected="onItemDeselected">
<template v-slot:header>
<th>
{{$t('common.name')}}
</th>
<th>
{{$t('common.type')}}
</th>
<th :style="{ width: '80px' }"></th>
</template>
<template v-slot:item="{ item }">
<td>
{{item.friendly_name}}
</td>
<td>
{{item.type}}
</td>
<td :style="{ width: '80px' }">
<action-icon-button @onClick="onItemDeleted(item)" type="delete"></action-icon-button>
</td>
</template>
</yio-table>
<h1 class="title">
{{$t('pages.integrations.discoveredIntegrations')}}
</h1>
<div class="configured">
<h1 class="title">
{{$t('pages.integrations.configuredIntegrations')}}
</h1>
<yio-table ref="table" :items="integrations" max-height="525px" @onItemSelected="onItemSelected" @onItemsDeselected="onItemDeselected">
<template v-slot:header>
<th>
{{$t('common.name')}}
</th>
<th>
{{$t('common.type')}}
</th>
<th :style="{ width: '80px' }"></th>
</template>
<template v-slot:item="{ item }">
<td>
{{item.friendly_name}}
</td>
<td>
{{item.type}}
</td>
<td :style="{ width: '80px' }">
<action-icon-button @onClick="onItemDeleted(item)" type="delete"></action-icon-button>
</td>
</template>
</yio-table>
</div>
<div class="discovered">
<h1 class="title">
{{$t('pages.integrations.discoveredIntegrations')}}
</h1>
<yio-table ref="table" :items="discoveredIntegrations" max-height="525px" @onItemSelected="onItemSelected" @onItemsDeselected="onItemDeselected">
<template v-slot:header>
<th>
{{$t('common.name')}}
</th>
<th>
{{$t('common.type')}}
</th>
<th :style="{ width: '80px' }"></th>
</template>
<template v-slot:item="{ item }">
<td>
{{item.friendly_name}}
</td>
<td>
{{item.type}}
</td>
<td :style="{ width: '80px' }"></td>
</template>
</yio-table>
</div>
</div>
92 changes: 75 additions & 17 deletions src/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { BehaviorSubject } from 'rxjs';
import { Guid } from 'guid-typescript';
import { Singleton, Inject } from './utilities/dependency-injection';
import { YioStore } from './store';
import { IConfigState, IKeyValuePair, IIntegrationInstance, IEntity, IServerResponse, IServerResponseWithData, IProfile, IPage, IGroup, IIntegrationSchema, IProfileAggregate, IPageAggregate, IEntityAggregate, IGroupAggregate, ILanguageSetting } from './types';
import { IConfigState, IKeyValuePair, IIntegrationInstance, IEntity, IServerResponse, IServerResponseWithData, IProfile, IPage, IGroup, IIntegrationSchema, IProfileAggregate, IPageAggregate, IEntityAggregate, IGroupAggregate, ILanguageSetting, IDiscoveredIntegration } from './types';
import Vue from 'vue';
import { Localisation } from './i18n';

Expand All @@ -22,14 +22,20 @@ export class ServerConnection {
private wsp: WebSocketAsPromised;
private configPollingRequestId: number;
private entitiesPollingRequestId: number;
private discoveryPollingRequestId: number;
private requestId: number;
private isDiscoveringIntegrations: boolean;
private hasInitialData: boolean;

constructor() {
this.host = window.location.hostname;
this.port = 946;
this.requestId = 0;
this.isDiscoveringIntegrations = false;
this.hasInitialData = false;
this.configPollingRequestId = 1316134911;
this.entitiesPollingRequestId = 1316134910;
this.discoveryPollingRequestId = 1316134909;
this.isConnected$ = new BehaviorSubject<boolean>(false);
this.wsp = new WebSocketAsPromised(`ws://${this.host}:${this.port}`, {
packMessage: (data) => JSON.stringify(data),
Expand All @@ -38,16 +44,17 @@ export class ServerConnection {
extractRequestId: (data) => data && data.id
});
this.wsp.onClose.addListener(() => {
this.hasInitialData = false;
this.isConnected$.next(false);
this.connect();
window.setTimeout(() => this.connect(), 3000);
});
this.wsp.onError.addListener(() => this.isConnected$.next(false));
this.wsp.onResponse.addListener((response) => {
this.isConnected$.next(true);

if (response.success && response.id === this.configPollingRequestId) {
this.store.dispatch(this.store.actions.updateConfig(response.config));
this.pollForData();
this.pollForConfig();
}
});
}
Expand All @@ -66,7 +73,10 @@ export class ServerConnection {
.then(() => this.getProfiles())
.then(() => this.getConfig(true))
.then(() => this.getAvailableEntities())
.then(() => this.pollForData());
.then(() => this.hasInitialData = true)
.then(() => this.pollForConfig())
.then(() => this.pollForEntities())
.then(() => this.pollForIntegrations());
}

public authenticate(token: string) {
Expand Down Expand Up @@ -116,10 +126,44 @@ export class ServerConnection {
return this.sendMessage<IEntity[]>({type: 'get_available_entities'})
.then((response) => response.available_entities)
.then((entities) => this.store.dispatch(this.store.actions.setAvailableEntities(entities)))
.then(() => this.pollForEntities())
.catch(() => ({}));
}

public getSupportedIntegrations(): Promise < void > {
public discoverIntegrations() {
if (this.isDiscoveringIntegrations) {
this.pollForIntegrations();
return Promise.resolve();
}

this.isDiscoveringIntegrations = true;

return new Promise<IDiscoveredIntegration[]>((resolve, reject) => {
const listener = (response: string) => {
const parsedResponse = JSON.parse(response) as IServerResponseWithData<IDiscoveredIntegration>;

if (parsedResponse.id === this.discoveryPollingRequestId) {
if (parsedResponse.message === 'discovery_done') {
this.wsp.onMessage.removeListener(listener);
resolve();
return;
}

if (parsedResponse.discovered_integration) {
this.store.dispatch(this.store.actions.addDiscoveredIntegration(parsedResponse.discovered_integration));
}
}
};

this.wsp.onMessage.addListener(listener);
this.wsp.sendRequest({type: 'discover_integrations'}, { requestId: this.discoveryPollingRequestId })
.catch((error) => reject(error));
})
.then(() => this.isDiscoveringIntegrations = false)
.then(() => this.pollForIntegrations());
}

public getSupportedIntegrations(): Promise<void> {
return this.sendMessage<string[]>({type: 'get_supported_integrations'})
.then((response) => response.supported_integrations)
.then((integrations: string[]) => {
Expand All @@ -135,7 +179,7 @@ export class ServerConnection {
.then((integrations) => this.store.dispatch(this.store.actions.setSupportedIntegrations(integrations)));
}

public getIntegrationSchema(integration: string): Promise < IIntegrationSchema > {
public getIntegrationSchema(integration: string): Promise<IIntegrationSchema> {
return this.sendMessage<IIntegrationSchema>({type: 'get_integration_setup_data', integration})
.then((response) => response.data);
}
Expand Down Expand Up @@ -507,6 +551,13 @@ export class ServerConnection {
.catch((response) => this.showToast(response));
}

// public checkForUpdate() {
// return this.sendMessage({ type: 'check_for_update' })
// .then((response) => this.showToast(response))
// .then(() => this.store.dispatch(this.store.actions.setLanguage(language)))
// .catch((response) => this.showToast(response));
// }

public reboot() {
return this.sendMessage({ type: 'reboot' })
.catch((response) => this.showToast(response));
Expand All @@ -517,21 +568,28 @@ export class ServerConnection {
this.requestId++;

return this.wsp.sendRequest(message, {requestId: this.requestId})
.then((response: IServerResponseWithData<T>) => {
if (!response.success) {
return Promise.reject(response);
}
.then((response: IServerResponseWithData<T>) => {
if (!response.success) {
return Promise.reject(response);
}

if (message.type !== 'get_config') {
this.getConfig(true);
}
return response;
});
if (message.type !== 'get_config' && this.hasInitialData) {
this.getConfig(true);
}
return response;
});
}

private pollForData() {
private pollForConfig() {
window.setTimeout(() => this.getConfig(), 3000);
window.setTimeout(() => this.getAvailableEntities(), 3000);
}

private pollForEntities() {
window.setTimeout(() => this.getAvailableEntities(), 5000);
}

private pollForIntegrations() {
window.setTimeout(() => this.discoverIntegrations(), 10000);
}

private showToast(response: IServerResponse) {
Expand Down
3 changes: 2 additions & 1 deletion src/store/actions.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { createStandardAction, ActionType } from 'typesafe-actions';
import { IKeyValuePair, IEntity, IConfigState, IIntegration, IIntegrationSchema, IProfile, IPage, IGroup, ILanguageSetting } from '../types';
import { IKeyValuePair, IEntity, IConfigState, IIntegration, IIntegrationSchema, IProfile, IPage, IGroup, ILanguageSetting, IDiscoveredIntegration } from '../types';

const actions = {
// Config
Expand All @@ -13,6 +13,7 @@ const actions = {
// Integrations
setConfiguredIntegrations: createStandardAction('store/integrations/set-configured')<IKeyValuePair<IIntegration>>(),
setSupportedIntegrations: createStandardAction('store/integrations/set-supported')<IKeyValuePair<IIntegrationSchema>>(),
addDiscoveredIntegration: createStandardAction('store/integrations/add-discovered')<IDiscoveredIntegration>(),

// Profiles
setProfiles: createStandardAction('store/profiles/set-all')<IKeyValuePair<IProfile>>(),
Expand Down
4 changes: 3 additions & 1 deletion src/store/aggregates/integrations.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
import { YioStore } from '..';
import { IIntegrationInstance, IKeyValuePair } from '../../types';
import { IIntegrationInstance, IKeyValuePair, IDiscoveredIntegration } from '../../types';

export class IntegrationsAggregate {
public configured$: Observable<IIntegrationInstance[]>;
public supported$: Observable<IKeyValuePair<object>>;
public discovered$: Observable<IDiscoveredIntegration[]>;
private store: YioStore;

constructor(store: YioStore) {
Expand All @@ -30,5 +31,6 @@ export class IntegrationsAggregate {
);

this.supported$ = this.store.select('integrations', 'supported');
this.discovered$ = this.store.select('integrations', 'discovered');
}
}
3 changes: 2 additions & 1 deletion src/store/integrations/initial-state.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ import { IIntegrationsState } from '../../types';

const initialState: IIntegrationsState = {
configured: {},
supported: {}
supported: {},
discovered: []
};

export default initialState;
7 changes: 7 additions & 0 deletions src/store/integrations/reducer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,13 @@ export default function reducer(state: IIntegrationsState = initialState, action
configured: action.payload.integrations
}
};
case getType(actions.addDiscoveredIntegration):
const alreadyAdded = !!state.discovered.find((existing) => JSON.stringify(existing) === JSON.stringify(action.payload));

return {
...state,
discovered: [...state.discovered, ...(alreadyAdded ? [] : [action.payload])]
};
case getType(actions.setSupportedIntegrations):
return {
...state,
Expand Down
Loading

0 comments on commit 5871e05

Please sign in to comment.