mirror of
https://github.com/turt2live/matrix-dimension.git
synced 2024-08-31 06:02:09 +00:00
Re-wire the UI to support the new backend
This still doesn't allow editing, but it supports showing the widgets at least.
This commit is contained in:
parent
599fb80112
commit
4965b61f2d
@ -1,4 +1,4 @@
|
||||
import { GET, Path, QueryParam } from "typescript-rest";
|
||||
import { GET, Path, PathParam, QueryParam } from "typescript-rest";
|
||||
import * as Promise from "bluebird";
|
||||
import { ScalarService } from "../scalar/ScalarService";
|
||||
import { DimensionStore } from "../../db/DimensionStore";
|
||||
@ -35,6 +35,13 @@ export class DimensionIntegrationsService {
|
||||
});
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("room/:roomId")
|
||||
public getIntegrationsInRoom(@QueryParam("scalar_token") scalarToken: string, @PathParam("roomId") roomId: string) :Promise<IntegrationsResponse>{
|
||||
console.log(roomId);
|
||||
return this.getEnabledIntegrations(scalarToken);
|
||||
}
|
||||
|
||||
private getIntegrations(isEnabledCheck?: boolean): Promise<IntegrationsResponse> {
|
||||
const cachedResponse = DimensionIntegrationsService.integrationCache.get("integrations_" + isEnabledCheck);
|
||||
if (cachedResponse) {
|
||||
|
@ -12,6 +12,7 @@ export default {
|
||||
"avatarUrl": {type: DataType.STRING, allowNull: false},
|
||||
"description": {type: DataType.STRING, allowNull: false},
|
||||
"isEnabled": {type: DataType.BOOLEAN, allowNull: false},
|
||||
"isPublic": {type: DataType.BOOLEAN, allowNull: false},
|
||||
"optionsJson": {type: DataType.STRING, allowNull: true},
|
||||
}))
|
||||
.then(() => queryInterface.bulkInsert("dimension_widgets", [
|
||||
@ -64,6 +65,15 @@ export default {
|
||||
avatarUrl: "/img/avatars/twitch.png",
|
||||
description: "Embed a Twitch livestream into your room.",
|
||||
},
|
||||
{
|
||||
type: "jitsi",
|
||||
name: "Jitsi Conference",
|
||||
isEnabled: true,
|
||||
isPublic: true,
|
||||
avatarUrl: "/img/avatars/jitsi.png",
|
||||
description: "Hold a video conference with Jitsi Meet",
|
||||
optionsJson: '{"jitsiDomain":"jitsi.riot.im", "scriptUrl":"https://jitsi.riot.im/libs/external_api.min.js"}',
|
||||
},
|
||||
]));
|
||||
},
|
||||
down: (queryInterface: QueryInterface) => {
|
||||
|
@ -5,6 +5,7 @@ export class Integration {
|
||||
public category: "bot" | "complex-bot" | "bridge" | "widget";
|
||||
public type: string;
|
||||
public requirements: IntegrationRequirement[];
|
||||
public isEncryptionSupported = false;
|
||||
|
||||
// These are meant to be set by us
|
||||
public displayName: string;
|
||||
@ -26,5 +27,9 @@ export class Integration {
|
||||
export interface IntegrationRequirement {
|
||||
condition: "publicRoom" | "canSendEventTypes";
|
||||
argument: any;
|
||||
|
||||
// For publicRoom this is true or false (boolean)
|
||||
// For canSendEventTypes this is an array of {isState: boolean, type: string}
|
||||
// For userInRoom this is the user ID
|
||||
expectedValue: any;
|
||||
}
|
@ -5,6 +5,11 @@ export interface EtherpadWidgetOptions {
|
||||
defaultUrl: string;
|
||||
}
|
||||
|
||||
export interface JitsiWidgetOptions {
|
||||
jitsiDomain: string;
|
||||
scriptUrl: string;
|
||||
}
|
||||
|
||||
export class Widget extends Integration {
|
||||
public options: any;
|
||||
|
||||
@ -14,8 +19,11 @@ export class Widget extends Integration {
|
||||
this.options = widgetRecord.optionsJson ? JSON.parse(widgetRecord.optionsJson) : {};
|
||||
this.requirements = [{
|
||||
condition: "canSendEventTypes",
|
||||
argument: ["im.vector.widget"],
|
||||
argument: [{isState: true, type: "im.vector.widget"}],
|
||||
expectedValue: true,
|
||||
}];
|
||||
|
||||
// Technically widgets are supported in encrypted rooms, although at risk.
|
||||
this.isEncryptionSupported = true;
|
||||
}
|
||||
}
|
@ -14,6 +14,8 @@ export class MatrixOpenIdClient {
|
||||
"/_matrix/federation/v1/openid/userinfo",
|
||||
{access_token: this.openId.access_token}
|
||||
).then(response => {
|
||||
// Annoyingly, the response isn't JSON for this
|
||||
response = JSON.parse(response);
|
||||
return response['sub'];
|
||||
});
|
||||
}
|
||||
|
@ -8,16 +8,14 @@ import { routing } from "./app.routing";
|
||||
import { createNewHosts, removeNgStyles } from "@angularclass/hmr";
|
||||
import { NgbModule } from "@ng-bootstrap/ng-bootstrap";
|
||||
import { RiotComponent } from "./riot/riot.component";
|
||||
import { ApiService } from "./shared/services/api.service";
|
||||
import { UiSwitchModule } from "angular2-ui-switch";
|
||||
import { ScalarService } from "./shared/services/scalar.service";
|
||||
import { ScalarClientApiService } from "./shared/services/scalar-client-api.service";
|
||||
import { ToasterModule } from "angular2-toaster";
|
||||
import { BrowserAnimationsModule } from "@angular/platform-browser/animations";
|
||||
import { ScalarCloseComponent } from "./riot/scalar-close/scalar-close.component";
|
||||
import { IntegrationService } from "./shared/services/integration.service";
|
||||
import { LegacyIntegrationService } from "./shared/services/legacy/integration.service";
|
||||
import { BootstrapModalModule } from "ngx-modialog/plugins/bootstrap";
|
||||
import { ModalModule } from "ngx-modialog";
|
||||
import { IrcApiService } from "./shared/services/irc-api.service";
|
||||
import { GenericWidgetWrapperComponent } from "./widget_wrappers/generic/generic.component";
|
||||
import { ToggleFullscreenDirective } from "./shared/directives/toggle-fullscreen.directive";
|
||||
import { FullscreenButtonComponent } from "./fullscreen-button/fullscreen-button.component";
|
||||
@ -30,8 +28,11 @@ import { BreadcrumbsModule } from "ng2-breadcrumbs";
|
||||
import { RiotHomeComponent } from "./riot/riot-home/home.component";
|
||||
import { IntegrationBagComponent } from "./integration-bag/integration-bag.component";
|
||||
import { IntegrationComponent } from "./integration/integration.component";
|
||||
import { ScalarServerApiService } from "./shared/services/scalar-server-api.service";
|
||||
import { DimensionApiService } from "./shared/services/dimension-api.service";
|
||||
import { AdminApiService } from "./shared/services/admin-api.service";
|
||||
|
||||
const WIDGET_CONFIGURATION_COMPONENTS: any[] = IntegrationService.getAllConfigComponents();
|
||||
const WIDGET_CONFIGURATION_COMPONENTS: any[] = LegacyIntegrationService.getAllConfigComponents();
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
@ -68,10 +69,10 @@ const WIDGET_CONFIGURATION_COMPONENTS: any[] = IntegrationService.getAllConfigCo
|
||||
// Vendor
|
||||
],
|
||||
providers: [
|
||||
ApiService,
|
||||
ScalarService,
|
||||
IntegrationService,
|
||||
IrcApiService,
|
||||
ScalarClientApiService,
|
||||
ScalarServerApiService,
|
||||
DimensionApiService,
|
||||
AdminApiService,
|
||||
{provide: Window, useValue: window},
|
||||
|
||||
// Vendor
|
||||
|
@ -1,9 +1,9 @@
|
||||
import { Component } from "@angular/core";
|
||||
import { CircleCiIntegration } from "../../shared/models/integration";
|
||||
import { CircleCiIntegration } from "../../shared/models/legacyintegration";
|
||||
import { ModalComponent, DialogRef } from "ngx-modialog";
|
||||
import { ConfigModalContext } from "../../integration/integration.component";
|
||||
import { ToasterService } from "angular2-toaster";
|
||||
import { ApiService } from "../../shared/services/api.service";
|
||||
import { ApiService } from "../../shared/services/legacy/api.service";
|
||||
|
||||
@Component({
|
||||
selector: "my-circleci-config",
|
||||
|
@ -1,11 +1,11 @@
|
||||
import { Component, OnDestroy } from "@angular/core";
|
||||
import { IRCIntegration } from "../../shared/models/integration";
|
||||
import { IRCIntegration } from "../../shared/models/legacyintegration";
|
||||
import { ModalComponent, DialogRef } from "ngx-modialog";
|
||||
import { ConfigModalContext } from "../../integration/integration.component";
|
||||
import { IrcApiService } from "../../shared/services/irc-api.service";
|
||||
import { IrcApiService } from "../../shared/services/legacy/irc-api.service";
|
||||
import { ToasterService } from "angular2-toaster";
|
||||
import { IntervalObservable } from "rxjs/observable/IntervalObservable";
|
||||
import { ApiService } from "../../shared/services/api.service";
|
||||
import { ApiService } from "../../shared/services/legacy/api.service";
|
||||
import { Subscription } from "rxjs";
|
||||
|
||||
@Component({
|
||||
|
@ -1,9 +1,9 @@
|
||||
import { Component } from "@angular/core";
|
||||
import { RSSIntegration } from "../../shared/models/integration";
|
||||
import { RSSIntegration } from "../../shared/models/legacyintegration";
|
||||
import { ModalComponent, DialogRef } from "ngx-modialog";
|
||||
import { ConfigModalContext } from "../../integration/integration.component";
|
||||
import { ToasterService } from "angular2-toaster";
|
||||
import { ApiService } from "../../shared/services/api.service";
|
||||
import { ApiService } from "../../shared/services/legacy/api.service";
|
||||
|
||||
@Component({
|
||||
selector: "my-rss-config",
|
||||
|
@ -1,9 +1,9 @@
|
||||
import { Component } from "@angular/core";
|
||||
import { TravisCiIntegration } from "../../shared/models/integration";
|
||||
import { TravisCiIntegration } from "../../shared/models/legacyintegration";
|
||||
import { ModalComponent, DialogRef } from "ngx-modialog";
|
||||
import { ConfigModalContext } from "../../integration/integration.component";
|
||||
import { ToasterService } from "angular2-toaster";
|
||||
import { ApiService } from "../../shared/services/api.service";
|
||||
import { ApiService } from "../../shared/services/legacy/api.service";
|
||||
|
||||
@Component({
|
||||
selector: "my-travisci-config",
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { Component } from "@angular/core";
|
||||
import { DialogRef, ModalComponent } from "ngx-modialog";
|
||||
import { WidgetComponent } from "../widget.component";
|
||||
import { ScalarService } from "../../../shared/services/scalar.service";
|
||||
import { ScalarClientApiService } from "../../../shared/services/scalar-client-api.service";
|
||||
import { ConfigModalContext } from "../../../integration/integration.component";
|
||||
import { ToasterService } from "angular2-toaster";
|
||||
import { WIDGET_CUSTOM } from "../../../shared/models/widget";
|
||||
@ -15,7 +15,7 @@ export class CustomWidgetConfigComponent extends WidgetComponent implements Moda
|
||||
|
||||
constructor(public dialog: DialogRef<ConfigModalContext>,
|
||||
toaster: ToasterService,
|
||||
scalarService: ScalarService,
|
||||
scalarService: ScalarClientApiService,
|
||||
window: Window) {
|
||||
super(
|
||||
window,
|
||||
|
@ -1,11 +1,11 @@
|
||||
import { Component } from "@angular/core";
|
||||
import { DialogRef, ModalComponent } from "ngx-modialog";
|
||||
import { WidgetComponent } from "../widget.component";
|
||||
import { ScalarService } from "../../../shared/services/scalar.service";
|
||||
import { ScalarClientApiService } from "../../../shared/services/scalar-client-api.service";
|
||||
import { ConfigModalContext } from "../../../integration/integration.component";
|
||||
import { ToasterService } from "angular2-toaster";
|
||||
import { WIDGET_ETHERPAD } from "../../../shared/models/widget";
|
||||
import { EtherpadWidgetIntegration } from "../../../shared/models/integration";
|
||||
import { EtherpadWidgetIntegration } from "../../../shared/models/legacyintegration";
|
||||
|
||||
@Component({
|
||||
selector: "my-etherpadwidget-config",
|
||||
@ -18,7 +18,7 @@ export class EtherpadWidgetConfigComponent extends WidgetComponent implements Mo
|
||||
|
||||
constructor(public dialog: DialogRef<ConfigModalContext>,
|
||||
toaster: ToasterService,
|
||||
scalarService: ScalarService,
|
||||
scalarService: ScalarClientApiService,
|
||||
window: Window) {
|
||||
super(
|
||||
window,
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { Component } from "@angular/core";
|
||||
import { DialogRef, ModalComponent } from "ngx-modialog";
|
||||
import { WidgetComponent } from "../widget.component";
|
||||
import { ScalarService } from "../../../shared/services/scalar.service";
|
||||
import { ScalarClientApiService } from "../../../shared/services/scalar-client-api.service";
|
||||
import { ConfigModalContext } from "../../../integration/integration.component";
|
||||
import { ToasterService } from "angular2-toaster";
|
||||
import { EditableWidget, WIDGET_GOOGLE_CALENDAR } from "../../../shared/models/widget";
|
||||
@ -15,7 +15,7 @@ export class GoogleCalendarWidgetConfigComponent extends WidgetComponent impleme
|
||||
|
||||
constructor(public dialog: DialogRef<ConfigModalContext>,
|
||||
toaster: ToasterService,
|
||||
scalarService: ScalarService,
|
||||
scalarService: ScalarClientApiService,
|
||||
window: Window) {
|
||||
super(
|
||||
window,
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { Component } from "@angular/core";
|
||||
import { DialogRef, ModalComponent } from "ngx-modialog";
|
||||
import { WidgetComponent } from "../widget.component";
|
||||
import { ScalarService } from "../../../shared/services/scalar.service";
|
||||
import { ScalarClientApiService } from "../../../shared/services/scalar-client-api.service";
|
||||
import { ConfigModalContext } from "../../../integration/integration.component";
|
||||
import { ToasterService } from "angular2-toaster";
|
||||
import { WIDGET_GOOGLE_DOCS } from "../../../shared/models/widget";
|
||||
@ -15,7 +15,7 @@ export class GoogleDocsWidgetConfigComponent extends WidgetComponent implements
|
||||
|
||||
constructor(public dialog: DialogRef<ConfigModalContext>,
|
||||
toaster: ToasterService,
|
||||
scalarService: ScalarService,
|
||||
scalarService: ScalarClientApiService,
|
||||
window: Window) {
|
||||
super(
|
||||
window,
|
||||
|
@ -1,11 +1,11 @@
|
||||
import { Component } from "@angular/core";
|
||||
import { DialogRef, ModalComponent } from "ngx-modialog";
|
||||
import { WidgetComponent } from "../widget.component";
|
||||
import { ScalarService } from "../../../shared/services/scalar.service";
|
||||
import { ScalarClientApiService } from "../../../shared/services/scalar-client-api.service";
|
||||
import { ConfigModalContext } from "../../../integration/integration.component";
|
||||
import { ToasterService } from "angular2-toaster";
|
||||
import { EditableWidget, WIDGET_JITSI } from "../../../shared/models/widget";
|
||||
import { JitsiWidgetIntegration } from "../../../shared/models/integration";
|
||||
import { JitsiWidgetIntegration } from "../../../shared/models/legacyintegration";
|
||||
import * as gobyInit from "goby";
|
||||
import * as url from "url";
|
||||
|
||||
@ -26,7 +26,7 @@ export class JitsiWidgetConfigComponent extends WidgetComponent implements Modal
|
||||
|
||||
constructor(public dialog: DialogRef<ConfigModalContext>,
|
||||
toaster: ToasterService,
|
||||
scalarService: ScalarService,
|
||||
scalarService: ScalarClientApiService,
|
||||
window: Window) {
|
||||
super(
|
||||
window,
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { Component } from "@angular/core";
|
||||
import { DialogRef, ModalComponent } from "ngx-modialog";
|
||||
import { WidgetComponent } from "../widget.component";
|
||||
import { ScalarService } from "../../../shared/services/scalar.service";
|
||||
import { ScalarClientApiService } from "../../../shared/services/scalar-client-api.service";
|
||||
import { ConfigModalContext } from "../../../integration/integration.component";
|
||||
import { ToasterService } from "angular2-toaster";
|
||||
import { EditableWidget, WIDGET_TWITCH } from "../../../shared/models/widget";
|
||||
@ -15,7 +15,7 @@ export class TwitchWidgetConfigComponent extends WidgetComponent implements Moda
|
||||
|
||||
constructor(public dialog: DialogRef<ConfigModalContext>,
|
||||
toaster: ToasterService,
|
||||
scalarService: ScalarService,
|
||||
scalarService: ScalarClientApiService,
|
||||
window: Window) {
|
||||
super(
|
||||
window,
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { ScalarService } from "../../shared/services/scalar.service";
|
||||
import { ScalarClientApiService } from "../../shared/services/scalar-client-api.service";
|
||||
import { convertScalarWidgetsToDtos, EditableWidget } from "../../shared/models/widget";
|
||||
import { ToasterService } from "angular2-toaster";
|
||||
import { Integration } from "../../shared/models/integration";
|
||||
import { LegacyIntegration } from "../../shared/models/legacyintegration";
|
||||
|
||||
const SCALAR_WIDGET_LINKS = [
|
||||
"https://scalar-staging.riot.im/scalar/api/widgets/__TYPE__.html?url=",
|
||||
@ -23,9 +23,9 @@ export class WidgetComponent {
|
||||
|
||||
constructor(window: Window,
|
||||
protected toaster: ToasterService,
|
||||
protected scalarApi: ScalarService,
|
||||
protected scalarApi: ScalarClientApiService,
|
||||
public roomId: string,
|
||||
public integration: Integration,
|
||||
public integration: LegacyIntegration,
|
||||
editWidgetId: string,
|
||||
private widgetIds: string[],
|
||||
private defaultName: string,
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { Component } from "@angular/core";
|
||||
import { DialogRef, ModalComponent } from "ngx-modialog";
|
||||
import { WidgetComponent } from "../widget.component";
|
||||
import { ScalarService } from "../../../shared/services/scalar.service";
|
||||
import { ScalarClientApiService } from "../../../shared/services/scalar-client-api.service";
|
||||
import { ConfigModalContext } from "../../../integration/integration.component";
|
||||
import { ToasterService } from "angular2-toaster";
|
||||
import { EditableWidget, WIDGET_YOUTUBE } from "../../../shared/models/widget";
|
||||
@ -17,7 +17,7 @@ export class YoutubeWidgetConfigComponent extends WidgetComponent implements Mod
|
||||
|
||||
constructor(public dialog: DialogRef<ConfigModalContext>,
|
||||
toaster: ToasterService,
|
||||
scalarService: ScalarService,
|
||||
scalarService: ScalarClientApiService,
|
||||
window: Window) {
|
||||
super(
|
||||
window,
|
||||
|
@ -1,10 +1,8 @@
|
||||
<div class="integration-bag">
|
||||
<!--<my-integration *ngFor="let integration of integrations"-->
|
||||
<!--[integration]="integration" (selected)="onClick(integration)"></my-integration>-->
|
||||
<div class="integration" *ngFor="let integration of integrations">
|
||||
<img class="integration-avatar" [src]="getSafeUrl(integration.avatar)"/>
|
||||
<div class="integration-name">{{ integration.name }}</div>
|
||||
<div class="integration-description">{{ integration.about }}</div>
|
||||
<img class="integration-avatar" [src]="getSafeUrl(integration.avatarUrl)"/>
|
||||
<div class="integration-name">{{ integration.displayName }}</div>
|
||||
<div class="integration-description">{{ integration.description }}</div>
|
||||
<div class="integration-arrow"><i class="fa fa-chevron-right"></i></div>
|
||||
</div>
|
||||
</div>
|
@ -1,6 +1,7 @@
|
||||
import { Component, EventEmitter, Input, Output } from "@angular/core";
|
||||
import { Integration } from "../shared/models/integration";
|
||||
import { LegacyIntegration } from "../shared/models/legacyintegration";
|
||||
import { DomSanitizer, SafeResourceUrl } from "@angular/platform-browser";
|
||||
import { Integration } from "../shared/models/integration";
|
||||
|
||||
@Component({
|
||||
selector: "my-integration-bag",
|
||||
@ -9,7 +10,7 @@ import { DomSanitizer, SafeResourceUrl } from "@angular/platform-browser";
|
||||
})
|
||||
export class IntegrationBagComponent {
|
||||
|
||||
@Input() integrations: Integration[];
|
||||
@Input() integrations: LegacyIntegration[];
|
||||
@Output() integrationClicked: EventEmitter<Integration> = new EventEmitter<Integration>();
|
||||
|
||||
constructor(private sanitizer: DomSanitizer) {
|
||||
|
@ -1,10 +1,10 @@
|
||||
import { Component, EventEmitter, Input, Output } from "@angular/core";
|
||||
import { Integration } from "../shared/models/integration";
|
||||
import { LegacyIntegration } from "../shared/models/legacyintegration";
|
||||
import { BSModalContext } from "ngx-modialog/plugins/bootstrap";
|
||||
import { DomSanitizer, SafeResourceUrl } from "@angular/platform-browser";
|
||||
|
||||
export class ConfigModalContext extends BSModalContext {
|
||||
public integration: Integration;
|
||||
public integration: LegacyIntegration;
|
||||
public roomId: string;
|
||||
public userId: string;
|
||||
public scalarToken: string;
|
||||
@ -18,7 +18,7 @@ export class ConfigModalContext extends BSModalContext {
|
||||
})
|
||||
export class IntegrationComponent {
|
||||
|
||||
@Input() integration: Integration;
|
||||
@Input() integration: LegacyIntegration;
|
||||
@Output() selected: EventEmitter<any> = new EventEmitter<any>();
|
||||
|
||||
constructor(private sanitizer: DomSanitizer) {
|
||||
|
@ -1,12 +1,13 @@
|
||||
import { Component, ViewChildren } from "@angular/core";
|
||||
import { IntegrationService } from "../../shared/services/integration.service";
|
||||
import { IntegrationComponent } from "../../integration/integration.component";
|
||||
import { Component } from "@angular/core";
|
||||
import { ToasterService } from "angular2-toaster";
|
||||
import { Integration } from "../../shared/models/integration";
|
||||
import { ActivatedRoute } from "@angular/router";
|
||||
import { ApiService } from "../../shared/services/api.service";
|
||||
import { ScalarService } from "../../shared/services/scalar.service";
|
||||
import { ScalarClientApiService } from "../../shared/services/scalar-client-api.service";
|
||||
import * as _ from "lodash";
|
||||
import { ScalarServerApiService } from "../../shared/services/scalar-server-api.service";
|
||||
import { AuthedApi } from "../../shared/services/AuthedApi";
|
||||
import { DimensionApiService } from "../../shared/services/dimension-api.service";
|
||||
import { Integration, IntegrationRequirement } from "../../shared/models/integration";
|
||||
import { IntegrationService } from "../../shared/services/integration.service";
|
||||
|
||||
const CATEGORY_MAP = {
|
||||
"Widgets": ["widget"],
|
||||
@ -20,14 +21,11 @@ const CATEGORY_MAP = {
|
||||
styleUrls: ["./home.component.scss"],
|
||||
})
|
||||
export class RiotHomeComponent {
|
||||
@ViewChildren(IntegrationComponent) integrationComponents: Array<IntegrationComponent>;
|
||||
|
||||
public isLoading = true;
|
||||
public isError = false;
|
||||
public errorMessage: string;
|
||||
public isRoomEncrypted: boolean;
|
||||
|
||||
private scalarToken: string;
|
||||
private roomId: string;
|
||||
private userId: string;
|
||||
private requestedScreen: string = null;
|
||||
@ -36,8 +34,9 @@ export class RiotHomeComponent {
|
||||
private categoryMap: { [categoryName: string]: string[] } = CATEGORY_MAP;
|
||||
|
||||
constructor(private activatedRoute: ActivatedRoute,
|
||||
private api: ApiService,
|
||||
private scalar: ScalarService,
|
||||
private scalarApi: ScalarServerApiService,
|
||||
private scalar: ScalarClientApiService,
|
||||
private dimensionApi: DimensionApiService,
|
||||
private toaster: ToasterService) {
|
||||
let params: any = this.activatedRoute.snapshot.queryParams;
|
||||
|
||||
@ -51,9 +50,10 @@ export class RiotHomeComponent {
|
||||
this.errorMessage = "Unable to load Dimension - missing room ID or token.";
|
||||
} else {
|
||||
this.roomId = params.room_id;
|
||||
this.scalarToken = params.scalar_token;
|
||||
AuthedApi.SCALAR_TOKEN = params.scalar_token;
|
||||
|
||||
this.api.getTokenOwner(params.scalar_token).then(userId => {
|
||||
this.scalarApi.getAccount().then(response => {
|
||||
const userId = response.user_id;
|
||||
if (!userId) {
|
||||
console.error("No user returned for token. Is the token registered in Dimension?");
|
||||
this.isError = true;
|
||||
@ -89,31 +89,42 @@ export class RiotHomeComponent {
|
||||
return this.integrationsForCategory[category];
|
||||
}
|
||||
|
||||
public modifyIntegration(integration: Integration) {
|
||||
console.log(this.userId + " is trying to modify " + integration.name);
|
||||
private getIntegrations(): Integration[] {
|
||||
const result: Integration[] = [];
|
||||
|
||||
if (integration.hasAdditionalConfig) {
|
||||
// TODO: Navigate to edit screen
|
||||
console.log("EDIT SCREEN FOR " + integration.name);
|
||||
} else {
|
||||
// It's a flip-a-bit (simple bot)
|
||||
for (const category of this.getCategories()) {
|
||||
for (const integration of this.getIntegrationsIn(category)) {
|
||||
result.push(integration);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
public modifyIntegration(integration: Integration) {
|
||||
console.log(this.userId + " is trying to modify " + integration.displayName);
|
||||
|
||||
if (integration.category === "bot") {
|
||||
// It's a bot
|
||||
// TODO: "Are you sure?" dialog
|
||||
|
||||
let promise = null;
|
||||
if (!integration.isEnabled) {
|
||||
promise = this.scalar.inviteUser(this.roomId, integration.userId);
|
||||
} else promise = this.api.removeIntegration(this.roomId, integration.type, integration.integrationType, this.scalarToken);
|
||||
|
||||
// let promise = null;
|
||||
const promise = Promise.resolve();
|
||||
// if (!integration._inRoom) {
|
||||
// promise = this.scalar.inviteUser(this.roomId, integration.userId);
|
||||
// } else promise = this.api.removeIntegration(this.roomId, integration.type, integration.integrationType, this.scalarToken);
|
||||
// We set this ahead of the promise for debouncing
|
||||
integration.isEnabled = !integration.isEnabled;
|
||||
integration.isUpdating = true;
|
||||
|
||||
integration._inRoom = !integration._inRoom;
|
||||
integration._isUpdating = true;
|
||||
promise.then(() => {
|
||||
integration.isUpdating = false;
|
||||
if (integration.isEnabled) this.toaster.pop("success", integration.name + " was invited to the room");
|
||||
else this.toaster.pop("success", integration.name + " was removed from the room");
|
||||
integration._isUpdating = false;
|
||||
if (integration._inRoom) this.toaster.pop("success", integration.displayName + " was invited to the room");
|
||||
else this.toaster.pop("success", integration.displayName + " was removed from the room");
|
||||
}).catch(err => {
|
||||
integration.isEnabled = !integration.isEnabled; // revert the status change
|
||||
integration.isUpdating = false;
|
||||
integration._inRoom = !integration._inRoom; // revert the status change
|
||||
integration._isUpdating = false;
|
||||
console.error(err);
|
||||
|
||||
let errorMessage = null;
|
||||
@ -122,31 +133,27 @@ export class RiotHomeComponent {
|
||||
if (!errorMessage) errorMessage = "Could not update integration status";
|
||||
|
||||
this.toaster.pop("error", errorMessage);
|
||||
})
|
||||
});
|
||||
} else {
|
||||
// TODO: Navigate to edit screen
|
||||
console.log("EDIT SCREEN FOR " + integration.displayName);
|
||||
}
|
||||
}
|
||||
|
||||
private prepareIntegrations() {
|
||||
this.scalar.isRoomEncrypted(this.roomId).then(payload => {
|
||||
this.isRoomEncrypted = payload.response;
|
||||
return this.api.getIntegrations(this.roomId, this.scalarToken);
|
||||
}).then(integrations => {
|
||||
return this.dimensionApi.getIntegrations(this.roomId);
|
||||
}).then(response => {
|
||||
const integrations: Integration[] = _.flatten(Object.keys(response).map(k => response[k]));
|
||||
const supportedIntegrations: Integration[] = _.filter(integrations, i => IntegrationService.isSupported(i));
|
||||
|
||||
for (const integration of supportedIntegrations) {
|
||||
// Widgets technically support encrypted rooms, so unless they explicitly declare that
|
||||
// they don't, we'll assume they do. A warning about adding widgets in encrypted rooms
|
||||
// is displayed to users elsewhere.
|
||||
if (integration.type === "widget" && integration.supportsEncryptedRooms !== false)
|
||||
integration.supportsEncryptedRooms = true;
|
||||
}
|
||||
|
||||
// Flag integrations that aren't supported in encrypted rooms
|
||||
if (this.isRoomEncrypted) {
|
||||
for (const integration of supportedIntegrations) {
|
||||
if (!integration.supportsEncryptedRooms) {
|
||||
integration.isSupported = false;
|
||||
integration.notSupportedReason = "This integration is not supported in encrypted rooms";
|
||||
if (!integration.isEncryptionSupported) {
|
||||
integration._isSupported = false;
|
||||
integration._notSupportedReason = "This integration is not supported in encrypted rooms";
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -154,7 +161,7 @@ export class RiotHomeComponent {
|
||||
// Set up the categories
|
||||
for (const category of Object.keys(this.categoryMap)) {
|
||||
const supportedTypes = this.categoryMap[category];
|
||||
this.integrationsForCategory[category] = _.filter(supportedIntegrations, i => supportedTypes.indexOf(i.type) !== -1);
|
||||
this.integrationsForCategory[category] = _.filter(supportedIntegrations, i => supportedTypes.indexOf(i.category) !== -1);
|
||||
}
|
||||
|
||||
let promises = supportedIntegrations.map(i => this.updateIntegrationState(i));
|
||||
@ -173,92 +180,57 @@ export class RiotHomeComponent {
|
||||
}
|
||||
|
||||
private tryOpenConfigScreen() {
|
||||
let category = null;
|
||||
let type = null;
|
||||
let integrationType = null;
|
||||
if (!this.requestedScreen) return;
|
||||
|
||||
const targetIntegration = IntegrationService.getIntegrationForScreen(this.requestedScreen);
|
||||
if (targetIntegration) {
|
||||
category = targetIntegration.category;
|
||||
type = targetIntegration.type;
|
||||
integrationType = targetIntegration.integrationType;
|
||||
} else {
|
||||
console.log("Unknown screen requested: " + this.requestedScreen);
|
||||
}
|
||||
|
||||
let opened = false;
|
||||
this.integrationComponents.forEach(component => {
|
||||
if (opened) return;
|
||||
if (component.integration.type !== type || component.integration.integrationType !== integrationType) return;
|
||||
console.log("Configuring integration " + this.requestedIntegration + " type=" + type + " integrationType=" + integrationType);
|
||||
//component.configureIntegration(this.requestedIntegration);
|
||||
// TODO: Support editing integrations
|
||||
opened = true;
|
||||
});
|
||||
if (!opened) {
|
||||
console.log("Failed to find integration component for type=" + type + " integrationType=" + integrationType);
|
||||
for (const integration of this.getIntegrations()) {
|
||||
if (integration.category === category && integration.type === type) {
|
||||
console.log("Configuring integration " + this.requestedIntegration + " category=" + category + " type=" + type);
|
||||
// TODO: Actually edit integration
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
console.log("Failed to find integration component for category=" + category + " type=" + type);
|
||||
}
|
||||
|
||||
private updateIntegrationState(integration: Integration) {
|
||||
integration.hasAdditionalConfig = IntegrationService.hasConfig(integration);
|
||||
if (!integration.requirements) return;
|
||||
|
||||
if (integration.type === "widget") {
|
||||
if (!integration.requirements) integration.requirements = {};
|
||||
integration.requirements["canSetWidget"] = true;
|
||||
}
|
||||
let promises = integration.requirements.map(r => this.checkRequirement(r));
|
||||
|
||||
// If the integration has requirements, then we'll check those instead of anything else
|
||||
if (integration.requirements) {
|
||||
let keys = _.keys(integration.requirements);
|
||||
let promises = [];
|
||||
|
||||
for (let key of keys) {
|
||||
let requirement = this.checkRequirement(integration, key);
|
||||
promises.push(requirement);
|
||||
}
|
||||
|
||||
return Promise.all(promises).then(() => {
|
||||
integration.isSupported = true;
|
||||
integration.notSupportedReason = null;
|
||||
}, error => {
|
||||
console.error(error);
|
||||
integration.isSupported = false;
|
||||
integration.notSupportedReason = error;
|
||||
});
|
||||
}
|
||||
|
||||
// The integration doesn't have requirements, so we'll just make sure the bot user can be retrieved.
|
||||
return this.scalar.getMembershipState(this.roomId, integration.userId).then(payload => {
|
||||
if (payload.response) {
|
||||
integration.isSupported = true;
|
||||
integration.notSupportedReason = null;
|
||||
integration.isEnabled = (payload.response.membership === "join" || payload.response.membership === "invite");
|
||||
} else {
|
||||
console.error("No response received to membership query of " + integration.userId);
|
||||
integration.isSupported = false;
|
||||
integration.notSupportedReason = "Unable to query membership state for this bot";
|
||||
}
|
||||
}, (error) => {
|
||||
return Promise.all(promises).then(() => {
|
||||
integration._isSupported = true;
|
||||
integration._notSupportedReason = null;
|
||||
}, error => {
|
||||
console.error(error);
|
||||
integration.isSupported = false;
|
||||
integration.notSupportedReason = "Unable to query membership state for this bot";
|
||||
integration._isSupported = false;
|
||||
integration._notSupportedReason = error;
|
||||
});
|
||||
}
|
||||
|
||||
private checkRequirement(integration: Integration, key: string) {
|
||||
let requirement = integration.requirements[key];
|
||||
|
||||
switch (key) {
|
||||
case "joinRule":
|
||||
private checkRequirement(requirement: IntegrationRequirement) {
|
||||
switch (requirement.condition) {
|
||||
case "publicRoom":
|
||||
return this.scalar.getJoinRule(this.roomId).then(payload => {
|
||||
if (!payload.response) {
|
||||
return Promise.reject("Could not communicate with Riot");
|
||||
}
|
||||
return payload.response.join_rule === requirement
|
||||
? Promise.resolve()
|
||||
: Promise.reject("The room must be " + requirement + " to use this integration.");
|
||||
const isPublic = payload.response.join_rule === "public";
|
||||
if (isPublic !== requirement.expectedValue) {
|
||||
return Promise.reject("The room must be " + (isPublic ? "non-public" : "public") + " to use this integration");
|
||||
} else return Promise.resolve();
|
||||
});
|
||||
case "canSetWidget":
|
||||
case "canSendEventTypes":
|
||||
const processPayload = payload => {
|
||||
const response = <any>payload.response;
|
||||
if (response === true) return Promise.resolve();
|
||||
@ -266,9 +238,17 @@ export class RiotHomeComponent {
|
||||
return Promise.reject("You cannot modify widgets in this room");
|
||||
return Promise.reject("Error communicating with Riot");
|
||||
};
|
||||
return this.scalar.canSendEvent(this.roomId, "im.vector.modular.widgets", true).then(processPayload).catch(processPayload);
|
||||
|
||||
let promiseChain = Promise.resolve();
|
||||
requirement.argument.forEach(e => promiseChain = promiseChain.then(() => this.scalar.canSendEvent(this.roomId, e.type, e.isState).then(processPayload).catch(processPayload)));
|
||||
return promiseChain.then(() => {
|
||||
if (!requirement.expectedValue) return Promise.reject("Expected to not be able to send specific event types");
|
||||
}).catch(err => {
|
||||
console.error(err);
|
||||
if (requirement.expectedValue) return Promise.reject("Expected to be able to send specific event types");
|
||||
});
|
||||
default:
|
||||
return Promise.reject("Requirement '" + key + "' not found");
|
||||
return Promise.reject("Requirement '" + requirement.condition + "' not found");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { Component } from "@angular/core";
|
||||
import { ScalarService } from "../../shared/services/scalar.service";
|
||||
import { ScalarClientApiService } from "../../shared/services/scalar-client-api.service";
|
||||
|
||||
@Component({
|
||||
selector: "my-scalar-close",
|
||||
@ -8,7 +8,7 @@ import { ScalarService } from "../../shared/services/scalar.service";
|
||||
})
|
||||
export class ScalarCloseComponent {
|
||||
|
||||
constructor(private scalar: ScalarService) {
|
||||
constructor(private scalar: ScalarClientApiService) {
|
||||
}
|
||||
|
||||
public closeScalar() {
|
||||
|
5
web/app/shared/models/dimension_responses.ts
Normal file
5
web/app/shared/models/dimension_responses.ts
Normal file
@ -0,0 +1,5 @@
|
||||
import { Widget } from "./integration";
|
||||
|
||||
export interface DimensionIntegrationsResponse {
|
||||
widgets: Widget[];
|
||||
}
|
@ -1,49 +1,40 @@
|
||||
export interface Integration {
|
||||
// These are from the server
|
||||
category: "bot" | "complex-bot" | "bridge" | "widget";
|
||||
type: string;
|
||||
integrationType: string;
|
||||
userId: string;
|
||||
name: string;
|
||||
avatar: string;
|
||||
about: string; // nullable
|
||||
supportsEncryptedRooms: boolean;
|
||||
requirements: any; // nullable
|
||||
requirements: IntegrationRequirement[];
|
||||
isEncryptionSupported: boolean;
|
||||
displayName: string;
|
||||
avatarUrl: string;
|
||||
description: string;
|
||||
isEnabled: boolean;
|
||||
isPublic: boolean;
|
||||
|
||||
// These are set in the UI
|
||||
isSupported: boolean;
|
||||
notSupportedReason: string;
|
||||
hasAdditionalConfig: boolean;
|
||||
isEnabled: boolean; // for the flip-a-bit integrations
|
||||
isUpdating: boolean;
|
||||
// Used by us
|
||||
_inRoom: boolean;
|
||||
_isUpdating: boolean;
|
||||
_isSupported: boolean;
|
||||
_notSupportedReason: string;
|
||||
}
|
||||
|
||||
export interface RSSIntegration extends Integration {
|
||||
feeds: string[];
|
||||
immutableFeeds: { url: string, ownerId: string }[];
|
||||
export interface Widget extends Integration {
|
||||
options: any;
|
||||
}
|
||||
|
||||
export interface TravisCiIntegration extends Integration {
|
||||
repoTemplates: { repoKey: string, template: string, newTemplate: string }[]; // newTemplate is local
|
||||
immutableRepoTemplates: { repoKey: string, template: string, ownerId: string }[];
|
||||
webhookUrl: string; // immutable
|
||||
export interface EtherpadWidget extends Widget {
|
||||
options: {
|
||||
defaultUrl: string;
|
||||
};
|
||||
}
|
||||
|
||||
export interface CircleCiIntegration extends Integration {
|
||||
repoTemplates: { repoKey: string, template: string, newTemplate: string }[]; // newTemplate is local
|
||||
immutableRepoTemplates: { repoKey: string, template: string, ownerId: string }[];
|
||||
webhookUrl: string; // immutable
|
||||
export interface JitsiWidget extends Widget {
|
||||
options: {
|
||||
jitsiDomain: string;
|
||||
scriptUrl: string;
|
||||
};
|
||||
}
|
||||
|
||||
export interface IRCIntegration extends Integration {
|
||||
availableNetworks: { name: string, id: string }[];
|
||||
channels: { [networkId: string]: string[] };
|
||||
}
|
||||
|
||||
export interface EtherpadWidgetIntegration extends Integration {
|
||||
defaultUrl: string;
|
||||
}
|
||||
|
||||
export interface JitsiWidgetIntegration extends Integration {
|
||||
jitsiDomain: string;
|
||||
scriptUrl: string
|
||||
export interface IntegrationRequirement {
|
||||
condition: "publicRoom" | "canSendEventTypes";
|
||||
argument: any;
|
||||
expectedValue: any;
|
||||
}
|
49
web/app/shared/models/legacyintegration.ts
Normal file
49
web/app/shared/models/legacyintegration.ts
Normal file
@ -0,0 +1,49 @@
|
||||
export interface LegacyIntegration {
|
||||
// These are from the server
|
||||
type: string;
|
||||
integrationType: string;
|
||||
userId: string;
|
||||
name: string;
|
||||
avatar: string;
|
||||
about: string; // nullable
|
||||
supportsEncryptedRooms: boolean;
|
||||
requirements: any; // nullable
|
||||
|
||||
// These are set in the UI
|
||||
isSupported: boolean;
|
||||
notSupportedReason: string;
|
||||
hasAdditionalConfig: boolean;
|
||||
isEnabled: boolean; // for the flip-a-bit integrations
|
||||
isUpdating: boolean;
|
||||
}
|
||||
|
||||
export interface RSSIntegration extends LegacyIntegration {
|
||||
feeds: string[];
|
||||
immutableFeeds: { url: string, ownerId: string }[];
|
||||
}
|
||||
|
||||
export interface TravisCiIntegration extends LegacyIntegration {
|
||||
repoTemplates: { repoKey: string, template: string, newTemplate: string }[]; // newTemplate is local
|
||||
immutableRepoTemplates: { repoKey: string, template: string, ownerId: string }[];
|
||||
webhookUrl: string; // immutable
|
||||
}
|
||||
|
||||
export interface CircleCiIntegration extends LegacyIntegration {
|
||||
repoTemplates: { repoKey: string, template: string, newTemplate: string }[]; // newTemplate is local
|
||||
immutableRepoTemplates: { repoKey: string, template: string, ownerId: string }[];
|
||||
webhookUrl: string; // immutable
|
||||
}
|
||||
|
||||
export interface IRCIntegration extends LegacyIntegration {
|
||||
availableNetworks: { name: string, id: string }[];
|
||||
channels: { [networkId: string]: string[] };
|
||||
}
|
||||
|
||||
export interface EtherpadWidgetIntegration extends LegacyIntegration {
|
||||
defaultUrl: string;
|
||||
}
|
||||
|
||||
export interface JitsiWidgetIntegration extends LegacyIntegration {
|
||||
jitsiDomain: string;
|
||||
scriptUrl: string
|
||||
}
|
3
web/app/shared/models/scalar_server_responses.ts
Normal file
3
web/app/shared/models/scalar_server_responses.ts
Normal file
@ -0,0 +1,3 @@
|
||||
export interface ScalarAccountResponse {
|
||||
user_id: string;
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
import { WidgetsResponse } from "./scalar_responses";
|
||||
import { WidgetsResponse } from "./scalar_client_responses";
|
||||
|
||||
export const WIDGET_CUSTOM = ["customwidget", "dimension-customwidget"];
|
||||
export const WIDGET_ETHERPAD = ["etherpad", "dimension-etherpad"];
|
||||
|
15
web/app/shared/services/AuthedApi.ts
Normal file
15
web/app/shared/services/AuthedApi.ts
Normal file
@ -0,0 +1,15 @@
|
||||
import { Http, Response } from "@angular/http";
|
||||
import { Observable } from "rxjs/Observable";
|
||||
|
||||
export class AuthedApi {
|
||||
public static SCALAR_TOKEN: string = null;
|
||||
|
||||
constructor(protected http: Http) {
|
||||
}
|
||||
|
||||
protected authedGet(url: string, qs?: any): Observable<Response> {
|
||||
if (!qs) qs = {};
|
||||
qs["scalar_token"] = AuthedApi.SCALAR_TOKEN;
|
||||
return this.http.get(url, {params: qs});
|
||||
}
|
||||
}
|
10
web/app/shared/services/admin-api.service.ts
Normal file
10
web/app/shared/services/admin-api.service.ts
Normal file
@ -0,0 +1,10 @@
|
||||
import { Injectable } from "@angular/core";
|
||||
import { Http } from "@angular/http";
|
||||
import { AuthedApi } from "./AuthedApi";
|
||||
|
||||
@Injectable()
|
||||
export class AdminApiService extends AuthedApi {
|
||||
constructor(http: Http) {
|
||||
super(http);
|
||||
}
|
||||
}
|
15
web/app/shared/services/dimension-api.service.ts
Normal file
15
web/app/shared/services/dimension-api.service.ts
Normal file
@ -0,0 +1,15 @@
|
||||
import { Injectable } from "@angular/core";
|
||||
import { Http } from "@angular/http";
|
||||
import { AuthedApi } from "./AuthedApi";
|
||||
import { DimensionIntegrationsResponse } from "../models/dimension_responses";
|
||||
|
||||
@Injectable()
|
||||
export class DimensionApiService extends AuthedApi {
|
||||
constructor(http: Http) {
|
||||
super(http);
|
||||
}
|
||||
|
||||
public getIntegrations(roomId: string): Promise<DimensionIntegrationsResponse> {
|
||||
return this.authedGet("/api/v1/dimension/integrations/room/" + roomId).map(r => r.json()).toPromise();
|
||||
}
|
||||
}
|
@ -1,21 +1,9 @@
|
||||
import { Injectable } from "@angular/core";
|
||||
import { Integration } from "../models/integration";
|
||||
import { RssConfigComponent } from "../../configs/rss/rss-config.component";
|
||||
import { ContainerContent } from "ngx-modialog";
|
||||
import { IrcConfigComponent } from "../../configs/irc/irc-config.component";
|
||||
import { TravisCiConfigComponent } from "../../configs/travisci/travisci-config.component";
|
||||
import { CustomWidgetConfigComponent } from "../../configs/widget/custom_widget/custom_widget-config.component";
|
||||
import { YoutubeWidgetConfigComponent } from "../../configs/widget/youtube/youtube-config.component";
|
||||
import { TwitchWidgetConfigComponent } from "../../configs/widget/twitch/twitch-config.component";
|
||||
import { EtherpadWidgetConfigComponent } from "../../configs/widget/etherpad/etherpad-config.component";
|
||||
import { JitsiWidgetConfigComponent } from "../../configs/widget/jitsi/jitsi-config.component";
|
||||
import { Component, Injectable } from "@angular/core";
|
||||
import {
|
||||
WIDGET_CUSTOM, WIDGET_ETHERPAD, WIDGET_GOOGLE_CALENDAR, WIDGET_GOOGLE_DOCS, WIDGET_JITSI, WIDGET_TWITCH,
|
||||
WIDGET_YOUTUBE
|
||||
} from "../models/widget";
|
||||
import { GoogleDocsWidgetConfigComponent } from "../../configs/widget/googledocs/googledocs-config.component";
|
||||
import { GoogleCalendarWidgetConfigComponent } from "../../configs/widget/googlecalendar/googlecalendar-config.component";
|
||||
import { CircleCiConfigComponent } from "../../configs/circleci/circleci-config.component";
|
||||
import { Integration } from "../models/integration";
|
||||
|
||||
@Injectable()
|
||||
export class IntegrationService {
|
||||
@ -24,53 +12,53 @@ export class IntegrationService {
|
||||
"bot": {}, // empty == supported
|
||||
"complex-bot": {
|
||||
"rss": {
|
||||
component: RssConfigComponent,
|
||||
//component: RssConfigComponent,
|
||||
},
|
||||
"travisci": {
|
||||
component: TravisCiConfigComponent,
|
||||
//component: TravisCiConfigComponent,
|
||||
},
|
||||
"circleci": {
|
||||
component: CircleCiConfigComponent,
|
||||
//component: CircleCiConfigComponent,
|
||||
},
|
||||
},
|
||||
"bridge": {
|
||||
"irc": {
|
||||
component: IrcConfigComponent,
|
||||
//component: IrcConfigComponent,
|
||||
},
|
||||
},
|
||||
"widget": {
|
||||
"customwidget": {
|
||||
component: CustomWidgetConfigComponent,
|
||||
//component: CustomWidgetConfigComponent,
|
||||
types: WIDGET_CUSTOM,
|
||||
},
|
||||
"youtube": {
|
||||
component: YoutubeWidgetConfigComponent,
|
||||
//component: YoutubeWidgetConfigComponent,
|
||||
types: WIDGET_YOUTUBE
|
||||
},
|
||||
"etherpad": {
|
||||
component: EtherpadWidgetConfigComponent,
|
||||
//component: EtherpadWidgetConfigComponent,
|
||||
types: WIDGET_ETHERPAD,
|
||||
},
|
||||
"twitch": {
|
||||
component: TwitchWidgetConfigComponent,
|
||||
//component: TwitchWidgetConfigComponent,
|
||||
types: WIDGET_TWITCH,
|
||||
},
|
||||
"jitsi": {
|
||||
component: JitsiWidgetConfigComponent,
|
||||
//component: JitsiWidgetConfigComponent,
|
||||
types: WIDGET_JITSI,
|
||||
},
|
||||
"googledocs": {
|
||||
component: GoogleDocsWidgetConfigComponent,
|
||||
//component: GoogleDocsWidgetConfigComponent,
|
||||
types: WIDGET_GOOGLE_DOCS,
|
||||
},
|
||||
"googlecalendar": {
|
||||
component: GoogleCalendarWidgetConfigComponent,
|
||||
//component: GoogleCalendarWidgetConfigComponent,
|
||||
types: WIDGET_GOOGLE_CALENDAR,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
static getAllConfigComponents(): ContainerContent[] {
|
||||
static getAllConfigComponents(): Component[] {
|
||||
const components = [];
|
||||
|
||||
for (const iType of Object.keys(IntegrationService.supportedIntegrationsMap)) {
|
||||
@ -84,34 +72,30 @@ export class IntegrationService {
|
||||
}
|
||||
|
||||
static isSupported(integration: Integration): boolean {
|
||||
const forType = IntegrationService.supportedIntegrationsMap[integration.type];
|
||||
const forType = IntegrationService.supportedIntegrationsMap[integration.category];
|
||||
if (!forType) return false;
|
||||
|
||||
if (Object.keys(forType).length === 0) return true;
|
||||
|
||||
return forType[integration.integrationType]; // has sub type
|
||||
return forType[integration.type]; // has sub type
|
||||
}
|
||||
|
||||
static hasConfig(integration: Integration): boolean {
|
||||
return integration.type !== "bot";
|
||||
static getConfigComponent(integration: Integration): Component {
|
||||
return IntegrationService.supportedIntegrationsMap[integration.category][integration.type].component;
|
||||
}
|
||||
|
||||
static getConfigComponent(integration: Integration): ContainerContent {
|
||||
return IntegrationService.supportedIntegrationsMap[integration.type][integration.integrationType].component;
|
||||
}
|
||||
|
||||
static getIntegrationForScreen(screen: string): { type: string, integrationType: string } {
|
||||
static getIntegrationForScreen(screen: string): { category: string, type: string } {
|
||||
for (const iType of Object.keys(IntegrationService.supportedIntegrationsMap)) {
|
||||
for (const iiType of Object.keys(IntegrationService.supportedIntegrationsMap[iType])) {
|
||||
const integrationTypes = IntegrationService.supportedIntegrationsMap[iType][iiType].types;
|
||||
const integrationScreens = integrationTypes.map(t => "type_" + t);
|
||||
if (integrationScreens.includes(screen)) return {type: iType, integrationType: iiType};
|
||||
if (integrationScreens.includes(screen)) return {category: iType, type: iiType};
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
constructor() {
|
||||
private constructor() {
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { Injectable } from "@angular/core";
|
||||
import { Http } from "@angular/http";
|
||||
import { Integration } from "../models/integration";
|
||||
import { LegacyIntegration } from "../../models/legacyintegration";
|
||||
|
||||
@Injectable()
|
||||
export class ApiService {
|
||||
@ -17,7 +17,7 @@ export class ApiService {
|
||||
.map(res => res.status === 200 ? res.json()["userId"] : null).toPromise();
|
||||
}
|
||||
|
||||
getIntegrations(roomId: string, scalarToken: string): Promise<Integration[]> {
|
||||
getIntegrations(roomId: string, scalarToken: string): Promise<LegacyIntegration[]> {
|
||||
return this.http.get("/api/v1/dimension/integrations/" + roomId, {params: {scalar_token: scalarToken}})
|
||||
.map(res => res.json()).toPromise();
|
||||
}
|
||||
@ -46,7 +46,7 @@ export class ApiService {
|
||||
.map(res => res.json()).toPromise();
|
||||
}
|
||||
|
||||
getIntegration(type: string, integrationType: string): Promise<Integration> {
|
||||
getIntegration(type: string, integrationType: string): Promise<LegacyIntegration> {
|
||||
const url = "/api/v1/dimension/integration/" + type + "/" + integrationType;
|
||||
return this.http.get(url).map(res => res.json()).toPromise();
|
||||
}
|
@ -1,24 +1,24 @@
|
||||
import { Injectable } from "@angular/core";
|
||||
import { Integration } from "./models/integration";
|
||||
import { RssConfigComponent } from "../configs/rss/rss-config.component";
|
||||
import { LegacyIntegration } from "../../models/legacyintegration";
|
||||
import { RssConfigComponent } from "../../../configs/rss/rss-config.component";
|
||||
import { ContainerContent } from "ngx-modialog";
|
||||
import { IrcConfigComponent } from "../configs/irc/irc-config.component";
|
||||
import { TravisCiConfigComponent } from "../configs/travisci/travisci-config.component";
|
||||
import { CircleCiConfigComponent } from "../configs/circleci/circleci-config.component";
|
||||
import { CustomWidgetConfigComponent } from "../configs/widget/custom_widget/custom_widget-config.component";
|
||||
import { YoutubeWidgetConfigComponent } from "../configs/widget/youtube/youtube-config.component";
|
||||
import { TwitchWidgetConfigComponent } from "../configs/widget/twitch/twitch-config.component";
|
||||
import { EtherpadWidgetConfigComponent } from "../configs/widget/etherpad/etherpad-config.component";
|
||||
import { JitsiWidgetConfigComponent } from "../configs/widget/jitsi/jitsi-config.component";
|
||||
import { IrcConfigComponent } from "../../../configs/irc/irc-config.component";
|
||||
import { TravisCiConfigComponent } from "../../../configs/travisci/travisci-config.component";
|
||||
import { CustomWidgetConfigComponent } from "../../../configs/widget/custom_widget/custom_widget-config.component";
|
||||
import { YoutubeWidgetConfigComponent } from "../../../configs/widget/youtube/youtube-config.component";
|
||||
import { TwitchWidgetConfigComponent } from "../../../configs/widget/twitch/twitch-config.component";
|
||||
import { EtherpadWidgetConfigComponent } from "../../../configs/widget/etherpad/etherpad-config.component";
|
||||
import { JitsiWidgetConfigComponent } from "../../../configs/widget/jitsi/jitsi-config.component";
|
||||
import {
|
||||
WIDGET_CUSTOM, WIDGET_ETHERPAD, WIDGET_GOOGLE_CALENDAR, WIDGET_GOOGLE_DOCS, WIDGET_JITSI, WIDGET_TWITCH,
|
||||
WIDGET_YOUTUBE
|
||||
} from "./models/widget";
|
||||
import { GoogleDocsWidgetConfigComponent } from "../configs/widget/googledocs/googledocs-config.component";
|
||||
import { GoogleCalendarWidgetConfigComponent } from "../configs/widget/googlecalendar/googlecalendar-config.component";
|
||||
} from "../../models/widget";
|
||||
import { GoogleDocsWidgetConfigComponent } from "../../../configs/widget/googledocs/googledocs-config.component";
|
||||
import { GoogleCalendarWidgetConfigComponent } from "../../../configs/widget/googlecalendar/googlecalendar-config.component";
|
||||
import { CircleCiConfigComponent } from "../../../configs/circleci/circleci-config.component";
|
||||
|
||||
@Injectable()
|
||||
export class IntegrationService {
|
||||
export class LegacyIntegrationService {
|
||||
|
||||
private static supportedIntegrationsMap = {
|
||||
"bot": {}, // empty == supported
|
||||
@ -73,9 +73,9 @@ export class IntegrationService {
|
||||
static getAllConfigComponents(): ContainerContent[] {
|
||||
const components = [];
|
||||
|
||||
for (const iType of Object.keys(IntegrationService.supportedIntegrationsMap)) {
|
||||
for (const iiType of Object.keys(IntegrationService.supportedIntegrationsMap[iType])) {
|
||||
const component = IntegrationService.supportedIntegrationsMap[iType][iiType].component;
|
||||
for (const iType of Object.keys(LegacyIntegrationService.supportedIntegrationsMap)) {
|
||||
for (const iiType of Object.keys(LegacyIntegrationService.supportedIntegrationsMap[iType])) {
|
||||
const component = LegacyIntegrationService.supportedIntegrationsMap[iType][iiType].component;
|
||||
if (component) components.push(component);
|
||||
}
|
||||
}
|
||||
@ -83,8 +83,8 @@ export class IntegrationService {
|
||||
return components;
|
||||
}
|
||||
|
||||
static isSupported(integration: Integration): boolean {
|
||||
const forType = IntegrationService.supportedIntegrationsMap[integration.type];
|
||||
static isSupported(integration: LegacyIntegration): boolean {
|
||||
const forType = LegacyIntegrationService.supportedIntegrationsMap[integration.type];
|
||||
if (!forType) return false;
|
||||
|
||||
if (Object.keys(forType).length === 0) return true;
|
||||
@ -92,18 +92,18 @@ export class IntegrationService {
|
||||
return forType[integration.integrationType]; // has sub type
|
||||
}
|
||||
|
||||
static hasConfig(integration: Integration): boolean {
|
||||
static hasConfig(integration: LegacyIntegration): boolean {
|
||||
return integration.type !== "bot";
|
||||
}
|
||||
|
||||
static getConfigComponent(integration: Integration): ContainerContent {
|
||||
return IntegrationService.supportedIntegrationsMap[integration.type][integration.integrationType].component;
|
||||
static getConfigComponent(integration: LegacyIntegration): ContainerContent {
|
||||
return LegacyIntegrationService.supportedIntegrationsMap[integration.type][integration.integrationType].component;
|
||||
}
|
||||
|
||||
static getIntegrationForScreen(screen: string): { type: string, integrationType: string } {
|
||||
for (const iType of Object.keys(IntegrationService.supportedIntegrationsMap)) {
|
||||
for (const iiType of Object.keys(IntegrationService.supportedIntegrationsMap[iType])) {
|
||||
const integrationTypes = IntegrationService.supportedIntegrationsMap[iType][iiType].types;
|
||||
for (const iType of Object.keys(LegacyIntegrationService.supportedIntegrationsMap)) {
|
||||
for (const iiType of Object.keys(LegacyIntegrationService.supportedIntegrationsMap[iType])) {
|
||||
const integrationTypes = LegacyIntegrationService.supportedIntegrationsMap[iType][iiType].types;
|
||||
const integrationScreens = integrationTypes.map(t => "type_" + t);
|
||||
if (integrationScreens.includes(screen)) return {type: iType, integrationType: iiType};
|
||||
}
|
@ -6,17 +6,17 @@ import {
|
||||
MembershipStateResponse, RoomEncryptionStatusResponse,
|
||||
ScalarSuccessResponse,
|
||||
WidgetsResponse
|
||||
} from "../models/scalar_responses";
|
||||
} from "../models/scalar_client_responses";
|
||||
import { EditableWidget } from "../models/widget";
|
||||
|
||||
@Injectable()
|
||||
export class ScalarService {
|
||||
export class ScalarClientApiService {
|
||||
|
||||
private static actionMap: { [key: string]: { resolve: (obj: any) => void, reject: (obj: any) => void } } = {};
|
||||
|
||||
public static getAndRemoveActionHandler(requestKey: string): { resolve: (obj: any) => void, reject: (obj: any) => void } {
|
||||
let handler = ScalarService.actionMap[requestKey];
|
||||
ScalarService.actionMap[requestKey] = null;
|
||||
let handler = ScalarClientApiService.actionMap[requestKey];
|
||||
ScalarClientApiService.actionMap[requestKey] = null;
|
||||
return handler;
|
||||
}
|
||||
|
||||
@ -96,7 +96,7 @@ export class ScalarService {
|
||||
return;
|
||||
}
|
||||
|
||||
ScalarService.actionMap[requestKey] = {
|
||||
ScalarClientApiService.actionMap[requestKey] = {
|
||||
resolve: resolve,
|
||||
reject: reject
|
||||
};
|
||||
@ -117,7 +117,7 @@ window.addEventListener("message", event => {
|
||||
let requestKey = event.data["request_id"];
|
||||
if (!requestKey) return;
|
||||
|
||||
let action = ScalarService.getAndRemoveActionHandler(requestKey);
|
||||
let action = ScalarClientApiService.getAndRemoveActionHandler(requestKey);
|
||||
if (!action) return;
|
||||
|
||||
if (event.data.response && event.data.response.error) action.reject(event.data);
|
15
web/app/shared/services/scalar-server-api.service.ts
Normal file
15
web/app/shared/services/scalar-server-api.service.ts
Normal file
@ -0,0 +1,15 @@
|
||||
import { Injectable } from "@angular/core";
|
||||
import { Http } from "@angular/http";
|
||||
import { ScalarAccountResponse } from "../models/scalar_server_responses";
|
||||
import { AuthedApi } from "./AuthedApi";
|
||||
|
||||
@Injectable()
|
||||
export class ScalarServerApiService extends AuthedApi {
|
||||
constructor(http: Http) {
|
||||
super(http)
|
||||
}
|
||||
|
||||
public getAccount(): Promise<ScalarAccountResponse> {
|
||||
return this.authedGet("/api/v1/scalar/account").map(res => res.json()).toPromise();
|
||||
}
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
import { Component } from "@angular/core";
|
||||
import { ApiService } from "../../shared/services/api.service";
|
||||
import { ApiService } from "../../shared/services/legacy/api.service";
|
||||
import { ActivatedRoute } from "@angular/router";
|
||||
import { DomSanitizer, SafeUrl } from "@angular/platform-browser";
|
||||
|
||||
|
@ -1,8 +1,8 @@
|
||||
import { Component, OnInit } from "@angular/core";
|
||||
import { ActivatedRoute } from "@angular/router";
|
||||
import * as $ from "jquery";
|
||||
import { ApiService } from "../../shared/services/api.service";
|
||||
import { JitsiWidgetIntegration } from "../../shared/models/integration";
|
||||
import { ApiService } from "../../shared/services/legacy/api.service";
|
||||
import { JitsiWidgetIntegration } from "../../shared/models/legacyintegration";
|
||||
|
||||
declare var JitsiMeetExternalAPI: any;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user