mirror of
https://github.com/turt2live/matrix-dimension.git
synced 2024-08-31 14:12:08 +00:00
Admin section for enabling, disabling, and configuring widgets
This commit is contained in:
parent
441bef5606
commit
3f694c2b28
@ -1,4 +1,4 @@
|
|||||||
import { GET, Path, PathParam, QueryParam } from "typescript-rest";
|
import { GET, Path, PathParam, POST, QueryParam } from "typescript-rest";
|
||||||
import * as Promise from "bluebird";
|
import * as Promise from "bluebird";
|
||||||
import { ScalarService } from "../scalar/ScalarService";
|
import { ScalarService } from "../scalar/ScalarService";
|
||||||
import { DimensionStore } from "../../db/DimensionStore";
|
import { DimensionStore } from "../../db/DimensionStore";
|
||||||
@ -12,6 +12,14 @@ interface IntegrationsResponse {
|
|||||||
widgets: Widget[],
|
widgets: Widget[],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface SetEnabledRequest {
|
||||||
|
enabled: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface SetOptionsRequest {
|
||||||
|
options: any;
|
||||||
|
}
|
||||||
|
|
||||||
@Path("/api/v1/dimension/integrations")
|
@Path("/api/v1/dimension/integrations")
|
||||||
export class DimensionIntegrationsService {
|
export class DimensionIntegrationsService {
|
||||||
|
|
||||||
@ -21,6 +29,26 @@ export class DimensionIntegrationsService {
|
|||||||
DimensionIntegrationsService.integrationCache.clear();
|
DimensionIntegrationsService.integrationCache.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@POST
|
||||||
|
@Path(":category/:type/enabled")
|
||||||
|
public setEnabled(@QueryParam("scalar_token") scalarToken: string, @PathParam("category") category: string, @PathParam("type") type: string, body: SetEnabledRequest): Promise<any> {
|
||||||
|
return DimensionAdminService.validateAndGetAdminTokenOwner(scalarToken).then(_userId => {
|
||||||
|
if (category === "widget") {
|
||||||
|
return DimensionStore.setWidgetEnabled(type, body.enabled);
|
||||||
|
} else throw new ApiError(400, "Unrecongized category");
|
||||||
|
}).then(() => DimensionIntegrationsService.clearIntegrationCache());
|
||||||
|
}
|
||||||
|
|
||||||
|
@POST
|
||||||
|
@Path(":category/:type/options")
|
||||||
|
public setOptions(@QueryParam("scalar_token") scalarToken: string, @PathParam("category") category: string, @PathParam("type") type: string, body: SetOptionsRequest): Promise<any> {
|
||||||
|
return DimensionAdminService.validateAndGetAdminTokenOwner(scalarToken).then(_userId => {
|
||||||
|
if (category === "widget") {
|
||||||
|
return DimensionStore.setWidgetOptions(type, body.options);
|
||||||
|
} else throw new ApiError(400, "Unrecongized category");
|
||||||
|
}).then(() => DimensionIntegrationsService.clearIntegrationCache());
|
||||||
|
}
|
||||||
|
|
||||||
@GET
|
@GET
|
||||||
@Path("enabled")
|
@Path("enabled")
|
||||||
public getEnabledIntegrations(@QueryParam("scalar_token") scalarToken: string): Promise<IntegrationsResponse> {
|
public getEnabledIntegrations(@QueryParam("scalar_token") scalarToken: string): Promise<IntegrationsResponse> {
|
||||||
|
@ -94,6 +94,31 @@ class _DimensionStore {
|
|||||||
if (isEnabled === true || isEnabled === false) conditions = {where: {isEnabled: isEnabled}};
|
if (isEnabled === true || isEnabled === false) conditions = {where: {isEnabled: isEnabled}};
|
||||||
return WidgetRecord.findAll(conditions).then(widgets => widgets.map(w => new Widget(w)));
|
return WidgetRecord.findAll(conditions).then(widgets => widgets.map(w => new Widget(w)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public setWidgetEnabled(type: string, isEnabled: boolean): Promise<any> {
|
||||||
|
return this.getWidget(type).then(widget => {
|
||||||
|
widget.isEnabled = isEnabled;
|
||||||
|
return widget.save();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public setWidgetOptions(type: string, options: any): Promise<any> {
|
||||||
|
const optionsJson = JSON.stringify(options);
|
||||||
|
return this.getWidget(type).then(widget => {
|
||||||
|
widget.optionsJson = optionsJson;
|
||||||
|
return widget.save();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private getWidget(type: string): Promise<WidgetRecord> {
|
||||||
|
return WidgetRecord.findAll({where: {type: type}}).then(widgets => {
|
||||||
|
if (!widgets || widgets.length !== 1) {
|
||||||
|
return Promise.reject("Widget not found or too many results");
|
||||||
|
}
|
||||||
|
|
||||||
|
return Promise.resolve(widgets[0]);
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const DimensionStore = new _DimensionStore();
|
export const DimensionStore = new _DimensionStore();
|
@ -1,5 +1,6 @@
|
|||||||
<ul class="adminNav">
|
<ul class="adminNav">
|
||||||
<li (click)="goto('')" [ngClass]="[isActive('', true) ? 'active' : '']">Dashboard</li>
|
<li (click)="goto('')" [ngClass]="[isActive('', true) ? 'active' : '']">Dashboard</li>
|
||||||
|
<li (click)="goto('widgets')" [ngClass]="[isActive('widgets') ? 'active' : '']">Widgets</li>
|
||||||
</ul>
|
</ul>
|
||||||
<span class="version">{{ version }}</span>
|
<span class="version">{{ version }}</span>
|
||||||
|
|
||||||
|
8
web/app/admin/widgets/config-dialog.scss
Normal file
8
web/app/admin/widgets/config-dialog.scss
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
.text-muted {
|
||||||
|
display: block;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.label-block {
|
||||||
|
margin-bottom: 15px;
|
||||||
|
}
|
22
web/app/admin/widgets/etherpad/etherpad.component.html
Normal file
22
web/app/admin/widgets/etherpad/etherpad.component.html
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
<div class="dialog">
|
||||||
|
<div class="dialog-header">
|
||||||
|
<h4>Etherpad Widget Configuration</h4>
|
||||||
|
</div>
|
||||||
|
<div class="dialog-content">
|
||||||
|
<label class="label-block">
|
||||||
|
Default Pad URL Template
|
||||||
|
<span class="text-muted ">$padName and $roomId will be replaced during creation to help create a unique pad URL.</span>
|
||||||
|
<input type="text" class="form-control"
|
||||||
|
placeholder="https://demo.riot.im/etherpad/p/$padName_$roomId"
|
||||||
|
[(ngModel)]="widget.options.defaultUrl" [disabled]="isUpdating"/>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<div class="dialog-footer">
|
||||||
|
<button type="button" (click)="save()" title="save" class="btn btn-primary btn-sm">
|
||||||
|
<i class="far fa-save"></i> Save
|
||||||
|
</button>
|
||||||
|
<button type="button" (click)="dialog.close()" title="close" class="btn btn-secondary btn-sm">
|
||||||
|
<i class="far fa-times-circle"></i> Cancel
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
35
web/app/admin/widgets/etherpad/etherpad.component.ts
Normal file
35
web/app/admin/widgets/etherpad/etherpad.component.ts
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
import { Component } from "@angular/core";
|
||||||
|
import { AdminApiService } from "../../../shared/services/admin-api.service";
|
||||||
|
import { EtherpadWidget } from "../../../shared/models/integration";
|
||||||
|
import { ToasterService } from "angular2-toaster";
|
||||||
|
import { DialogRef, ModalComponent } from "ngx-modialog";
|
||||||
|
import { WidgetConfigDialogContext } from "../widgets.component";
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
templateUrl: "./etherpad.component.html",
|
||||||
|
styleUrls: ["./etherpad.component.scss", "../config-dialog.scss"],
|
||||||
|
})
|
||||||
|
export class AdminWidgetEtherpadConfigComponent implements ModalComponent<WidgetConfigDialogContext> {
|
||||||
|
|
||||||
|
public isUpdating = false;
|
||||||
|
public widget: EtherpadWidget;
|
||||||
|
private originalWidget: EtherpadWidget;
|
||||||
|
|
||||||
|
constructor(public dialog: DialogRef<WidgetConfigDialogContext>, private adminApi: AdminApiService, private toaster: ToasterService) {
|
||||||
|
this.originalWidget = dialog.context.widget;
|
||||||
|
this.widget = JSON.parse(JSON.stringify(this.originalWidget));
|
||||||
|
}
|
||||||
|
|
||||||
|
public save() {
|
||||||
|
this.isUpdating = true;
|
||||||
|
this.adminApi.setWidgetOptions(this.widget.category, this.widget.type, this.widget.options).then(() => {
|
||||||
|
this.originalWidget.options = this.widget.options;
|
||||||
|
this.toaster.pop("success", "Widget updated");
|
||||||
|
this.dialog.close();
|
||||||
|
}).catch(err => {
|
||||||
|
this.isUpdating = false;
|
||||||
|
console.error(err);
|
||||||
|
this.toaster.pop("error", "Error updating widget");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
29
web/app/admin/widgets/jitsi/jitsi.component.html
Normal file
29
web/app/admin/widgets/jitsi/jitsi.component.html
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
<div class="dialog">
|
||||||
|
<div class="dialog-header">
|
||||||
|
<h4>Jitsi Widget Configuration</h4>
|
||||||
|
</div>
|
||||||
|
<div class="dialog-content">
|
||||||
|
<label class="label-block">
|
||||||
|
Jitsi Domain
|
||||||
|
<span class="text-muted ">This is the domain that is used to host the conference.</span>
|
||||||
|
<input type="text" class="form-control"
|
||||||
|
placeholder="jitsi.riot.im"
|
||||||
|
[(ngModel)]="widget.options.jitsiDomain" [disabled]="isUpdating"/>
|
||||||
|
</label>
|
||||||
|
<label class="label-block">
|
||||||
|
Jitsi Script URL
|
||||||
|
<span class="text-muted ">This is used to create the Jitsi widget. It is normally at /libs/external_api.min.js from your domain.</span>
|
||||||
|
<input type="text" class="form-control"
|
||||||
|
placeholder="https://jitsi.riot.im/libs/external_api.min.js"
|
||||||
|
[(ngModel)]="widget.options.scriptUrl" [disabled]="isUpdating"/>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<div class="dialog-footer">
|
||||||
|
<button type="button" (click)="save()" title="save" class="btn btn-primary btn-sm">
|
||||||
|
<i class="far fa-save"></i> Save
|
||||||
|
</button>
|
||||||
|
<button type="button" (click)="dialog.close()" title="close" class="btn btn-secondary btn-sm">
|
||||||
|
<i class="far fa-times-circle"></i> Cancel
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
0
web/app/admin/widgets/jitsi/jitsi.component.scss
Normal file
0
web/app/admin/widgets/jitsi/jitsi.component.scss
Normal file
35
web/app/admin/widgets/jitsi/jitsi.component.ts
Normal file
35
web/app/admin/widgets/jitsi/jitsi.component.ts
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
import { Component } from "@angular/core";
|
||||||
|
import { AdminApiService } from "../../../shared/services/admin-api.service";
|
||||||
|
import { JitsiWidget } from "../../../shared/models/integration";
|
||||||
|
import { ToasterService } from "angular2-toaster";
|
||||||
|
import { DialogRef, ModalComponent } from "ngx-modialog";
|
||||||
|
import { WidgetConfigDialogContext } from "../widgets.component";
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
templateUrl: "./jitsi.component.html",
|
||||||
|
styleUrls: ["./jitsi.component.scss", "../config-dialog.scss"],
|
||||||
|
})
|
||||||
|
export class AdminWidgetJitsiConfigComponent implements ModalComponent<WidgetConfigDialogContext> {
|
||||||
|
|
||||||
|
public isUpdating = false;
|
||||||
|
public widget: JitsiWidget;
|
||||||
|
private originalWidget: JitsiWidget;
|
||||||
|
|
||||||
|
constructor(public dialog: DialogRef<WidgetConfigDialogContext>, private adminApi: AdminApiService, private toaster: ToasterService) {
|
||||||
|
this.originalWidget = dialog.context.widget;
|
||||||
|
this.widget = JSON.parse(JSON.stringify(this.originalWidget));
|
||||||
|
}
|
||||||
|
|
||||||
|
public save() {
|
||||||
|
this.isUpdating = true;
|
||||||
|
this.adminApi.setWidgetOptions(this.widget.category, this.widget.type, this.widget.options).then(() => {
|
||||||
|
this.originalWidget.options = this.widget.options;
|
||||||
|
this.toaster.pop("success", "Widget updated");
|
||||||
|
this.dialog.close();
|
||||||
|
}).catch(err => {
|
||||||
|
this.isUpdating = false;
|
||||||
|
console.error(err);
|
||||||
|
this.toaster.pop("error", "Error updating widget");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
34
web/app/admin/widgets/widgets.component.html
Normal file
34
web/app/admin/widgets/widgets.component.html
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
<div *ngIf="isLoading">
|
||||||
|
<my-spinner></my-spinner>
|
||||||
|
</div>
|
||||||
|
<div *ngIf="!isLoading">
|
||||||
|
<my-ibox title="Widgets">
|
||||||
|
<div class="my-ibox-content">
|
||||||
|
<p>Widgets are small webpages that can be embedded in a Matrix room. Here you can configure which widgets
|
||||||
|
Dimension will offer to users.</p>
|
||||||
|
|
||||||
|
<table class="table table-striped table-condensed table-bordered">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Name</th>
|
||||||
|
<th>Description</th>
|
||||||
|
<th class="text-center">Actions</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr *ngFor="let widget of widgets trackById">
|
||||||
|
<td>{{ widget.displayName }}</td>
|
||||||
|
<td>{{ widget.description }}</td>
|
||||||
|
<td class="text-right">
|
||||||
|
<span class="editButton" (click)="editWidget(widget)" *ngIf="widget.isEnabled && hasConfiguration(widget)">
|
||||||
|
<i class="fa fa-pencil-alt"></i>
|
||||||
|
</span>
|
||||||
|
<ui-switch [checked]="widget.isEnabled" size="small" [disabled]="isUpdating"
|
||||||
|
(change)="disableWidget(widget)"></ui-switch>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</my-ibox>
|
||||||
|
</div>
|
13
web/app/admin/widgets/widgets.component.scss
Normal file
13
web/app/admin/widgets/widgets.component.scss
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
ul {
|
||||||
|
padding-left: 25px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.editButton {
|
||||||
|
cursor: pointer;
|
||||||
|
position: relative;
|
||||||
|
top: -5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
tr td:last-child {
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
69
web/app/admin/widgets/widgets.component.ts
Normal file
69
web/app/admin/widgets/widgets.component.ts
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
import { Component } from "@angular/core";
|
||||||
|
import { AdminApiService } from "../../shared/services/admin-api.service";
|
||||||
|
import { Widget } from "../../shared/models/integration";
|
||||||
|
import { ToasterService } from "angular2-toaster";
|
||||||
|
import { AdminWidgetEtherpadConfigComponent } from "./etherpad/etherpad.component";
|
||||||
|
import { Modal, overlayConfigFactory } from "ngx-modialog";
|
||||||
|
import { BSModalContext } from "ngx-modialog/plugins/bootstrap";
|
||||||
|
import { AdminWidgetJitsiConfigComponent } from "./jitsi/jitsi.component";
|
||||||
|
|
||||||
|
export class WidgetConfigDialogContext extends BSModalContext {
|
||||||
|
public widget: Widget;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
templateUrl: "./widgets.component.html",
|
||||||
|
styleUrls: ["./widgets.component.scss"],
|
||||||
|
})
|
||||||
|
export class AdminWidgetsComponent {
|
||||||
|
|
||||||
|
public isLoading = true;
|
||||||
|
public isUpdating = false;
|
||||||
|
public widgets: Widget[];
|
||||||
|
|
||||||
|
constructor(private adminApi: AdminApiService, private toaster: ToasterService, private modal: Modal) {
|
||||||
|
adminApi.getAllIntegrations().then(integrations => {
|
||||||
|
this.isLoading = false;
|
||||||
|
this.widgets = integrations.widgets;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public disableWidget(widget: Widget) {
|
||||||
|
widget.isEnabled = !widget.isEnabled;
|
||||||
|
this.isUpdating = true;
|
||||||
|
this.adminApi.toggleIntegration(widget.category, widget.type, widget.isEnabled).then(() => {
|
||||||
|
this.isUpdating = false;
|
||||||
|
this.toaster.pop("success", "Widget updated");
|
||||||
|
}).catch(err => {
|
||||||
|
console.error(err);
|
||||||
|
widget.isEnabled = !widget.isEnabled; // revert change
|
||||||
|
this.isUpdating = false;
|
||||||
|
this.toaster.pop("error", "Error updating widget");
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
public editWidget(widget: Widget) {
|
||||||
|
let component = null;
|
||||||
|
|
||||||
|
if (widget.type === "etherpad") component = AdminWidgetEtherpadConfigComponent;
|
||||||
|
if (widget.type === "jitsi") component = AdminWidgetJitsiConfigComponent;
|
||||||
|
|
||||||
|
if (!component) {
|
||||||
|
console.error("No known dialog component for " + widget.type);
|
||||||
|
this.toaster.pop("error", "Error opening configuration page");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.modal.open(component, overlayConfigFactory({
|
||||||
|
widget: widget,
|
||||||
|
|
||||||
|
isBlocking: true,
|
||||||
|
size: 'lg',
|
||||||
|
}, WidgetConfigDialogContext));
|
||||||
|
}
|
||||||
|
|
||||||
|
public hasConfiguration(widget: Widget) {
|
||||||
|
// Currently only Jitsi and Etherpad have additional configuration
|
||||||
|
return widget.type === "jitsi" || widget.type === "etherpad";
|
||||||
|
}
|
||||||
|
}
|
@ -42,6 +42,9 @@ import { TwitchWidgetConfigComponent } from "./configs/widget/twitch/twitch.widg
|
|||||||
import { YoutubeWidgetConfigComponent } from "./configs/widget/youtube/youtube.widget.component";
|
import { YoutubeWidgetConfigComponent } from "./configs/widget/youtube/youtube.widget.component";
|
||||||
import { AdminComponent } from "./admin/admin.component";
|
import { AdminComponent } from "./admin/admin.component";
|
||||||
import { AdminHomeComponent } from "./admin/home/home.component";
|
import { AdminHomeComponent } from "./admin/home/home.component";
|
||||||
|
import { AdminWidgetsComponent } from "./admin/widgets/widgets.component";
|
||||||
|
import { AdminWidgetEtherpadConfigComponent } from "./admin/widgets/etherpad/etherpad.component";
|
||||||
|
import { AdminWidgetJitsiConfigComponent } from "./admin/widgets/jitsi/jitsi.component";
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
imports: [
|
imports: [
|
||||||
@ -83,6 +86,9 @@ import { AdminHomeComponent } from "./admin/home/home.component";
|
|||||||
YoutubeWidgetConfigComponent,
|
YoutubeWidgetConfigComponent,
|
||||||
AdminComponent,
|
AdminComponent,
|
||||||
AdminHomeComponent,
|
AdminHomeComponent,
|
||||||
|
AdminWidgetsComponent,
|
||||||
|
AdminWidgetEtherpadConfigComponent,
|
||||||
|
AdminWidgetJitsiConfigComponent,
|
||||||
|
|
||||||
// Vendor
|
// Vendor
|
||||||
],
|
],
|
||||||
@ -97,7 +103,10 @@ import { AdminHomeComponent } from "./admin/home/home.component";
|
|||||||
// Vendor
|
// Vendor
|
||||||
],
|
],
|
||||||
bootstrap: [AppComponent],
|
bootstrap: [AppComponent],
|
||||||
entryComponents: []
|
entryComponents: [
|
||||||
|
AdminWidgetEtherpadConfigComponent,
|
||||||
|
AdminWidgetJitsiConfigComponent,
|
||||||
|
]
|
||||||
})
|
})
|
||||||
export class AppModule {
|
export class AppModule {
|
||||||
constructor(public appRef: ApplicationRef, injector: Injector) {
|
constructor(public appRef: ApplicationRef, injector: Injector) {
|
||||||
|
@ -15,6 +15,7 @@ import { TwitchWidgetConfigComponent } from "./configs/widget/twitch/twitch.widg
|
|||||||
import { YoutubeWidgetConfigComponent } from "./configs/widget/youtube/youtube.widget.component";
|
import { YoutubeWidgetConfigComponent } from "./configs/widget/youtube/youtube.widget.component";
|
||||||
import { AdminComponent } from "./admin/admin.component";
|
import { AdminComponent } from "./admin/admin.component";
|
||||||
import { AdminHomeComponent } from "./admin/home/home.component";
|
import { AdminHomeComponent } from "./admin/home/home.component";
|
||||||
|
import { AdminWidgetsComponent } from "./admin/widgets/widgets.component";
|
||||||
|
|
||||||
const routes: Routes = [
|
const routes: Routes = [
|
||||||
{path: "", component: HomeComponent},
|
{path: "", component: HomeComponent},
|
||||||
@ -37,6 +38,11 @@ const routes: Routes = [
|
|||||||
path: "",
|
path: "",
|
||||||
component: AdminHomeComponent,
|
component: AdminHomeComponent,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: "widgets",
|
||||||
|
component: AdminWidgetsComponent,
|
||||||
|
data: {breadcrumb: "Widgets", name: "Widgets"},
|
||||||
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -11,4 +11,10 @@ export class AuthedApi {
|
|||||||
qs["scalar_token"] = SessionStorage.scalarToken;
|
qs["scalar_token"] = SessionStorage.scalarToken;
|
||||||
return this.http.get(url, {params: qs});
|
return this.http.get(url, {params: qs});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected authedPost(url: string, body?: any): Observable<Response> {
|
||||||
|
if (!body) body = {};
|
||||||
|
const qs = {scalar_token: SessionStorage.scalarToken};
|
||||||
|
return this.http.post(url, body, {params: qs});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@ import { Injectable } from "@angular/core";
|
|||||||
import { Http } from "@angular/http";
|
import { Http } from "@angular/http";
|
||||||
import { AuthedApi } from "./AuthedApi";
|
import { AuthedApi } from "./AuthedApi";
|
||||||
import { DimensionConfigResponse, DimensionVersionResponse } from "../models/admin_responses";
|
import { DimensionConfigResponse, DimensionVersionResponse } from "../models/admin_responses";
|
||||||
|
import { DimensionIntegrationsResponse } from "../models/dimension_responses";
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class AdminApiService extends AuthedApi {
|
export class AdminApiService extends AuthedApi {
|
||||||
@ -20,4 +21,16 @@ export class AdminApiService extends AuthedApi {
|
|||||||
public getVersion(): Promise<DimensionVersionResponse> {
|
public getVersion(): Promise<DimensionVersionResponse> {
|
||||||
return this.authedGet("/api/v1/dimension/admin/version").map(r => r.json()).toPromise();
|
return this.authedGet("/api/v1/dimension/admin/version").map(r => r.json()).toPromise();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public getAllIntegrations(): Promise<DimensionIntegrationsResponse> {
|
||||||
|
return this.authedGet("/api/v1/dimension/integrations/all").map(r => r.json()).toPromise();
|
||||||
|
}
|
||||||
|
|
||||||
|
public toggleIntegration(category: string, type: string, enabled: boolean): Promise<any> {
|
||||||
|
return this.authedPost("/api/v1/dimension/integrations/" + category + "/" + type + "/enabled", {enabled: enabled}).map(r => r.json()).toPromise();
|
||||||
|
}
|
||||||
|
|
||||||
|
public setWidgetOptions(category: string, type: string, options: any): Promise<any> {
|
||||||
|
return this.authedPost("/api/v1/dimension/integrations/" + category + "/" + type + "/options", {options: options}).map(r => r.json()).toPromise();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
@import url('https://fonts.googleapis.com/css?family=Open+Sans:100|Roboto:300');
|
@import url('https://fonts.googleapis.com/css?family=Open+Sans:100|Roboto:300');
|
||||||
@import '../../node_modules/angular2-toaster/toaster';
|
@import '../../node_modules/angular2-toaster/toaster';
|
||||||
@import "components/ibox";
|
@import "components/ibox";
|
||||||
|
@import "components/dialog";
|
||||||
@import "riot";
|
@import "riot";
|
||||||
|
|
||||||
body {
|
body {
|
||||||
|
21
web/style/components/dialog.scss
Normal file
21
web/style/components/dialog.scss
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
.dialog {
|
||||||
|
.dialog-header {
|
||||||
|
border-bottom: 1px solid #ddd;
|
||||||
|
padding: 20px;
|
||||||
|
|
||||||
|
h4 {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.dialog-content {
|
||||||
|
padding: 20px;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.dialog-footer {
|
||||||
|
padding: 20px;
|
||||||
|
border-top: 1px solid #bbb;
|
||||||
|
background-color: #ddd;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user