Replace ngx-modialog with ng-bootstrap modals

This commit is contained in:
Tony Stipanic 2021-08-17 00:00:59 +02:00
parent 4954de2a96
commit e77d712afd
No known key found for this signature in database
GPG Key ID: 3026BCCB6C9CC6BD
63 changed files with 1300 additions and 1151 deletions

2
.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,2 @@
{
}

6
config/bot.json Normal file
View File

@ -0,0 +1,6 @@
{
"syncToken": "s22_2648_0_1_29_1_25_19_1",
"filter": null,
"appserviceUsers": {},
"appserviceTransactions": {}
}

6
config/bot.json.bak Normal file
View File

@ -0,0 +1,6 @@
{
"syncToken": "s3510138_39116385_25484_5602626_218935_269_119102_8310593_32",
"filter": null,
"appserviceUsers": {},
"appserviceTransactions": {}
}

BIN
config/dimension.db.bak Normal file

Binary file not shown.

9
package-lock.json generated
View File

@ -11648,15 +11648,6 @@
"resolved": "https://registry.npmjs.org/netmask/-/netmask-2.0.2.tgz",
"integrity": "sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg=="
},
"ngx-modialog": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/ngx-modialog/-/ngx-modialog-5.0.1.tgz",
"integrity": "sha512-m6o7V01j97C/6GGQjNfxF96k6713G11Fs/S6RF7NbxRV3EUZsG0MqkDn2Q1fR0UEoaNqyKMDVDTya7N3hAnfPA==",
"dev": true,
"requires": {
"tslib": "^1.9.0"
}
},
"ngx-ui-switch": {
"version": "12.0.1",
"resolved": "https://registry.npmjs.org/ngx-ui-switch/-/ngx-ui-switch-12.0.1.tgz",

View File

@ -117,7 +117,6 @@
"jquery": "^3.6.0",
"json-loader": "^0.5.7",
"mini-css-extract-plugin": "^2.1.0",
"ngx-modialog": "^5.0.1",
"postcss-cssnext": "^3.1.0",
"postcss-import": "^14.0.2",
"postcss-loader": "^6.1.1",

View File

@ -1,8 +1,8 @@
<div class="dialog">
<div class="dialog-header">
<h4>{{'Add a new self-hosted IRC Bridge' | translate}}</h4>
</div>
<div class="dialog-content">
<div class="modal-header">
<h4 class="modal-title" id="modal-basic-title">{{'Add a new self-hosted IRC Bridge' | translate}}</h4>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close" (click)="modal.close()"></button>
</div>
<div class="modal-body">
<p>{{'Self-hosted IRC bridges must have' | translate}}<code>{{'provisioning' | translate}}</code> {{'enabled in the configuration.' | translate}}</p>
<label class="label-block">
@ -12,13 +12,12 @@
placeholder="http://localhost:9999"
[(ngModel)]="provisionUrl" [disabled]="isSaving"/>
</label>
</div>
<div class="dialog-footer">
</div>
<div class="modal-footer">
<button type="button" (click)="add()" title="close" class="btn btn-primary btn-sm">
<i class="far fa-save"></i> {{'Save' | translate}}
</button>
<button type="button" (click)="dialog.close()" title="close" class="btn btn-secondary btn-sm">
<button type="button" (click)="modal.close()" title="close" class="btn btn-secondary btn-sm">
<i class="far fa-times-circle"></i> {{'Cancel' | translate}}
</button>
</div>
</div>

View File

@ -1,23 +1,24 @@
import { Component } from "@angular/core";
import { NgbActiveModal } from "@ng-bootstrap/ng-bootstrap";
import { ToasterService } from "angular2-toaster";
import { DialogRef, ModalComponent } from "ngx-modialog";
import { BSModalContext } from "ngx-modialog/plugins/bootstrap";
import { AdminIrcApiService } from "../../../../shared/services/admin/admin-irc-api.service";
import { TranslateService } from "@ngx-translate/core";
export class AddSelfhostedIrcBridgeDialogContext extends BSModalContext {
export interface AddSelfhostedIrcBridgeDialogContextt {
isSaving: boolean;
provisionUrl: string;
}
@Component({
templateUrl: "./add-selfhosted.component.html",
styleUrls: ["./add-selfhosted.component.scss"],
})
export class AdminIrcBridgeAddSelfhostedComponent implements ModalComponent<AddSelfhostedIrcBridgeDialogContext> {
export class AdminIrcBridgeAddSelfhostedComponent {
public isSaving = false;
public provisionUrl: string;
constructor(public dialog: DialogRef<AddSelfhostedIrcBridgeDialogContext>,
constructor(public modal: NgbActiveModal,
private ircApi: AdminIrcApiService,
private toaster: ToasterService,
public translate: TranslateService) {
@ -28,7 +29,7 @@ export class AdminIrcBridgeAddSelfhostedComponent implements ModalComponent<AddS
this.isSaving = true;
this.ircApi.newSelfhosted(this.provisionUrl).then(() => {
this.translate.get('IRC Bridge added').subscribe((res: string) => {this.toaster.pop("success", res); });
this.dialog.close();
this.modal.close();
}).catch(err => {
console.error(err);
this.isSaving = false;

View File

@ -4,13 +4,12 @@ import { AdminIrcApiService } from "../../../shared/services/admin/admin-irc-api
import { FE_Upstream } from "../../../shared/models/admin-responses";
import { AdminUpstreamApiService } from "../../../shared/services/admin/admin-upstream-api.service";
import { FE_IrcBridge } from "../../../shared/models/irc";
import { Modal, overlayConfigFactory } from "ngx-modialog";
import { AdminIrcBridgeNetworksComponent, IrcNetworksDialogContext } from "./networks/networks.component";
import {
AddSelfhostedIrcBridgeDialogContext,
AdminIrcBridgeAddSelfhostedComponent
} from "./add-selfhosted/add-selfhosted.component";
import { TranslateService } from "@ngx-translate/core";
import { NgbModal } from "@ng-bootstrap/ng-bootstrap";
@Component({
templateUrl: "./irc.component.html",
@ -28,7 +27,7 @@ export class AdminIrcBridgeComponent implements OnInit {
constructor(private upstreamApi: AdminUpstreamApiService,
private ircApi: AdminIrcApiService,
private toaster: ToasterService,
private modal: Modal,
private modal: NgbModal,
public translate: TranslateService) {
this.translate = translate;
}
@ -94,23 +93,34 @@ export class AdminIrcBridgeComponent implements OnInit {
}
public addSelfHostedBridge() {
this.modal.open(AdminIrcBridgeAddSelfhostedComponent, overlayConfigFactory({
isBlocking: true,
const selfhostedRef = this.modal.open(AdminIrcBridgeAddSelfhostedComponent, {
backdrop: 'static',
size: 'lg',
}, AddSelfhostedIrcBridgeDialogContext)).result.then(() => {
this.reload().catch(err => {
});
selfhostedRef.result.then(() => {
try {
this.reload()
} catch (err) {
console.error(err);
this.translate.get('Failed to get an update IRC bridge list').subscribe((res: string) => {this.toaster.pop("error", res); });
});
});
}
})
}
public editNetworks(bridge: FE_IrcBridge) {
this.modal.open(AdminIrcBridgeNetworksComponent, overlayConfigFactory({
bridge: bridge,
isBlocking: true,
const selfhostedRef = this.modal.open(AdminIrcBridgeNetworksComponent, {
backdrop: 'static',
size: 'lg',
}, IrcNetworksDialogContext));
});
selfhostedRef.result.then(() => {
try {
this.reload()
} catch (err) {
console.error(err);
this.translate.get('Failed to get an update IRC bridge list').subscribe((res: string) => {this.toaster.pop("error", res); });
}
})
const selfhostedInstance = selfhostedRef.componentInstance as IrcNetworksDialogContext;
selfhostedInstance.bridge = bridge;
}
}

View File

@ -1,8 +1,8 @@
<div class="dialog">
<div class="dialog-header">
<h4>{{ bridge.upstreamId ? "matrix.org's" : "Self-hosted" }} IRC Bridge Networks</h4>
</div>
<div class="dialog-content">
<div class="modal-header">
<h4 class="modal-title" id="modal-basic-title">{{ bridge.upstreamId ? "matrix.org's" : "Self-hosted" }} IRC Bridge Networks</h4>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close" (click)="modal.close()"></button>
</div>
<div class="modal-body">
<table class="table table-striped table-condensed table-bordered">
<thead>
<tr>
@ -20,10 +20,9 @@
</tr>
</tbody>
</table>
</div>
<div class="dialog-footer">
<button type="button" (click)="dialog.close()" title="close" class="btn btn-primary btn-sm">
</div>
<div class="modal-footer">
<button type="button" (click)="modal.close()" title="close" class="btn btn-outline-secondary btn-sm">
<i class="far fa-times-circle"></i> {{'Close' | translate}}
</button>
</div>
</div>

View File

@ -1,13 +1,12 @@
import { Component } from "@angular/core";
import { NgbActiveModal } from "@ng-bootstrap/ng-bootstrap";
import { ToasterService } from "angular2-toaster";
import { DialogRef, ModalComponent } from "ngx-modialog";
import { BSModalContext } from "ngx-modialog/plugins/bootstrap";
import { FE_IrcBridge } from "../../../../shared/models/irc";
import { AdminIrcApiService } from "../../../../shared/services/admin/admin-irc-api.service";
import { TranslateService } from "@ngx-translate/core";
export class IrcNetworksDialogContext extends BSModalContext {
public bridge: FE_IrcBridge;
export interface IrcNetworksDialogContext {
bridge: FE_IrcBridge;
}
interface LocalNetwork {
@ -22,19 +21,17 @@ interface LocalNetwork {
templateUrl: "./networks.component.html",
styleUrls: ["./networks.component.scss"],
})
export class AdminIrcBridgeNetworksComponent implements ModalComponent<IrcNetworksDialogContext> {
export class AdminIrcBridgeNetworksComponent {
public isUpdating = false;
public bridge: FE_IrcBridge;
public networks: LocalNetwork[];
constructor(public dialog: DialogRef<IrcNetworksDialogContext>,
constructor(public modal: NgbActiveModal,
private ircApi: AdminIrcApiService,
private toaster: ToasterService,
public translate: TranslateService) {
this.translate = translate;
this.bridge = dialog.context.bridge;
const networkIds = Object.keys(this.bridge.availableNetworks);
this.networks = networkIds.map(i => {
return {

View File

@ -1,8 +1,8 @@
<div class="dialog">
<div class="dialog-header">
<h4> {{'self-hosted Slack bridge' | translate}} ({{ isAdding ? "Add a new" : "Edit" }})</h4>
</div>
<div class="dialog-content">
<div class="modal-header">
<h4 class="modal-title" id="modal-basic-title">{{'self-hosted Slack bridge' | translate}} ({{ isAdding ? "Add a new" : "Edit" }})</h4>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close" (click)="modal.close()"></button>
</div>
<div class="modal-body">
<p>
{{'Self-hosted Slack bridges already have provisioning enabled. Be careful not to expose the API to the public internet.' | translate}}
</p>
@ -14,13 +14,12 @@
placeholder="http://localhost:9000"
[(ngModel)]="provisionUrl" [disabled]="isSaving"/>
</label>
</div>
<div class="dialog-footer">
</div>
<div class="modal-footer">
<button type="button" (click)="add()" title="close" class="btn btn-primary btn-sm">
<i class="far fa-save"></i> {{'Save' | translate}}
</button>
<button type="button" (click)="dialog.close()" title="close" class="btn btn-secondary btn-sm">
<button type="button" (click)="modal.close()" title="close" class="btn btn-secondary btn-sm">
<i class="far fa-times-circle"></i> {{'Cancel' | translate}}
</button>
</div>
</div>

View File

@ -1,34 +1,31 @@
import { Component } from "@angular/core";
import { NgbActiveModal } from "@ng-bootstrap/ng-bootstrap";
import { ToasterService } from "angular2-toaster";
import { DialogRef, ModalComponent } from "ngx-modialog";
import { BSModalContext } from "ngx-modialog/plugins/bootstrap";
import { AdminSlackApiService } from "../../../../shared/services/admin/admin-slack-api.service";
import { TranslateService } from "@ngx-translate/core";
export class ManageSelfhostedSlackBridgeDialogContext extends BSModalContext {
public provisionUrl: string;
public bridgeId: number;
export interface ManageSelfhostedSlackBridgeDialogContext {
provisionUrl: string;
bridgeId: number;
isAdding: boolean;
}
@Component({
templateUrl: "./manage-selfhosted.component.html",
styleUrls: ["./manage-selfhosted.component.scss"],
})
export class AdminSlackBridgeManageSelfhostedComponent implements ModalComponent<ManageSelfhostedSlackBridgeDialogContext> {
export class AdminSlackBridgeManageSelfhostedComponent {
public isSaving = false;
public provisionUrl: string;
public bridgeId: number;
public isAdding = false;
public isAdding = true;
constructor(public dialog: DialogRef<ManageSelfhostedSlackBridgeDialogContext>,
constructor(public modal: NgbActiveModal,
private slackApi: AdminSlackApiService,
private toaster: ToasterService,
public translate: TranslateService) {
this.translate = translate;
this.provisionUrl = dialog.context.provisionUrl;
this.bridgeId = dialog.context.bridgeId;
this.isAdding = !this.bridgeId;
}
public add() {
@ -36,7 +33,7 @@ export class AdminSlackBridgeManageSelfhostedComponent implements ModalComponent
if (this.isAdding) {
this.slackApi.newSelfhosted(this.provisionUrl).then(() => {
this.translate.get('Slack bridge added').subscribe((res: string) => {this.toaster.pop("success", res); });
this.dialog.close();
this.modal.close();
}).catch(err => {
console.error(err);
this.isSaving = false;
@ -45,7 +42,7 @@ export class AdminSlackBridgeManageSelfhostedComponent implements ModalComponent
} else {
this.slackApi.updateSelfhosted(this.bridgeId, this.provisionUrl).then(() => {
this.translate.get('Slack bridge updated').subscribe((res: string) => this.toaster.pop("success", res));
this.dialog.close();
this.modal.close();
}).catch(err => {
console.error(err);
this.isSaving = false;

View File

@ -1,6 +1,5 @@
import { Component, OnInit } from "@angular/core";
import { ToasterService } from "angular2-toaster";
import { Modal, overlayConfigFactory } from "ngx-modialog";
import { FE_Upstream } from "../../../shared/models/admin-responses";
import { AdminUpstreamApiService } from "../../../shared/services/admin/admin-upstream-api.service";
import {
@ -10,6 +9,7 @@ import {
import { FE_SlackBridge } from "../../../shared/models/slack";
import { AdminSlackApiService } from "../../../shared/services/admin/admin-slack-api.service";
import { TranslateService } from "@ngx-translate/core";
import { NgbModal } from "@ng-bootstrap/ng-bootstrap";
@Component({
templateUrl: "./slack.component.html",
@ -26,7 +26,7 @@ export class AdminSlackBridgeComponent implements OnInit {
constructor(private slackApi: AdminSlackApiService,
private upstreamApi: AdminUpstreamApiService,
private toaster: ToasterService,
private modal: Modal,
private modal: NgbModal,
public translate: TranslateService) {
this.translate = translate;
}
@ -75,31 +75,38 @@ export class AdminSlackBridgeComponent implements OnInit {
}
public addSelfHostedBridge() {
this.modal.open(AdminSlackBridgeManageSelfhostedComponent, overlayConfigFactory({
isBlocking: true,
const selfhostedRef = this.modal.open(AdminSlackBridgeManageSelfhostedComponent, {
backdrop: 'static',
size: 'lg',
provisionUrl: '',
}, ManageSelfhostedSlackBridgeDialogContext)).result.then(() => {
this.reload().catch(err => {
});
selfhostedRef.result.then(() => {
try {
this.reload()
} catch (err) {
console.error(err);
this.translate.get('Failed to get an update Slack bridge list').subscribe((res: string) => {this.toaster.pop("error", res); });
}
});
});
const selfhostedInstance = selfhostedRef.componentInstance as ManageSelfhostedSlackBridgeDialogContext;
selfhostedInstance.provisionUrl = '';
}
public editBridge(bridge: FE_SlackBridge) {
this.modal.open(AdminSlackBridgeManageSelfhostedComponent, overlayConfigFactory({
isBlocking: true,
const selfhostedRef = this.modal.open(AdminSlackBridgeManageSelfhostedComponent, {
backdrop: 'static',
size: 'lg',
provisionUrl: bridge.provisionUrl,
bridgeId: bridge.id,
}, ManageSelfhostedSlackBridgeDialogContext)).result.then(() => {
this.reload().catch(err => {
});
selfhostedRef.result.then(() => {
try {
this.reload()
} catch (err) {
console.error(err);
this.translate.get('Failed to get an update Slack bridge list').subscribe((res: string) => {this.toaster.pop("error", res); });
}
});
});
const selfhostedInstance = selfhostedRef.componentInstance as ManageSelfhostedSlackBridgeDialogContext;
selfhostedInstance.provisionUrl = '';
selfhostedInstance.bridgeId = bridge.id;
selfhostedInstance.isAdding = !bridge.id;
}
}

View File

@ -1,8 +1,8 @@
<div class="dialog">
<div class="dialog-header">
<h4> {{'self-hosted Telegram bridge' | translate}} ({{ isAdding ? "Add a new" : "Edit" }})</h4>
</div>
<div class="dialog-content">
<div class="modal-header">
<h4 class="modal-title" id="modal-basic-title">{{'self-hosted Telegram bridge' | translate}} ({{ isAdding ? "Add a new" : "Edit" }})</h4>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close" (click)="modal.close()"></button>
</div>
<div class="modal-body">
<p>{{'Self-hosted Telegram bridges must have' | translate}} <code>{{'provisioning' | translate}}</code> {{'enabled in the configuration.' | translate}}</p>
<label class="label-block">
@ -34,13 +34,12 @@
<ui-switch [checked]="allowMxPuppets" size="small" [disabled]="isSaving"
(change)="allowMxPuppets = !allowMxPuppets"></ui-switch>
</label>
</div>
<div class="dialog-footer">
<button type="button" (click)="add()" title="close" class="btn btn-primary btn-sm">
</div>
<div class="modal-footer">
<button type="button" (click)="add()" title="save" class="btn btn-primary btn-sm">
<i class="far fa-save"></i> {{'Save' | translate}}
</button>
<button type="button" (click)="dialog.close()" title="close" class="btn btn-secondary btn-sm">
<button type="button" (click)="modal.close()" title="close" class="btn btn-secondary btn-sm">
<i class="far fa-times-circle"></i> {{'Cancel' | translate}}
</button>
</div>
</div>

View File

@ -1,43 +1,37 @@
import { Component } from "@angular/core";
import { NgbActiveModal } from "@ng-bootstrap/ng-bootstrap";
import { ToasterService } from "angular2-toaster";
import { DialogRef, ModalComponent } from "ngx-modialog";
import { BSModalContext } from "ngx-modialog/plugins/bootstrap";
import { AdminTelegramApiService } from "../../../../shared/services/admin/admin-telegram-api.service";
import { TranslateService } from "@ngx-translate/core";
export class ManageSelfhostedTelegramBridgeDialogContext extends BSModalContext {
public provisionUrl: string;
public sharedSecret: string;
public allowTgPuppets = false;
public allowMxPuppets = false;
public bridgeId: number;
export interface ManageSelfhostedTelegramBridgeDialogContext {
provisionUrl: string;
sharedSecret: string;
allowTgPuppets: boolean;
allowMxPuppets: boolean;
bridgeId: number;
isAdding: boolean;
}
@Component({
templateUrl: "./manage-selfhosted.component.html",
styleUrls: ["./manage-selfhosted.component.scss"],
})
export class AdminTelegramBridgeManageSelfhostedComponent implements ModalComponent<ManageSelfhostedTelegramBridgeDialogContext> {
export class AdminTelegramBridgeManageSelfhostedComponent {
public isSaving = false;
public provisionUrl: string;
public sharedSecret: string;
public allowTgPuppets = false;
public allowMxPuppets = false;
public bridgeId: number;
public isAdding = false;
isSaving = false;
provisionUrl: string;
sharedSecret: string;
allowTgPuppets = false;
allowMxPuppets = false;
bridgeId: number;
isAdding = true;
constructor(public dialog: DialogRef<ManageSelfhostedTelegramBridgeDialogContext>,
constructor(public modal: NgbActiveModal,
private telegramApi: AdminTelegramApiService,
private toaster: ToasterService,
public translate: TranslateService) {
this.translate = translate;
this.provisionUrl = dialog.context.provisionUrl;
this.sharedSecret = dialog.context.sharedSecret;
this.allowTgPuppets = dialog.context.allowTgPuppets;
this.allowMxPuppets = dialog.context.allowMxPuppets;
this.bridgeId = dialog.context.bridgeId;
this.isAdding = !this.bridgeId;
}
public add() {
@ -49,7 +43,7 @@ export class AdminTelegramBridgeManageSelfhostedComponent implements ModalCompon
if (this.isAdding) {
this.telegramApi.newSelfhosted(this.provisionUrl, this.sharedSecret, options).then(() => {
this.translate.get('Telegram bridge added').subscribe((res: string) => {this.toaster.pop("success", res); });
this.dialog.close();
this.modal.close();
}).catch(err => {
console.error(err);
this.isSaving = false;
@ -58,7 +52,7 @@ export class AdminTelegramBridgeManageSelfhostedComponent implements ModalCompon
} else {
this.telegramApi.updateSelfhosted(this.bridgeId, this.provisionUrl, this.sharedSecret, options).then(() => {
this.translate.get('Telegram bridge updated').subscribe((res: string) => {this.toaster.pop("success", res); });
this.dialog.close();
this.modal.close();
}).catch(err => {
console.error(err);
this.isSaving = false;

View File

@ -1,6 +1,5 @@
import { Component, OnInit } from "@angular/core";
import { ToasterService } from "angular2-toaster";
import { Modal, overlayConfigFactory } from "ngx-modialog";
import {
AdminTelegramBridgeManageSelfhostedComponent,
ManageSelfhostedTelegramBridgeDialogContext
@ -8,6 +7,7 @@ import {
import { FE_TelegramBridge } from "../../../shared/models/telegram";
import { AdminTelegramApiService } from "../../../shared/services/admin/admin-telegram-api.service";
import { TranslateService } from "@ngx-translate/core";
import { NgbModal } from "@ng-bootstrap/ng-bootstrap";
@Component({
templateUrl: "./telegram.component.html",
@ -21,7 +21,7 @@ export class AdminTelegramBridgeComponent implements OnInit {
constructor(private telegramApi: AdminTelegramApiService,
private toaster: ToasterService,
private modal: Modal,
private modal: NgbModal,
public translate: TranslateService) {
this.translate = translate;
}
@ -40,19 +40,23 @@ export class AdminTelegramBridgeComponent implements OnInit {
}
public addSelfHostedBridge() {
this.modal.open(AdminTelegramBridgeManageSelfhostedComponent, overlayConfigFactory({
isBlocking: true,
const selfhostedRef = this.modal.open(AdminTelegramBridgeManageSelfhostedComponent, {
backdrop: 'static',
size: 'lg',
provisionUrl: '',
sharedSecret: '',
allowPuppets: false,
}, ManageSelfhostedTelegramBridgeDialogContext)).result.then(() => {
this.reload().catch(err => {
});
selfhostedRef.result.then(() => {
try {
this.reload()
} catch (err) {
console.error(err);
this.translate.get('Failed to get an update Telegram bridge list').subscribe((res: string) => {this.toaster.pop("error", res); });
});
});
}
})
const selfhostedInstance = selfhostedRef.componentInstance as ManageSelfhostedTelegramBridgeDialogContext;
selfhostedInstance.provisionUrl = '';
selfhostedInstance.sharedSecret = '';
selfhostedInstance.allowMxPuppets = false;
selfhostedInstance.allowTgPuppets = false;
}
public getEnabledFeaturesString(bridge: FE_TelegramBridge): string {
@ -63,20 +67,24 @@ export class AdminTelegramBridgeComponent implements OnInit {
}
public editBridge(bridge: FE_TelegramBridge) {
this.modal.open(AdminTelegramBridgeManageSelfhostedComponent, overlayConfigFactory({
isBlocking: true,
const selfhostedRef = this.modal.open(AdminTelegramBridgeManageSelfhostedComponent, {
backdrop: 'static',
size: 'lg',
provisionUrl: bridge.provisionUrl,
sharedSecret: bridge.sharedSecret,
allowTgPuppets: bridge.options ? bridge.options.allowTgPuppets : false,
allowMxPuppets: bridge.options ? bridge.options.allowMxPuppets : false,
bridgeId: bridge.id,
}, ManageSelfhostedTelegramBridgeDialogContext)).result.then(() => {
this.reload().catch(err => {
});
selfhostedRef.result.then(() => {
try {
this.reload()
} catch (err) {
console.error(err);
this.translate.get('Failed to get an update Telegram bridge list').subscribe((res: string) => {this.toaster.pop("error", res); });
});
});
}
})
const selfhostedInstance = selfhostedRef.componentInstance as ManageSelfhostedTelegramBridgeDialogContext;
selfhostedInstance.provisionUrl = bridge.provisionUrl;
selfhostedInstance.sharedSecret = bridge.sharedSecret;
selfhostedInstance.allowMxPuppets = bridge.options?.allowTgPuppets || false;
selfhostedInstance.allowTgPuppets = bridge.options?.allowMxPuppets || false;
selfhostedInstance.bridgeId = bridge.id;
selfhostedInstance.isAdding = !bridge.id;
}
}

View File

@ -1,8 +1,8 @@
<div class="dialog">
<div class="dialog-header">
<h4> {{'self-hosted webhook bridge' | translate}} ({{ isAdding ? "Add a new" : "Edit" }})</h4>
</div>
<div class="dialog-content">
<div class="modal-header">
<h4 class="modal-title" id="modal-basic-title">{{'self-hosted webhook bridge' | translate}} ({{ isAdding ? "Add a new" : "Edit" }})</h4>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close" (click)="modal.close()"></button>
</div>
<div class="modal-body">
<p>{{'Self-hosted webhook bridges must have' | translate}} <code>{{'provisioning' | translate}}</code> {{'enabled in the configuration.' | translate}}</p>
<label class="label-block">
@ -20,13 +20,12 @@
placeholder="some_secret_value"
[(ngModel)]="sharedSecret" [disabled]="isSaving"/>
</label>
</div>
<div class="dialog-footer">
<button type="button" (click)="add()" title="close" class="btn btn-primary btn-sm">
</div>
<div class="modal-footer">
<button type="button" (click)="add()" title="save" class="btn btn-primary btn-sm">
<i class="far fa-save"></i> {{'Save' | translate}}
</button>
<button type="button" (click)="dialog.close()" title="close" class="btn btn-secondary btn-sm">
<button type="button" (click)="modal.close()" title="close" class="btn btn-secondary btn-sm">
<i class="far fa-times-circle"></i> {{'Cancel' | translate}}
</button>
</div>
</div>

View File

@ -1,39 +1,37 @@
import { Component } from "@angular/core";
import { NgbActiveModal } from "@ng-bootstrap/ng-bootstrap";
import { ToasterService } from "angular2-toaster";
import { DialogRef, ModalComponent } from "ngx-modialog";
import { BSModalContext } from "ngx-modialog/plugins/bootstrap";
import { AdminWebhooksApiService } from "../../../../shared/services/admin/admin-webhooks-api.service";
import { TranslateService } from "@ngx-translate/core";
export class ManageSelfhostedWebhooksBridgeDialogContext extends BSModalContext {
public provisionUrl: string;
public sharedSecret: string;
public allowTgPuppets = false;
public allowMxPuppets = false;
public bridgeId: number;
export interface ManageSelfhostedWebhooksBridgeDialogContext {
provisionUrl: string;
sharedSecret: string;
allowTgPuppets: boolean;
allowMxPuppets: boolean;
bridgeId: number;
isAdding: boolean;
}
@Component({
templateUrl: "./manage-selfhosted.component.html",
styleUrls: ["./manage-selfhosted.component.scss"],
})
export class AdminWebhooksBridgeManageSelfhostedComponent implements ModalComponent<ManageSelfhostedWebhooksBridgeDialogContext> {
export class AdminWebhooksBridgeManageSelfhostedComponent {
public isSaving = false;
public provisionUrl: string;
public sharedSecret: string;
public provisionUrl: '';
public sharedSecret: '';
public allowTgPuppets = false;
public allowMxPuppets = false;
public bridgeId: number;
public isAdding = false;
public isAdding = true;
constructor(public dialog: DialogRef<ManageSelfhostedWebhooksBridgeDialogContext>,
constructor(public modal: NgbActiveModal,
private webhooksApi: AdminWebhooksApiService,
private toaster: ToasterService,
public translate: TranslateService) {
this.translate = translate;
this.provisionUrl = dialog.context.provisionUrl;
this.sharedSecret = dialog.context.sharedSecret;
this.bridgeId = dialog.context.bridgeId;
this.isAdding = !this.bridgeId;
}
public add() {
@ -41,7 +39,7 @@ export class AdminWebhooksBridgeManageSelfhostedComponent implements ModalCompon
if (this.isAdding) {
this.webhooksApi.newSelfhosted(this.provisionUrl, this.sharedSecret).then(() => {
this.translate.get('Webhook bridge added').subscribe((res: string) => {this.toaster.pop("success", res); });
this.dialog.close();
this.modal.close();
}).catch(err => {
console.error(err);
this.isSaving = false;
@ -50,7 +48,7 @@ export class AdminWebhooksBridgeManageSelfhostedComponent implements ModalCompon
} else {
this.webhooksApi.updateSelfhosted(this.bridgeId, this.provisionUrl, this.sharedSecret).then(() => {
this.translate.get('Webhook bridge updated').subscribe((res: string) => {this.toaster.pop("success", res); });
this.dialog.close();
this.modal.close();
}).catch(err => {
console.error(err);
this.isSaving = false;

View File

@ -1,6 +1,5 @@
import { Component, OnInit } from "@angular/core";
import { ToasterService } from "angular2-toaster";
import { Modal, overlayConfigFactory } from "ngx-modialog";
import {
AdminWebhooksBridgeManageSelfhostedComponent,
ManageSelfhostedWebhooksBridgeDialogContext
@ -8,6 +7,7 @@ import {
import { FE_WebhooksBridge } from "../../../shared/models/webhooks";
import { AdminWebhooksApiService } from "../../../shared/services/admin/admin-webhooks-api.service";
import { TranslateService } from "@ngx-translate/core";
import { NgbModal } from "@ng-bootstrap/ng-bootstrap";
@Component({
templateUrl: "./webhooks.component.html",
@ -21,7 +21,7 @@ export class AdminWebhooksBridgeComponent implements OnInit {
constructor(private webhooksApi: AdminWebhooksApiService,
private toaster: ToasterService,
private modal: Modal,
private modal: NgbModal,
public translate: TranslateService) {
this.translate = translate;
}
@ -40,34 +40,42 @@ export class AdminWebhooksBridgeComponent implements OnInit {
}
public addSelfHostedBridge() {
this.modal.open(AdminWebhooksBridgeManageSelfhostedComponent, overlayConfigFactory({
isBlocking: true,
const selfhostedRef = this.modal.open(AdminWebhooksBridgeManageSelfhostedComponent, {
backdrop: 'static',
size: 'lg',
provisionUrl: '',
sharedSecret: '',
allowPuppets: false,
}, ManageSelfhostedWebhooksBridgeDialogContext)).result.then(() => {
this.reload().catch(err => {
});
selfhostedRef.result.then(() => {
try {
this.reload()
} catch (err) {
console.error(err);
this.translate.get('Failed to get an update Webhooks bridge list').subscribe((res: string) => {this.toaster.pop("error", res); });
}
});
});
const selfhostedInstance = selfhostedRef.componentInstance as ManageSelfhostedWebhooksBridgeDialogContext;
selfhostedInstance.provisionUrl = '';
selfhostedInstance.sharedSecret = '';
selfhostedInstance.allowMxPuppets = false;
selfhostedInstance.allowTgPuppets = false;
}
public editBridge(bridge: FE_WebhooksBridge) {
this.modal.open(AdminWebhooksBridgeManageSelfhostedComponent, overlayConfigFactory({
isBlocking: true,
const selfhostedRef = this.modal.open(AdminWebhooksBridgeManageSelfhostedComponent, {
backdrop: 'static',
size: 'lg',
provisionUrl: bridge.provisionUrl,
sharedSecret: bridge.sharedSecret,
bridgeId: bridge.id,
}, ManageSelfhostedWebhooksBridgeDialogContext)).result.then(() => {
this.reload().catch(err => {
});
selfhostedRef.result.then(() => {
try {
this.reload()
} catch (err) {
console.error(err);
this.translate.get('Failed to get an update Webhooks bridge list').subscribe((res: string) => {this.toaster.pop("error", res); });
}
});
});
const selfhostedInstance = selfhostedRef.componentInstance as ManageSelfhostedWebhooksBridgeDialogContext;
selfhostedInstance.provisionUrl = bridge.provisionUrl;
selfhostedInstance.sharedSecret = bridge.sharedSecret
selfhostedInstance.bridgeId = bridge.id;
selfhostedInstance.isAdding = !bridge.id;
}
}

View File

@ -1,8 +1,8 @@
<div class="dialog">
<div class="dialog-header">
<h4>{{ isAdding ? "Add a new" : "Edit" }} {{ 'custom bot' | translate}}</h4>
</div>
<div class="dialog-content">
<div class="modal-header">
<h4 class="modal-title" id="modal-basic-title">{{ isAdding ? "Add a new" : "Edit" }} {{ 'custom bot' | translate}}</h4>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close" (click)="modal.close()"></button>
</div>
<div class="modal-body">
<label class="label-block">
User ID
<span class="text-muted">{{'The user ID that Dimension will invite to rooms.' | translate}}</span>
@ -44,13 +44,12 @@
placeholder="MDaX..."
[(ngModel)]="bot.accessToken" [disabled]="isSaving"/>
</label>
</div>
<div class="dialog-footer">
<button type="button" (click)="add()" title="close" class="btn btn-primary btn-sm">
</div>
<div class="modal-footer">
<button type="button" (click)="add()" title="save" class="btn btn-primary btn-sm">
<i class="far fa-save"></i> {{'Save' | translate}}
</button>
<button type="button" (click)="dialog.close()" title="close" class="btn btn-secondary btn-sm">
<i class="far fa-times-circle"></i>{{'Cancel' | translate}}
<button type="button" (click)="modal.close()" title="close" class="btn btn-secondary btn-sm">
<i class="far fa-times-circle"></i> {{'Cancel' | translate}}
</button>
</div>
</div>

View File

@ -1,34 +1,32 @@
import { Component } from "@angular/core";
import { NgbActiveModal } from "@ng-bootstrap/ng-bootstrap";
import { ToasterService } from "angular2-toaster";
import { DialogRef, ModalComponent } from "ngx-modialog";
import { BSModalContext } from "ngx-modialog/plugins/bootstrap";
import { FE_CustomSimpleBot, FE_UserProfile } from "../../../shared/models/admin-responses";
import { AdminCustomSimpleBotsApiService } from "../../../shared/services/admin/admin-custom-simple-bots-api.service";
import { TranslateService } from "@ngx-translate/core";
export class AddCustomBotDialogContext extends BSModalContext {
export interface AddCustomBotDialogContext {
bot: FE_CustomSimpleBot;
isAdding: boolean;
}
@Component({
templateUrl: "./add.component.html",
styleUrls: ["./add.component.scss"],
})
export class AdminAddCustomBotComponent implements ModalComponent<AddCustomBotDialogContext> {
export class AdminAddCustomBotComponent {
public bot: FE_CustomSimpleBot;
public isAdding = false;
public bot = <FE_CustomSimpleBot>{};
public isAdding = true;
public isSaving = false;
private lastProfile: FE_UserProfile;
constructor(public dialog: DialogRef<AddCustomBotDialogContext>,
constructor(public modal: NgbActiveModal,
private botApi: AdminCustomSimpleBotsApiService,
private toaster: ToasterService,
public translate: TranslateService) {
this.translate = translate;
this.bot = this.dialog.context.bot || <FE_CustomSimpleBot>{};
this.isAdding = !this.dialog.context.bot;
}
public loadProfile() {
@ -89,7 +87,7 @@ export class AdminAddCustomBotComponent implements ModalComponent<AddCustomBotDi
promise.then(() => {
this.translate.get('Bot updated').subscribe((res: string) => {this.toaster.pop("success", res); });
this.dialog.close();
this.modal.close();
}).catch(error => {
this.isSaving = false;
console.error(error);

View File

@ -2,9 +2,9 @@ import { Component } from "@angular/core";
import { ToasterService } from "angular2-toaster";
import { FE_CustomSimpleBot } from "../../shared/models/admin-responses";
import { AdminCustomSimpleBotsApiService } from "../../shared/services/admin/admin-custom-simple-bots-api.service";
import { Modal, overlayConfigFactory } from "ngx-modialog";
import { AddCustomBotDialogContext, AdminAddCustomBotComponent } from "./add/add.component";
import { TranslateService } from "@ngx-translate/core";
import { NgbModal } from "@ng-bootstrap/ng-bootstrap";
@Component({
templateUrl: "./custom-bots.component.html",
@ -18,7 +18,7 @@ export class AdminCustomBotsComponent {
constructor(private botApi: AdminCustomSimpleBotsApiService,
private toaster: ToasterService,
private modal: Modal,
private modal: NgbModal,
public translate: TranslateService) {
this.translate = translate;
@ -36,29 +36,36 @@ export class AdminCustomBotsComponent {
}
public addBot() {
this.modal.open(AdminAddCustomBotComponent, overlayConfigFactory({
isBlocking: true,
const selfhostedRef = this.modal.open(AdminAddCustomBotComponent, {
backdrop: 'static',
size: 'lg',
}, AddCustomBotDialogContext)).result.then(() => {
this.reload().catch(err => {
});
selfhostedRef.result.then(() => {
try {
this.reload()
} catch (err) {
console.error(err);
this.translate.get('Failed to get an updated bot list').subscribe((res: string) => {this.toaster.pop("error", res); });
});
}
});
}
public editBot(bot: FE_CustomSimpleBot) {
this.modal.open(AdminAddCustomBotComponent, overlayConfigFactory({
isBlocking: true,
const selfhostedRef = this.modal.open(AdminAddCustomBotComponent, {
backdrop: 'static',
size: 'lg',
bot: bot,
}, AddCustomBotDialogContext)).result.then(() => {
this.reload().catch(err => {
});
selfhostedRef.result.then(() => {
try {
this.reload()
} catch (err) {
console.error(err);
this.translate.get('Failed to get an updated bot list').subscribe((res: string) => {this.toaster.pop("error", res); });
}
});
});
const selfhostedInstance = selfhostedRef.componentInstance as AddCustomBotDialogContext;
selfhostedInstance.bot = bot;
selfhostedInstance.isAdding = !bot;
}
public toggleBot(bot: FE_CustomSimpleBot) {

View File

@ -2,12 +2,11 @@ import { Component } from "@angular/core";
import { AdminApiService } from "../../shared/services/admin/admin-api.service";
import { FE_DimensionConfig } from "../../shared/models/admin-responses";
import { ToasterService } from "angular2-toaster";
import { Modal, overlayConfigFactory } from "ngx-modialog";
import {
AdminLogoutConfirmationDialogComponent,
LogoutConfirmationDialogContext
} from "./logout-confirmation/logout-confirmation.component";
import { TranslateService } from "@ngx-translate/core";
import { NgbModal } from "@ng-bootstrap/ng-bootstrap";
@Component({
templateUrl: "./home.component.html",
@ -20,7 +19,7 @@ export class AdminHomeComponent {
constructor(private adminApi: AdminApiService,
private toaster: ToasterService,
private modal: Modal,
private modal: NgbModal,
public translate: TranslateService) {
this.translate = translate;
adminApi.getConfig().then(config => {
@ -30,16 +29,18 @@ export class AdminHomeComponent {
}
public logoutAll(): void {
this.modal.open(AdminLogoutConfirmationDialogComponent, overlayConfigFactory({
isBlocking: true,
}, LogoutConfirmationDialogContext)).result.then(() => {
this.adminApi.logoutAll().then(() => {
const selfhostedRef = this.modal.open(AdminLogoutConfirmationDialogComponent, {
backdrop: 'static'
});
selfhostedRef.result.then(async () => {
try {
await this.adminApi.logoutAll();
this.translate.get('Everyone has been logged out').subscribe((res: string) => {this.toaster.pop("success", res); });
this.config.sessionInfo.numTokens = 0;
}).catch(err => {
} catch (err) {
console.error(err);
this.translate.get('Error logging everyone out').subscribe((res: string) => {this.toaster.pop("error", res); });
});
}
});
}
}

View File

@ -1,18 +1,17 @@
<div class="dialog">
<div class="dialog-header">
<h4>{{'Logout confirmation' | translate}}</h4>
</div>
<div class="dialog-content">
<div class="modal-header">
<h4 class="modal-title" id="modal-basic-title">{{'Logout confirmation' | translate}}</h4>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close" (click)="modal.close()"></button>
</div>
<div class="modal-body">
<p>
{{'Logging everyone out will disable all known login tokens for Dimension and upstream integration managers. Most clients will automatically re-register for a login token behind the scenes, similar to how a login token was first acquired.' | translate}}
</p>
</div>
<div class="dialog-footer">
<button type="button" (click)="dialog.dismiss()" title="close" class="btn btn-secondary btn-sm">
</div>
<div class="modal-footer">
<button type="button" (click)="modal.dismiss()" title="close" class="btn btn-secondary btn-sm">
<i class="far fa-times-circle"></i> {{'Cancel' | translate}}
</button>
<button type="button" (click)="dialog.close()" title="logout everyone" class="btn btn-danger btn-sm">
<button type="button" (click)="modal.close()" title="logout everyone" class="btn btn-danger btn-sm">
<i class="far fa-times-circle"></i> {{'Logout Everyone' | translate}}
</button>
</div>
</div>

View File

@ -1,16 +1,15 @@
import { Component } from "@angular/core";
import { DialogRef, ModalComponent } from "ngx-modialog";
import { BSModalContext } from "ngx-modialog/plugins/bootstrap";
import { NgbActiveModal } from "@ng-bootstrap/ng-bootstrap";
export class LogoutConfirmationDialogContext extends BSModalContext {
export interface LogoutConfirmationDialogContext {
}
@Component({
templateUrl: "./logout-confirmation.component.html",
styleUrls: ["./logout-confirmation.component.scss"],
})
export class AdminLogoutConfirmationDialogComponent implements ModalComponent<LogoutConfirmationDialogContext> {
export class AdminLogoutConfirmationDialogComponent {
constructor(public dialog: DialogRef<LogoutConfirmationDialogContext>) {
constructor(public modal: NgbActiveModal) {
}
}

View File

@ -3,12 +3,12 @@ import { AdminAppserviceApiService } from "../../../shared/services/admin/admin-
import { AdminNebApiService } from "../../../shared/services/admin/admin-neb-api.service";
import { ToasterService } from "angular2-toaster";
import { ActivatedRoute, Router } from "@angular/router";
import { Modal, overlayConfigFactory } from "ngx-modialog";
import {
AdminNebAppserviceConfigComponent,
AppserviceConfigDialogContext
} from "../appservice-config/appservice-config.component";
import { TranslateService } from "@ngx-translate/core";
import { NgbModal } from "@ng-bootstrap/ng-bootstrap";
@Component({
@ -26,9 +26,9 @@ export class AdminAddSelfhostedNebComponent {
private toaster: ToasterService,
private router: Router,
private activatedRoute: ActivatedRoute,
private modal: Modal,
private modal: NgbModal,
public translate: TranslateService) {
this.translate = translate;
this.translate = translate;{
}
public save(): void {
@ -37,12 +37,14 @@ export class AdminAddSelfhostedNebComponent {
return this.nebApi.newAppserviceConfiguration(this.adminUrl, appservice);
}).then(neb => {
this.translate.get('New go-neb created').subscribe((res: string) => {this.toaster.pop("success", res); });
this.modal.open(AdminNebAppserviceConfigComponent, overlayConfigFactory({
neb: neb,
isBlocking: true,
const selfhostedRef = this.modal.open(AdminNebAppserviceConfigComponent, {
backdrop: 'static',
size: 'lg',
}, AppserviceConfigDialogContext)).result.then(() => this.router.navigate(["../.."], {relativeTo: this.activatedRoute}));
});
selfhostedRef.result.then(() => this.router.navigate(["../.."], {relativeTo: this.activatedRoute}));
const selfhostedInstance = selfhostedRef.componentInstance as AppserviceConfigDialogContext;
selfhostedInstance.neb = neb;
}).catch(err => {
console.error(err);
this.isSaving = false;

View File

@ -1,22 +1,21 @@
<div class="dialog">
<div class="dialog-header">
<h4>{{'go-neb appservice configuration' | translate}}</h4>
</div>
<div class="dialog-content" *ngIf="isLoading">
<div class="modal-header">
<h4 class="modal-title" id="modal-basic-title">{{'go-neb appservice configuration' | translate}}</h4>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close" (click)="modal.close()"></button>
</div>
<div class="modal-body" *ngif="isLoading">
<my-spinner></my-spinner>
</div>
<div class="dialog-content" *ngIf="!isLoading">
</div>
<div class="modal-body" *ngif="!isLoading">
{{'Copy and paste this configuration to' | translate}} <code>appservice-{{appservice.id}}.yaml</code>
{{'on your homeserver and register it as an application service.' | translate}}
<br/>
<pre>{{appserviceConfig}}</pre>
</div>
<div class="dialog-footer" *ngIf="!isLoading">
<button type="button" (click)="dialog.close()" title="save" class="btn btn-primary btn-sm">
<i class="far fa-times-circle"></i> {{'Close' | translate}}
</button>
<button type="button" (click)="test()" title="close" class="btn btn-secondary btn-sm">
</div>
<div class="modal-footer">
<button type="button" (click)="test()" title="save" class="btn btn-primary btn-sm">
<i class="fa fa-exchange-alt"></i> {{'Test Configuration' | translate}}
</button>
</div>
<button type="button" (click)="modal.close()" title="close" class="btn btn-secondary btn-sm">
<i class="far fa-times-circle"></i> {{'Cancel' | translate}}
</button>
</div>

View File

@ -1,32 +1,29 @@
import { Component } from "@angular/core";
import { ToasterService } from "angular2-toaster";
import { DialogRef, ModalComponent } from "ngx-modialog";
import { FE_Appservice, FE_NebConfiguration } from "../../../shared/models/admin-responses";
import { AdminAppserviceApiService } from "../../../shared/services/admin/admin-appservice-api.service";
import { BSModalContext } from "ngx-modialog/plugins/bootstrap";
import { TranslateService } from "@ngx-translate/core";
import { NgbActiveModal } from "@ng-bootstrap/ng-bootstrap";
export class AppserviceConfigDialogContext extends BSModalContext {
public neb: FE_NebConfiguration;
export interface AppserviceConfigDialogContext {
neb: FE_NebConfiguration;
}
@Component({
templateUrl: "./appservice-config.component.html",
styleUrls: ["./appservice-config.component.scss"],
})
export class AdminNebAppserviceConfigComponent implements ModalComponent<AppserviceConfigDialogContext> {
export class AdminNebAppserviceConfigComponent {
public isLoading = true;
public neb: FE_NebConfiguration;
public appservice: FE_Appservice;
constructor(public dialog: DialogRef<AppserviceConfigDialogContext>,
constructor(public modal: NgbActiveModal,
private adminAppserviceApi: AdminAppserviceApiService,
private toaster: ToasterService,
public translate: TranslateService) {
this.translate = translate;
this.neb = dialog.context.neb;
this.adminAppserviceApi.getAppservice(this.neb.appserviceId).then(appservice => {
this.appservice = appservice;
this.isLoading = false;

View File

@ -1,8 +1,7 @@
import { BSModalContext } from "ngx-modialog/plugins/bootstrap";
import { FE_NebConfiguration } from "../../../shared/models/admin-responses";
import { FE_Integration } from "../../../shared/models/integration";
export class NebBotConfigurationDialogContext extends BSModalContext {
public integration: FE_Integration;
public neb: FE_NebConfiguration;
export interface NebBotConfigurationDialogContext {
integration: FE_Integration;
neb: FE_NebConfiguration;
}

View File

@ -1,11 +1,11 @@
<div class="dialog">
<div class="dialog-header">
<h4>{{'Giphy Configuration' | translate}}</h4>
</div>
<div class="dialog-content" *ngIf="isLoading">
<div class="modal-header">
<h4 class="modal-title" id="modal-basic-title">{{'Giphy Configuration' | translate}}</h4>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close" (click)="modal.close()"></button>
</div>
<div class="modal-body" *ngIf="isLoading">
<my-spinner></my-spinner>
</div>
<div class="dialog-content" *ngIf="!isLoading">
</div>
<div class="modal-body" *ngIf="!isLoading">
<label class="label-block">
{{'Api Key' | translate}}
<span class="text-muted ">{{'The API key from' | translate}} <a href="https://developers.giphy.com/" target="_blank">developers.giphy.com</a>.</span>
@ -21,13 +21,12 @@
{{'Use downsized images' | translate}}
</label>
</label>
</div>
<div class="dialog-footer" *ngIf="!isLoading">
</div>
<div class="modal-footer">
<button type="button" (click)="save()" title="save" class="btn btn-primary btn-sm">
<i class="far fa-save"></i> {{'Save' | translate}}
</button>
<button type="button" (click)="dialog.close()" title="close" class="btn btn-secondary btn-sm">
<button type="button" (click)="modal.close()" title="close" class="btn btn-secondary btn-sm">
<i class="far fa-times-circle"></i> {{'Cancel' | translate}}
</button>
</div>
</div>

View File

@ -1,11 +1,10 @@
import { Component, OnInit } from "@angular/core";
import { ToasterService } from "angular2-toaster";
import { DialogRef, ModalComponent } from "ngx-modialog";
import { NebBotConfigurationDialogContext } from "../config-context";
import { AdminNebApiService } from "../../../../shared/services/admin/admin-neb-api.service";
import { FE_NebConfiguration } from "../../../../shared/models/admin-responses";
import { FE_Integration } from "../../../../shared/models/integration";
import { TranslateService } from "@ngx-translate/core";
import { NgbActiveModal } from "@ng-bootstrap/ng-bootstrap";
interface GiphyConfig {
api_key: string;
@ -16,7 +15,7 @@ interface GiphyConfig {
templateUrl: "./giphy.component.html",
styleUrls: ["./giphy.component.scss", "../config-dialog.scss"],
})
export class AdminNebGiphyConfigComponent implements ModalComponent<NebBotConfigurationDialogContext>, OnInit {
export class AdminNebGiphyConfigComponent implements OnInit {
public isLoading = true;
public isUpdating = false;
@ -24,13 +23,11 @@ export class AdminNebGiphyConfigComponent implements ModalComponent<NebBotConfig
public integration: FE_Integration;
public neb: FE_NebConfiguration;
constructor(public dialog: DialogRef<NebBotConfigurationDialogContext>,
constructor(public modal: NgbActiveModal,
private adminNebApi: AdminNebApiService,
private toaster: ToasterService,
public translate: TranslateService) {
this.translate = translate;
this.neb = dialog.context.neb;
this.integration = dialog.context.integration;
}
public ngOnInit() {
@ -47,7 +44,7 @@ export class AdminNebGiphyConfigComponent implements ModalComponent<NebBotConfig
this.isUpdating = true;
this.adminNebApi.setIntegrationConfiguration(this.neb.id, this.integration.type, this.config).then(() => {
this.translate.get('Configuration updated').subscribe((res: string) => {this.toaster.pop("success", res); });
this.dialog.close();
this.modal.close();
}).catch(err => {
this.isUpdating = false;
console.error(err);

View File

@ -1,11 +1,11 @@
<div class="dialog">
<div class="dialog-header">
<h4>{{'Google Configuration' | translate}}</h4>
</div>
<div class="dialog-content" *ngIf="isLoading">
<div class="modal-header">
<h4 class="modal-title" id="modal-basic-title">{{'Google Configuration' | translate}}</h4>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close" (click)="modal.close()"></button>
</div>
<div class="modal-body" *ngIf="isLoading">
<my-spinner></my-spinner>
</div>
<div class="dialog-content" *ngIf="!isLoading">
</div>
<div class="modal-body" *ngIf="!isLoading">
<label class="label-block">
{{'Api Key' | translate}}
<span class="text-muted ">{{'The API key for your Google Application.' | translate}}</span>
@ -14,19 +14,18 @@
[(ngModel)]="config.api_key" [disabled]="isUpdating"/>
</label>
<label class="label-block">
Search Engine ID
{{'Search Engine ID' | translate}}
<span class="text-muted ">{{'The search engine ID' | translate}}</span>
<input type="text" class="form-control"
placeholder="your_cx_id_here"
[(ngModel)]="config.cx" [disabled]="isUpdating"/>
</label>
</div>
<div class="dialog-footer" *ngIf="!isLoading">
</div>
<div class="modal-footer">
<button type="button" (click)="save()" title="save" class="btn btn-primary btn-sm">
<i class="far fa-save"></i> {{'Save' | translate}}
</button>
<button type="button" (click)="dialog.close()" title="close" class="btn btn-secondary btn-sm">
<button type="button" (click)="modal.close()" title="close" class="btn btn-secondary btn-sm">
<i class="far fa-times-circle"></i> {{'Cancel' | translate}}
</button>
</div>
</div>

View File

@ -1,11 +1,10 @@
import { Component, OnInit } from "@angular/core";
import { ToasterService } from "angular2-toaster";
import { DialogRef, ModalComponent } from "ngx-modialog";
import { NebBotConfigurationDialogContext } from "../config-context";
import { AdminNebApiService } from "../../../../shared/services/admin/admin-neb-api.service";
import { FE_NebConfiguration } from "../../../../shared/models/admin-responses";
import { FE_Integration } from "../../../../shared/models/integration";
import { TranslateService } from "@ngx-translate/core";
import { NgbActiveModal } from "@ng-bootstrap/ng-bootstrap";
interface GoogleConfig {
api_key: string;
@ -16,7 +15,7 @@ interface GoogleConfig {
templateUrl: "./google.component.html",
styleUrls: ["./google.component.scss", "../config-dialog.scss"],
})
export class AdminNebGoogleConfigComponent implements ModalComponent<NebBotConfigurationDialogContext>, OnInit {
export class AdminNebGoogleConfigComponent implements OnInit {
public isLoading = true;
public isUpdating = false;
@ -24,13 +23,11 @@ export class AdminNebGoogleConfigComponent implements ModalComponent<NebBotConfi
public integration: FE_Integration;
public neb: FE_NebConfiguration;
constructor(public dialog: DialogRef<NebBotConfigurationDialogContext>,
constructor(public modal: NgbActiveModal,
private adminNebApi: AdminNebApiService,
private toaster: ToasterService,
public translate: TranslateService) {
this.translate = translate;
this.neb = dialog.context.neb;
this.integration = dialog.context.integration;
}
public ngOnInit() {
@ -47,7 +44,7 @@ export class AdminNebGoogleConfigComponent implements ModalComponent<NebBotConfi
this.isUpdating = true;
this.adminNebApi.setIntegrationConfiguration(this.neb.id, this.integration.type, this.config).then(() => {
this.translate.get('Configuration updated').subscribe((res: string) => {this.toaster.pop("success", res); });
this.dialog.close();
this.modal.close();
}).catch(err => {
this.isUpdating = false;
console.error(err);

View File

@ -1,11 +1,11 @@
<div class="dialog">
<div class="dialog-header">
<h4>{{'Guggy Configuration' | translate}}</h4>
</div>
<div class="dialog-content" *ngIf="isLoading">
<div class="modal-header">
<h4 class="modal-title" id="modal-basic-title">{{'Guggy Configuration' | translate}}</h4>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close" (click)="modal.close()"></button>
</div>
<div class="modal-body" *ngIf="isLoading">
<my-spinner></my-spinner>
</div>
<div class="dialog-content" *ngIf="!isLoading">
</div>
<div class="modal-body" *ngIf="!isLoading">
<label class="label-block">
{{'Api Key' | translate}}
<span class="text-muted ">{{'The API key for' | translate}} <a href="http://docs.guggy.com/" target="_blank">Guggy's API</a>.</span>
@ -13,13 +13,12 @@
placeholder="your_api_key_here"
[(ngModel)]="config.api_key" [disabled]="isUpdating"/>
</label>
</div>
<div class="dialog-footer" *ngIf="!isLoading">
</div>
<div class="modal-footer">
<button type="button" (click)="save()" title="save" class="btn btn-primary btn-sm">
<i class="far fa-save"></i> {{'Save' | translate}}
</button>
<button type="button" (click)="dialog.close()" title="close" class="btn btn-secondary btn-sm">
<button type="button" (click)="modal.close()" title="close" class="btn btn-secondary btn-sm">
<i class="far fa-times-circle"></i> {{'Cancel' | translate}}
</button>
</div>
</div>

View File

@ -1,11 +1,10 @@
import { Component, OnInit } from "@angular/core";
import { ToasterService } from "angular2-toaster";
import { DialogRef, ModalComponent } from "ngx-modialog";
import { NebBotConfigurationDialogContext } from "../config-context";
import { AdminNebApiService } from "../../../../shared/services/admin/admin-neb-api.service";
import { FE_NebConfiguration } from "../../../../shared/models/admin-responses";
import { FE_Integration } from "../../../../shared/models/integration";
import { TranslateService } from "@ngx-translate/core";
import { NgbActiveModal } from "@ng-bootstrap/ng-bootstrap";
interface GuggyConfig {
api_key: string;
@ -15,7 +14,7 @@ interface GuggyConfig {
templateUrl: "./guggy.component.html",
styleUrls: ["./guggy.component.scss", "../config-dialog.scss"],
})
export class AdminNebGuggyConfigComponent implements ModalComponent<NebBotConfigurationDialogContext>, OnInit {
export class AdminNebGuggyConfigComponent implements OnInit {
public isLoading = true;
public isUpdating = false;
@ -23,13 +22,11 @@ export class AdminNebGuggyConfigComponent implements ModalComponent<NebBotConfig
public integration: FE_Integration;
public neb: FE_NebConfiguration;
constructor(public dialog: DialogRef<NebBotConfigurationDialogContext>,
constructor(public modal: NgbActiveModal,
private adminNebApi: AdminNebApiService,
private toaster: ToasterService,
public translate: TranslateService) {
this.translate = translate;
this.neb = dialog.context.neb;
this.integration = dialog.context.integration;
}
public ngOnInit() {
@ -46,7 +43,7 @@ export class AdminNebGuggyConfigComponent implements ModalComponent<NebBotConfig
this.isUpdating = true;
this.adminNebApi.setIntegrationConfiguration(this.neb.id, this.integration.type, this.config).then(() => {
this.translate.get('Configuration updated').subscribe((res: string) => {this.toaster.pop("success", res); });
this.dialog.close();
this.modal.close();
}).catch(err => {
this.isUpdating = false;
console.error(err);

View File

@ -1,11 +1,11 @@
<div class="dialog">
<div class="dialog-header">
<h4>{{'Imgur Configuration' | translate}}</h4>
</div>
<div class="dialog-content" *ngIf="isLoading">
<div class="modal-header">
<h4 class="modal-title" id="modal-basic-title">{{'Imgur Configuration' | translate}}</h4>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close" (click)="modal.close()"></button>
</div>
<div class="modal-body" *ngIf="isLoading">
<my-spinner></my-spinner>
</div>
<div class="dialog-content" *ngIf="!isLoading">
</div>
<div class="modal-body" *ngIf="!isLoading">
<label class="label-block">
{{'Client ID' | translate}}
<span class="text-muted ">{{'The client ID of your' | translate}} <a href="https://apidocs.imgur.com/" target="_blank">{{'Imgur Application' | translate}}</a>.</span>
@ -20,13 +20,12 @@
placeholder="your_client_secret"
[(ngModel)]="config.client_secret" [disabled]="isUpdating"/>
</label>
</div>
<div class="dialog-footer" *ngIf="!isLoading">
</div>
<div class="modal-footer">
<button type="button" (click)="save()" title="save" class="btn btn-primary btn-sm">
<i class="far fa-save"></i> {{'Save' | translate}}
</button>
<button type="button" (click)="dialog.close()" title="close" class="btn btn-secondary btn-sm">
<button type="button" (click)="modal.close()" title="close" class="btn btn-secondary btn-sm">
<i class="far fa-times-circle"></i> {{'Cancel' | translate}}
</button>
</div>
</div>

View File

@ -1,11 +1,10 @@
import { Component, OnInit } from "@angular/core";
import { ToasterService } from "angular2-toaster";
import { DialogRef, ModalComponent } from "ngx-modialog";
import { NebBotConfigurationDialogContext } from "../config-context";
import { AdminNebApiService } from "../../../../shared/services/admin/admin-neb-api.service";
import { FE_NebConfiguration } from "../../../../shared/models/admin-responses";
import { FE_Integration } from "../../../../shared/models/integration";
import { TranslateService } from "@ngx-translate/core";
import { NgbActiveModal } from "@ng-bootstrap/ng-bootstrap";
interface ImgurConfig {
client_id: string;
@ -16,7 +15,7 @@ interface ImgurConfig {
templateUrl: "./imgur.component.html",
styleUrls: ["./imgur.component.scss", "../config-dialog.scss"],
})
export class AdminNebImgurConfigComponent implements ModalComponent<NebBotConfigurationDialogContext>, OnInit {
export class AdminNebImgurConfigComponent implements OnInit {
public isLoading = true;
public isUpdating = false;
@ -24,13 +23,11 @@ export class AdminNebImgurConfigComponent implements ModalComponent<NebBotConfig
public integration: FE_Integration;
public neb: FE_NebConfiguration;
constructor(public dialog: DialogRef<NebBotConfigurationDialogContext>,
constructor(public modal: NgbActiveModal,
private adminNebApi: AdminNebApiService,
private toaster: ToasterService,
public translate: TranslateService) {
this.translate = translate;
this.neb = dialog.context.neb;
this.integration = dialog.context.integration;
}
public ngOnInit() {
@ -47,7 +44,7 @@ export class AdminNebImgurConfigComponent implements ModalComponent<NebBotConfig
this.isUpdating = true;
this.adminNebApi.setIntegrationConfiguration(this.neb.id, this.integration.type, this.config).then(() => {
this.translate.get('Configuration updated').subscribe((res: string) => {this.toaster.pop("success", res); });
this.dialog.close();
this.modal.close();
}).catch(err => {
this.isUpdating = false;
console.error(err);

View File

@ -5,14 +5,13 @@ import { ActivatedRoute } from "@angular/router";
import { ToasterService } from "angular2-toaster";
import { FE_Integration } from "../../../shared/models/integration";
import { NEB_HAS_CONFIG, NEB_IS_COMPLEX } from "../../../shared/models/neb";
import { ContainerContent, Modal, overlayConfigFactory } from "ngx-modialog";
import { AdminNebGiphyConfigComponent } from "../config/giphy/giphy.component";
import { NebBotConfigurationDialogContext } from "../config/config-context";
import { AdminNebGuggyConfigComponent } from "../config/guggy/guggy.component";
import { AdminNebGoogleConfigComponent } from "../config/google/google.component";
import { AdminNebImgurConfigComponent } from "../config/imgur/imgur.component";
import { TranslateService } from "@ngx-translate/core";
import { NgbModal } from "@ng-bootstrap/ng-bootstrap";
@Component({
templateUrl: "./edit.component.html",
@ -30,7 +29,7 @@ export class AdminEditNebComponent implements OnInit, OnDestroy {
constructor(private nebApi: AdminNebApiService,
private route: ActivatedRoute,
private modal: Modal,
private modal: NgbModal,
private toaster: ToasterService,
public translate: TranslateService) {
this.translate = translate;
@ -87,7 +86,7 @@ export class AdminEditNebComponent implements OnInit, OnDestroy {
}
public editBot(bot: FE_Integration) {
let component: ContainerContent;
let component;
if (bot.type === "giphy") component = AdminNebGiphyConfigComponent;
if (bot.type === "guggy") component = AdminNebGuggyConfigComponent;
@ -95,13 +94,13 @@ export class AdminEditNebComponent implements OnInit, OnDestroy {
if (bot.type === "imgur") component = AdminNebImgurConfigComponent;
if (!component) throw new Error("No config component for " + bot.type);
this.modal.open(component, overlayConfigFactory({
neb: this.nebConfig,
integration: bot,
isBlocking: true,
const nebBotRef = this.modal.open(component, {
backdrop: 'static',
size: 'lg',
}, NebBotConfigurationDialogContext));
});
const nebBotInstance = nebBotRef.componentInstance as NebBotConfigurationDialogContext;
nebBotInstance.neb = this.nebConfig;
nebBotInstance.integration = bot;
}
private loadNeb(nebId: number) {

View File

@ -9,8 +9,8 @@ import {
AdminNebAppserviceConfigComponent,
AppserviceConfigDialogContext
} from "./appservice-config/appservice-config.component";
import { Modal, overlayConfigFactory } from "ngx-modialog";
import { TranslateService } from "@ngx-translate/core";
import { NgbModal } from "@ng-bootstrap/ng-bootstrap";
@Component({
templateUrl: "./neb.component.html",
@ -31,7 +31,7 @@ export class AdminNebComponent {
private toaster: ToasterService,
private router: Router,
private activatedRoute: ActivatedRoute,
private modal: Modal,
private modal: NgbModal,
public translate: TranslateService) {
this.translate = translate;
@ -77,12 +77,12 @@ export class AdminNebComponent {
}
public showAppserviceConfig(neb: FE_NebConfiguration) {
this.modal.open(AdminNebAppserviceConfigComponent, overlayConfigFactory({
neb: neb,
isBlocking: true,
const selfhostedRef = this.modal.open(AdminNebAppserviceConfigComponent, {
backdrop: 'static',
size: 'lg',
}, AppserviceConfigDialogContext));
});
const selfhostedInstance = selfhostedRef.componentInstance as AppserviceConfigDialogContext;
selfhostedInstance.neb = neb;
}
public getEnabledBotsString(neb: FE_NebConfiguration): string {

View File

@ -1,8 +1,8 @@
<div class="dialog">
<div class="dialog-header">
<h4>Sticker Pack: {{ pack.displayName }}</h4>
</div>
<div class="dialog-content">
<div class="modal-header">
<h4 class="modal-title" id="modal-basic-title">Sticker Pack: {{ pack.displayName }}</h4>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close" (click)="modal.close()"></button>
</div>
<div class="modal-body">
<div class="sticker" *ngFor="let sticker of pack.stickers trackById">
<img [src]="getThumbnailUrl(sticker.thumbnail.mxc, 120, 120)" width="120" height="120"/>
<div class="caption">
@ -10,10 +10,7 @@
<span class="description">{{ sticker.description }}</span>
</div>
</div>
</div>
<div class="dialog-footer">
<button type="button" (click)="dialog.close()" title="close" class="btn btn-secondary btn-sm">
<i class="far fa-times-circle"></i> {{'Close' | translate}}
</button>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-outline-secondary" (click)="modal.close()"><i class="far fa-times-circle"></i> {{'Close' | translate}}</button>
</div>

View File

@ -1,10 +1,9 @@
import { Component } from "@angular/core";
import { FE_StickerPack } from "../../../shared/models/integration";
import { DialogRef, ModalComponent } from "ngx-modialog";
import { BSModalContext } from "ngx-modialog/plugins/bootstrap";
import { MediaService } from "../../../shared/services/media.service";
import { NgbActiveModal } from "@ng-bootstrap/ng-bootstrap";
export class StickerPackPreviewDialogContext extends BSModalContext {
export class StickerPackPreviewMoadlInstance {
public pack: FE_StickerPack;
}
@ -12,12 +11,12 @@ export class StickerPackPreviewDialogContext extends BSModalContext {
templateUrl: "./preview.component.html",
styleUrls: ["./preview.component.scss"],
})
export class AdminStickerPackPreviewComponent implements ModalComponent<StickerPackPreviewDialogContext> {
export class AdminStickerPackPreviewComponent {
public pack: FE_StickerPack;
pack: FE_StickerPack;
constructor(public modal: NgbActiveModal, private media: MediaService) {
constructor(public dialog: DialogRef<StickerPackPreviewDialogContext>, private media: MediaService) {
this.pack = dialog.context.pack;
}
public getThumbnailUrl(mxc: string, width: number, height: number, method: "crop" | "scale" = "scale"): string {

View File

@ -2,8 +2,8 @@ import { Component, OnInit } from "@angular/core";
import { ToasterService } from "angular2-toaster";
import { FE_StickerPack } from "../../shared/models/integration";
import { AdminStickersApiService } from "../../shared/services/admin/admin-stickers-api-service";
import { Modal, overlayConfigFactory } from "ngx-modialog";
import { AdminStickerPackPreviewComponent, StickerPackPreviewDialogContext } from "./preview/preview.component";
import { AdminStickerPackPreviewComponent, StickerPackPreviewMoadlInstance } from "./preview/preview.component";
import { NgbModal } from "@ng-bootstrap/ng-bootstrap";
import { TranslateService } from "@ngx-translate/core";
@Component({
@ -20,7 +20,7 @@ export class AdminStickerPacksComponent implements OnInit {
constructor(private adminStickers: AdminStickersApiService,
private toaster: ToasterService,
private modal: Modal,
private modal: NgbModal,
public translate: TranslateService) {
this.translate = translate;
}
@ -50,12 +50,10 @@ export class AdminStickerPacksComponent implements OnInit {
}
public previewStickers(pack: FE_StickerPack) {
this.modal.open(AdminStickerPackPreviewComponent, overlayConfigFactory({
pack: pack,
const modalRef = this.modal.open(AdminStickerPackPreviewComponent, { size: 'lg' });
const previewInstance = modalRef.componentInstance as StickerPackPreviewMoadlInstance;
isBlocking: false,
size: 'lg',
}, StickerPackPreviewDialogContext));
previewInstance.pack = pack;
}
public startTelegramImport() {

View File

@ -4,12 +4,11 @@ import { AdminTermsApiService } from "../../../shared/services/admin/admin-terms
import { ActivatedRoute, Router } from "@angular/router";
import * as ClassicEditor from '@ckeditor/ckeditor5-build-classic';
import ISO6391 from "iso-639-1";
import { Modal, overlayConfigFactory } from "ngx-modialog";
import {
AdminTermsNewEditPublishDialogComponent,
AdminTermsNewEditPublishDialogContext
} from "./publish/publish.component";
import { TranslateService } from "@ngx-translate/core";
import { NgbModal } from "@ng-bootstrap/ng-bootstrap";
interface ILanguage {
name: string,
@ -67,7 +66,7 @@ export class AdminNewEditTermsComponent implements OnInit {
private toaster: ToasterService,
private router: Router,
private activatedRoute: ActivatedRoute,
private modal: Modal,
private modal: NgbModal,
public translate: TranslateService) {
this.translate = translate;
}
@ -119,11 +118,11 @@ export class AdminNewEditTermsComponent implements OnInit {
url: `${window.location.origin}/widgets/terms/${this.shortcode}/en/draft`,
});
this.modal.open(AdminTermsNewEditPublishDialogComponent, overlayConfigFactory({
isBlocking: true,
const termsEditRef = this.modal.open(AdminTermsNewEditPublishDialogComponent, {
backdrop: 'static',
size: 'sm',
}, AdminTermsNewEditPublishDialogContext)).result.then(async (val) => {
});
termsEditRef.result.then(async (val) => {
if (!val) return; // closed without publish
try {

View File

@ -1,20 +1,19 @@
<div class="dialog">
<div class="dialog-header">
<h4>{{'Publish policy' | translate}}</h4>
</div>
<div class="dialog-content">
<div class="modal-header">
<h4 class="modal-title" id="modal-basic-title">{{'Publish policy' | translate}}</h4>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close" (click)="modal.close()"></button>
</div>
<div class="modal-body">
<label class="label-block">
{{'Version number' | translate}}
<span class="text-muted ">{{'The version number of this policy' | translate}}</span>
<input type="text" class="form-control" placeholder="eg: 1.1.0" [(ngModel)]="version"/>
</label>
</div>
<div class="dialog-footer">
</div>
<div class="modal-footer">
<button type="button" (click)="publish()" title="close" class="btn btn-primary btn-sm">
<i class="fas fa-upload"></i> {{'Publish' | translate}}
</button>
<button type="button" (click)="dialog.close()" title="save" class="btn btn-secondary btn-sm">
<button type="button" (click)="modal.close()" title="close" class="btn btn-secondary btn-sm">
<i class="far fa-times-circle"></i> {{'Close' | translate}}
</button>
</div>
</div>

View File

@ -1,21 +1,20 @@
import { Component } from "@angular/core";
import { DialogRef, ModalComponent } from "ngx-modialog";
import { BSModalContext } from "ngx-modialog/plugins/bootstrap";
import { ToasterService } from "angular2-toaster";
import { TranslateService } from "@ngx-translate/core";
import { NgbActiveModal } from "@ng-bootstrap/ng-bootstrap";
export class AdminTermsNewEditPublishDialogContext extends BSModalContext {
export interface AdminTermsNewEditPublishDialogContext {
}
@Component({
templateUrl: "./publish.component.html",
styleUrls: ["./publish.component.scss"],
})
export class AdminTermsNewEditPublishDialogComponent implements ModalComponent<AdminTermsNewEditPublishDialogContext> {
export class AdminTermsNewEditPublishDialogComponent {
public version: string;
constructor(public dialog: DialogRef<AdminTermsNewEditPublishDialogContext>, private toaster: ToasterService, public translate: TranslateService) {
constructor(public modal: NgbActiveModal, private toaster: ToasterService, public translate: TranslateService) {
}
public publish() {
@ -23,6 +22,6 @@ export class AdminTermsNewEditPublishDialogComponent implements ModalComponent<A
this.translate.get('Please enter a version number').subscribe((res: string) => {this.toaster.pop("warning", res); });
return;
}
this.dialog.close(this.version);
this.modal.close(this.version);
}
}

View File

@ -1,8 +1,8 @@
<div class="dialog">
<div class="dialog-header">
<h4>{{'Etherpad Widget Configuration' | translate}}</h4>
</div>
<div class="dialog-content">
<div class="modal-header">
<h4 class="modal-title" id="modal-basic-title">{{'Etherpad Widget Configuration' | translate}}</h4>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close" (click)="modal.close()"></button>
</div>
<div class="modal-body">
<label class="label-block">
{{'Default Pad URL Template' | translate}}
<span class="text-muted ">{{'$padName and $roomId will be replaced during creation to help create a unique pad URL.' | translate}}</span>
@ -10,13 +10,12 @@
placeholder="https://scalar.vector.im/etherpad/p/$padName_$roomId"
[(ngModel)]="widget.options.defaultUrl" [disabled]="isUpdating"/>
</label>
</div>
<div class="dialog-footer">
</div>
<div class="modal-footer">
<button type="button" (click)="save()" title="save" class="btn btn-primary btn-sm">
<i class="far fa-save"></i> {{'Save' | translate}}
</button>
<button type="button" (click)="dialog.close()" title="close" class="btn btn-secondary btn-sm">
<button type="button" (click)="modal.close()" title="close" class="btn btn-secondary btn-sm">
<i class="far fa-times-circle"></i> {{'Cancel' | translate}}
</button>
</div>
</div>

View File

@ -1,27 +1,29 @@
import { Component } from "@angular/core";
import { Component, OnInit } from "@angular/core";
import { FE_EtherpadWidget } from "../../../shared/models/integration";
import { ToasterService } from "angular2-toaster";
import { DialogRef, ModalComponent } from "ngx-modialog";
import { WidgetConfigDialogContext } from "../widgets.component";
import { AdminIntegrationsApiService } from "../../../shared/services/admin/admin-integrations-api.service";
import { TranslateService } from "@ngx-translate/core";
import { NgbActiveModal } from "@ng-bootstrap/ng-bootstrap";
@Component({
templateUrl: "./etherpad.component.html",
styleUrls: ["./etherpad.component.scss", "../config-dialog.scss"],
})
export class AdminWidgetEtherpadConfigComponent implements ModalComponent<WidgetConfigDialogContext> {
export class AdminWidgetEtherpadConfigComponent implements OnInit {
public isUpdating = false;
public widget: FE_EtherpadWidget;
private originalWidget: FE_EtherpadWidget;
private originalWidget = <FE_EtherpadWidget>{};
constructor(public dialog: DialogRef<WidgetConfigDialogContext>,
constructor(public modal: NgbActiveModal,
private adminIntegrationsApi: AdminIntegrationsApiService,
private toaster: ToasterService,
public translate: TranslateService) {
this.translate = translate;
this.originalWidget = dialog.context.widget;
}
ngOnInit() {
this.originalWidget = this.widget;
this.widget = JSON.parse(JSON.stringify(this.originalWidget));
}
@ -30,7 +32,7 @@ export class AdminWidgetEtherpadConfigComponent implements ModalComponent<Widget
this.adminIntegrationsApi.setIntegrationOptions(this.widget.category, this.widget.type, this.widget.options).then(() => {
this.originalWidget.options = this.widget.options;
this.translate.get('Widget updated').subscribe((res: string) => {this.toaster.pop("success", res); });
this.dialog.close();
this.modal.close();
}).catch(err => {
this.isUpdating = false;
console.error(err);

View File

@ -1,8 +1,8 @@
<div class="dialog">
<div class="dialog-header">
<h4>{{'Jitsi Widget Configuration' | translate}}</h4>
</div>
<div class="dialog-content">
<div class="modal-header">
<h4 class="modal-title" id="modal-basic-title">{{'Jitsi Widget Configuration' | translate}}</h4>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close" (click)="modal.close()"></button>
</div>
<div class="modal-body">
<label class="label-block">
{{'Jitsi Domain' | translate}}
<span class="text-muted ">{{'This is the domain that is used to host the conference.' | translate}}</span>
@ -23,13 +23,12 @@
placeholder="https://jitsi.riot.im/libs/external_api.min.js"
[(ngModel)]="widget.options.scriptUrl" [disabled]="isUpdating"/>
</label>
</div>
<div class="dialog-footer">
</div>
<div class="modal-footer">
<button type="button" (click)="save()" title="save" class="btn btn-primary btn-sm">
<i class="far fa-save"></i> {{'Save' | translate}}
</button>
<button type="button" (click)="dialog.close()" title="close" class="btn btn-secondary btn-sm">
<button type="button" (click)="modal.close()" title="close" class="btn btn-secondary btn-sm">
<i class="far fa-times-circle"></i> {{'Cancel' | translate}}
</button>
</div>
</div>

View File

@ -1,24 +1,29 @@
import { Component } from "@angular/core";
import { Component, OnInit } from "@angular/core";
import { FE_JitsiWidget } from "../../../shared/models/integration";
import { ToasterService } from "angular2-toaster";
import { DialogRef, ModalComponent } from "ngx-modialog";
import { WidgetConfigDialogContext } from "../widgets.component";
import { AdminIntegrationsApiService } from "../../../shared/services/admin/admin-integrations-api.service";
import { TranslateService } from "@ngx-translate/core";
import { NgbActiveModal } from "@ng-bootstrap/ng-bootstrap";
@Component({
templateUrl: "./jitsi.component.html",
styleUrls: ["./jitsi.component.scss", "../config-dialog.scss"],
})
export class AdminWidgetJitsiConfigComponent implements ModalComponent<WidgetConfigDialogContext> {
export class AdminWidgetJitsiConfigComponent implements OnInit {
public isUpdating = false;
public widget: FE_JitsiWidget;
private originalWidget: FE_JitsiWidget;
private originalWidget = <FE_JitsiWidget>{};
constructor(public dialog: DialogRef<WidgetConfigDialogContext>, private adminIntegrationsApi: AdminIntegrationsApiService, private toaster: ToasterService, public translate: TranslateService) {
constructor(public modal: NgbActiveModal,
private adminIntegrationsApi: AdminIntegrationsApiService,
private toaster: ToasterService,
public translate: TranslateService) {
this.translate = translate;
this.originalWidget = dialog.context.widget;
}
ngOnInit() {
this.originalWidget = this.widget;
this.widget = JSON.parse(JSON.stringify(this.originalWidget));
// Fix the ui-switch not picking up a boolean value
@ -30,7 +35,7 @@ export class AdminWidgetJitsiConfigComponent implements ModalComponent<WidgetCon
this.adminIntegrationsApi.setIntegrationOptions(this.widget.category, this.widget.type, this.widget.options).then(() => {
this.originalWidget.options = this.widget.options;
this.translate.get('Widget updated').subscribe((res: string) => {this.toaster.pop("success", res); });
this.dialog.close();
this.modal.close();
}).catch(err => {
this.isUpdating = false;
console.error(err);

View File

@ -1,22 +1,20 @@
<div class="dialog">
<div class="dialog-header">
<h4>Whiteboard Widget Configuration</h4>
</div>
<div class="dialog-content">
<label class="label-block">
<div class="modal-header">
<h4 class="modal-title" id="modal-basic-title">Whiteboard Widget Configuration</h4>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close" (click)="modal.close()"></button>
</div>
<div class="modal-body">
Default Board URL Template
<span class="text-muted ">$boardName and $roomId will be replaced during creation to help create a unique pad URL.</span>
<input type="text" class="form-control"
placeholder="https://cloud13.de/testwhiteboard/?whiteboardid=$roomId_$boardName"
[(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>
</label>
</div>
<div class="modal-footer">
<button type="button" (click)="save()" title="save" class="btn btn-primary btn-sm">
<i class="far fa-save"></i> {{'Save' | translate}}
</button>
<button type="button" (click)="modal.close()" title="close" class="btn btn-secondary btn-sm">
<i class="far fa-times-circle"></i> {{'Cancel' | translate}}
</button>
</div>

View File

@ -1,22 +1,29 @@
import { Component } from "@angular/core";
import { Component, OnInit } from "@angular/core";
import { FE_WhiteBoardWidget } from "../../../shared/models/integration";
import { ToasterService } from "angular2-toaster";
import { DialogRef, ModalComponent } from "ngx-modialog";
import { WidgetConfigDialogContext } from "../widgets.component";
import { TranslateService } from "@ngx-translate/core";
import { NgbActiveModal } from "@ng-bootstrap/ng-bootstrap";
import { AdminIntegrationsApiService } from "../../../shared/services/admin/admin-integrations-api.service";
@Component({
templateUrl: "./whiteboard.component.html",
styleUrls: ["./whiteboard.component.scss", "../config-dialog.scss"],
})
export class AdminWidgetWhiteboardConfigComponent implements ModalComponent<WidgetConfigDialogContext> {
export class AdminWidgetWhiteboardConfigComponent implements OnInit {
public isUpdating = false;
public widget: FE_WhiteBoardWidget;
private originalWidget: FE_WhiteBoardWidget;
constructor(public dialog: DialogRef<WidgetConfigDialogContext>, private adminIntegrationsApi: AdminIntegrationsApiService, private toaster: ToasterService) {
this.originalWidget = dialog.context.widget;
constructor(public modal: NgbActiveModal,
private adminIntegrationsApi: AdminIntegrationsApiService,
private toaster: ToasterService,
public translate: TranslateService) {
this.translate = translate;
}
ngOnInit() {
this.originalWidget = this.widget;
this.widget = JSON.parse(JSON.stringify(this.originalWidget));
}
@ -25,7 +32,7 @@ export class AdminWidgetWhiteboardConfigComponent implements ModalComponent<Widg
this.adminIntegrationsApi.setIntegrationOptions(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();
this.modal.close();
}).catch(err => {
this.isUpdating = false;
console.error(err);

View File

@ -2,15 +2,14 @@ import { Component } from "@angular/core";
import { FE_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";
import { AdminIntegrationsApiService } from "../../shared/services/admin/admin-integrations-api.service";
import { AdminWidgetWhiteboardConfigComponent } from "./whiteboard/whiteboard.component";
import { TranslateService } from "@ngx-translate/core";
import { NgbModal } from "@ng-bootstrap/ng-bootstrap";
export class WidgetConfigDialogContext extends BSModalContext {
public widget: FE_Widget;
export interface WidgetConfigDialogContext {
widget: FE_Widget;
}
@Component({
@ -23,7 +22,7 @@ export class AdminWidgetsComponent {
public isUpdating = false;
public widgets: FE_Widget[];
constructor(private adminIntegrationsApi: AdminIntegrationsApiService, private toaster: ToasterService, private modal: Modal, public translate: TranslateService) {
constructor(private adminIntegrationsApi: AdminIntegrationsApiService, private toaster: ToasterService, private modal: NgbModal, public translate: TranslateService) {
this.translate = translate;
this.adminIntegrationsApi.getAllWidgets().then(widgets => {
this.isLoading = false;
@ -61,12 +60,11 @@ export class AdminWidgetsComponent {
return;
}
this.modal.open(component, overlayConfigFactory({
widget: widget,
isBlocking: true,
size: 'lg',
}, WidgetConfigDialogContext));
const widgetConfigRef = this.modal.open(component, {
backdrop: 'static'
});
const widgetConfigInterface = widgetConfigRef.componentInstance as WidgetConfigDialogContext;
widgetConfigInterface.widget = widget;
}
public hasConfiguration(widget: FE_Widget) {

View File

@ -1,6 +1,4 @@
import { ApplicationRef, Injector, NgModule } from "@angular/core";
import { ModalModule } from "ngx-modialog";
import { BootstrapModalModule } from "ngx-modialog/plugins/bootstrap";
import { BreadcrumbModule } from "xng-breadcrumb";
import { BrowserAnimationsModule } from "@angular/platform-browser/animations";
import { UiSwitchModule } from "ngx-ui-switch";
@ -137,9 +135,7 @@ export function HttpLoaderFactory(http: HttpClient) {
UiSwitchModule,
ToasterModule,
BrowserAnimationsModule,
ModalModule.forRoot(),
BootstrapModalModule,
BreadcrumbsModule,
BreadcrumbModule,
CKEditorModule,
FontAwesomeModule,
TranslateModule.forRoot({

View File

@ -1,17 +1,15 @@
<div class="dialog">
<div class="dialog-header">
<h4>{{'Telegram chat is already bridged' | translate}}</h4>
</div>
<div class="dialog-content">
<div class="modal-header">
<h4 class="modal-title" id="modal-basic-title">{{'Telegram chat is already bridged' | translate}}</h4>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close" (click)="modal.close()"></button>
</div>
<div class="modal-body">
{{'You have the appropriate permissions to be able to unbridge the chat, however. Would you like to unbridge the other room and instead bridge it here?' | translate}}
</div>
<div class="dialog-footer">
<button type="button" (click)="unbridgeAndContinue()" title="unbridge and continue"
class="btn btn-danger btn-sm">
</div>
<div class="modal-footer">
<button type="button" (click)="unbridgeAndContinue()" title="unbridge and continue" class="btn btn-danger btn-sm">
{{'Unbridge and continue' | translate}}
</button>
<button type="button" (click)="cancel()" title="cancel" class="btn btn-primary btn-sm">
<i class="far fa-times-circle"></i> {{'No, don\'t bridge' | translate}}
</button>
</div>
</div>

View File

@ -1,24 +1,23 @@
import { Component } from "@angular/core";
import { DialogRef, ModalComponent } from "ngx-modialog";
import { BSModalContext } from "ngx-modialog/plugins/bootstrap";
import { NgbActiveModal } from "@ng-bootstrap/ng-bootstrap";
export class AskUnbridgeDialogContext extends BSModalContext {
export interface AskUnbridgeDialogContext {
}
@Component({
templateUrl: "./ask-unbridge.component.html",
styleUrls: ["./ask-unbridge.component.scss"],
})
export class TelegramAskUnbridgeComponent implements ModalComponent<AskUnbridgeDialogContext> {
export class TelegramAskUnbridgeComponent {
constructor(public dialog: DialogRef<AskUnbridgeDialogContext>) {
constructor(public modal: NgbActiveModal) {
}
public unbridgeAndContinue(): void {
this.dialog.close({unbridge: true});
this.modal.close({unbridge: true});
}
public cancel(): void {
this.dialog.close({unbridge: false});
this.modal.close({unbridge: false});
}
}

View File

@ -1,13 +1,12 @@
<div class="dialog">
<div class="dialog-header">
<h4>{{'Telegram chat is already bridged' | translate}}</h4>
</div>
<div class="dialog-content">
<div class="modal-header">
<h4 class="modal-title" id="modal-basic-title">{{'Telegram chat is already bridged' | translate}}</h4>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close" (click)="modal.close()"></button>
</div>
<div class="modal-body">
{{'That Telegram chat is bridged to another Matrix room and cannot be bridged here. Unfortunately, you do not have the required permissions to be able to unbridge the other room.' | translate}}
</div>
<div class="dialog-footer">
<button type="button" (click)="dialog.close()" title="cancel" class="btn btn-primary btn-sm">
</div>
<div class="modal-footer">
<button type="button" (click)="modal.close()" title="close" class="btn btn-primary btn-sm">
<i class="far fa-times-circle"></i> {{'Close' | translate}}
</button>
</div>
</div>

View File

@ -1,16 +1,15 @@
import { Component } from "@angular/core";
import { DialogRef, ModalComponent } from "ngx-modialog";
import { BSModalContext } from "ngx-modialog/plugins/bootstrap";
import { NgbActiveModal } from "@ng-bootstrap/ng-bootstrap";
export class CannotUnbridgeDialogContext extends BSModalContext {
export interface CannotUnbridgeDialogContext {
}
@Component({
templateUrl: "./cannot-unbridge.component.html",
styleUrls: ["./cannot-unbridge.component.scss"],
})
export class TelegramCannotUnbridgeComponent implements ModalComponent<CannotUnbridgeDialogContext> {
export class TelegramCannotUnbridgeComponent {
constructor(public dialog: DialogRef<CannotUnbridgeDialogContext>) {
constructor(public modal: NgbActiveModal) {
}
}

View File

@ -2,13 +2,12 @@ import { Component } from "@angular/core";
import { BridgeComponent } from "../bridge.component";
import { TelegramApiService } from "../../../shared/services/integrations/telegram-api.service";
import { FE_PortalInfo } from "../../../shared/models/telegram";
import { Modal, overlayConfigFactory } from "ngx-modialog";
import { AskUnbridgeDialogContext, TelegramAskUnbridgeComponent } from "./ask-unbridge/ask-unbridge.component";
import { TelegramAskUnbridgeComponent } from "./ask-unbridge/ask-unbridge.component";
import {
CannotUnbridgeDialogContext,
TelegramCannotUnbridgeComponent
} from "./cannot-unbridge/cannot-unbridge.component";
import { TranslateService } from "@ngx-translate/core";
import { NgbModal } from "@ng-bootstrap/ng-bootstrap";
interface TelegramConfig {
puppet: {
@ -40,7 +39,7 @@ export class TelegramBridgeConfigComponent extends BridgeComponent<TelegramConfi
public isUpdating: boolean;
constructor(private telegram: TelegramApiService, private modal: Modal, public translate: TranslateService) {
constructor(private telegram: TelegramApiService, private modal: NgbModal, public translate: TranslateService) {
super("telegram", translate);
this.translate = translate;
}
@ -80,21 +79,22 @@ export class TelegramBridgeConfigComponent extends BridgeComponent<TelegramConfi
this.telegram.getPortalInfo(this.bridge.config.portalInfo.chatId, this.roomId).then(async (chatInfo) => {
let forceUnbridge = false;
if (chatInfo.bridged && chatInfo.canUnbridge) {
const response = await this.modal.open(TelegramAskUnbridgeComponent, overlayConfigFactory({
isBlocking: true,
const askUnbridgeRef = this.modal.open(TelegramAskUnbridgeComponent, {
backdrop: 'static',
size: 'lg',
}, AskUnbridgeDialogContext)).result;
});
askUnbridgeRef.result.then((response) => {
if (response.unbridge) {
forceUnbridge = true;
} else {
return {aborted: true};
}
});
} else if (chatInfo.bridged) {
this.modal.open(TelegramCannotUnbridgeComponent, overlayConfigFactory({
isBlocking: true,
this.modal.open(TelegramCannotUnbridgeComponent, {
backdrop: 'static',
size: 'lg',
}, CannotUnbridgeDialogContext));
});
return {aborted: true};
}

View File

@ -1,14 +1,13 @@
<div class="dialog">
<div class="dialog-header">
<h4>{{ bot.displayName }}</h4>
</div>
<div class="dialog-content" style="text-align: center;">
<div class="modal-header">
<h4 class="modal-title" id="modal-basic-title">{{ bot.displayName }}</h4>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close" (click)="modal.close()"></button>
</div>
<div class="modal-body">
<p>{{ bot.description }}</p>
<ui-switch [checked]="bot._inRoom" [disabled]="bot._isUpdating" (change)="toggle()"></ui-switch>
</div>
<div class="dialog-footer">
<button type="button" (click)="dialog.close()" title="close" class="btn btn-secondary btn-sm">
</div>
<div class="modal-footer">
<button type="button" (click)="modal.close()" title="close" class="btn btn-secondary btn-sm">
<i class="far fa-times-circle"></i> {{'Close' | translate}}
</button>
</div>
</div>

View File

@ -1,36 +1,35 @@
import { Component } from "@angular/core";
import { Component, OnInit } from "@angular/core";
import { FE_SimpleBot } from "../../shared/models/integration";
import { ToasterService } from "angular2-toaster";
import { ScalarClientApiService } from "../../shared/services/scalar/scalar-client-api.service";
import { IntegrationsApiService } from "../../shared/services/integrations/integrations-api.service";
import { BSModalContext } from "ngx-modialog/plugins/bootstrap";
import { DialogRef } from "ngx-modialog";
import { TranslateService } from "@ngx-translate/core";
import { NgbActiveModal } from "@ng-bootstrap/ng-bootstrap";
export class SimpleBotConfigDialogContext extends BSModalContext {
public bot: FE_SimpleBot;
public roomId: string;
export interface SimpleBotConfigDialogContext {
bot: FE_SimpleBot;
roomId: string;
}
@Component({
templateUrl: "simple-bot.component.html",
styleUrls: ["simple-bot.component.scss"],
})
export class ConfigSimpleBotComponent {
export class ConfigSimpleBotComponent implements OnInit {
public bot: FE_SimpleBot;
private roomId: string;
constructor(public dialog: DialogRef<SimpleBotConfigDialogContext>,
constructor(public modal: NgbActiveModal,
private toaster: ToasterService,
private scalar: ScalarClientApiService,
private integrationsApi: IntegrationsApiService,
public translate: TranslateService) {
this.translate = translate;
this.bot = dialog.context.bot;
this.roomId = dialog.context.roomId;
}
ngOnInit() {
this.bot._isUpdating = false;
}

View File

@ -3,21 +3,28 @@ import { ActivatedRoute, Router } from "@angular/router";
import { ScalarClientApiService } from "../../shared/services/scalar/scalar-client-api.service";
import * as _ from "lodash";
import { ScalarServerApiService } from "../../shared/services/scalar/scalar-server-api.service";
import { FE_Integration, FE_IntegrationRequirement, FE_SimpleBot } from "../../shared/models/integration";
import {
FE_Integration,
FE_IntegrationRequirement,
FE_SimpleBot,
} from "../../shared/models/integration";
import { IntegrationsRegistry } from "../../shared/registry/integrations.registry";
import { SessionStorage } from "../../shared/SessionStorage";
import { AdminApiService } from "../../shared/services/admin/admin-api.service";
import { IntegrationsApiService } from "../../shared/services/integrations/integrations-api.service";
import { Modal, overlayConfigFactory } from "ngx-modialog";
import { ConfigSimpleBotComponent, SimpleBotConfigDialogContext } from "../../configs/simple-bot/simple-bot.component";
import {
ConfigSimpleBotComponent,
SimpleBotConfigDialogContext,
} from "../../configs/simple-bot/simple-bot.component";
import { ToasterService } from "angular2-toaster";
import { StickerApiService } from "../../shared/services/integrations/sticker-api.service";
import { TranslateService } from "@ngx-translate/core";
import { NgbModal } from "@ng-bootstrap/ng-bootstrap";
const CATEGORY_MAP = {
"Widgets": ["widget"],
"Bots": ["complex-bot", "bot"],
"Bridges": ["bridge"],
Widgets: ["widget"],
Bots: ["complex-bot", "bot"],
Bridges: ["bridge"],
};
@Component({
@ -39,16 +46,18 @@ export class RiotHomeComponent {
public integrationsForCategory: { [category: string]: FE_Integration[] } = {};
private categoryMap: { [categoryName: string]: string[] } = CATEGORY_MAP;
constructor(private activatedRoute: ActivatedRoute,
constructor(
private activatedRoute: ActivatedRoute,
private scalarApi: ScalarServerApiService,
private scalar: ScalarClientApiService,
private integrationsApi: IntegrationsApiService,
private stickerApi: StickerApiService,
private adminApi: AdminApiService,
private router: Router,
private modal: Modal,
private modal: NgbModal,
private toaster: ToasterService,
public translate: TranslateService) {
public translate: TranslateService
) {
this.translate = translate;
let params: any = this.activatedRoute.snapshot.queryParams;
@ -58,49 +67,79 @@ export class RiotHomeComponent {
if (SessionStorage.roomId && SessionStorage.userId) {
this.roomId = SessionStorage.roomId;
this.userId = SessionStorage.userId;
console.log("Already checked scalar token and other params - continuing startup");
console.log(
"Already checked scalar token and other params - continuing startup"
);
this.prepareIntegrations();
return;
}
if (!params.scalar_token || !params.room_id) {
console.error("Unable to load Dimension. Missing room ID or scalar token.");
console.error(
"Unable to load Dimension. Missing room ID or scalar token."
);
this.isError = true;
this.isLoading = false;
this.translate.get('Unable to load Dimension - missing room ID or token.').subscribe((res: string) => {this.errorMessage = res});
this.translate
.get("Unable to load Dimension - missing room ID or token.")
.subscribe((res: string) => {
this.errorMessage = res;
});
} else {
this.roomId = params.room_id;
SessionStorage.scalarToken = params.scalar_token;
SessionStorage.roomId = this.roomId;
this.scalarApi.getAccount().then(response => {
this.scalarApi
.getAccount()
.then((response) => {
const userId = response.user_id;
SessionStorage.userId = userId;
if (!userId) {
console.error("No user returned for token. Is the token registered in Dimension?");
console.error(
"No user returned for token. Is the token registered in Dimension?"
);
this.isError = true;
this.isLoading = false;
this.translate.get('Could not verify your token. Please try logging out of Element and back in. Be sure to back up your encryption keys!').subscribe((res: string) => {this.errorMessage = res});
this.translate
.get(
"Could not verify your token. Please try logging out of Element and back in. Be sure to back up your encryption keys!"
)
.subscribe((res: string) => {
this.errorMessage = res;
});
} else {
this.userId = userId;
console.log("Scalar token belongs to " + userId);
this.checkAdmin();
this.prepareIntegrations();
}
}).catch(err => {
})
.catch((err) => {
console.error(err);
this.isError = true;
this.isLoading = false;
this.translate.get('Unable to communicate with Dimension due to an unknown error.').subscribe((res: string) => {this.errorMessage = res});
this.translate
.get(
"Unable to communicate with Dimension due to an unknown error."
)
.subscribe((res: string) => {
this.errorMessage = res;
});
});
}
}
private checkAdmin() {
this.adminApi.isAdmin().then(() => {
console.log(SessionStorage.userId + " is an admin for this Dimension instance");
this.adminApi
.isAdmin()
.then(() => {
console.log(
SessionStorage.userId + " is an admin for this Dimension instance"
);
SessionStorage.isAdmin = true;
}).catch(() => SessionStorage.isAdmin = false);
})
.catch(() => (SessionStorage.isAdmin = false));
}
public hasIntegrations(): boolean {
@ -133,9 +172,22 @@ export class RiotHomeComponent {
public modifyIntegration(integration: FE_Integration) {
if (!integration._isSupported) {
console.log(this.userId + " tried to modify " + integration.displayName + " with error: " + integration._notSupportedReason);
this.translate.get('You do not appear to have permission to modify widgets in this room').subscribe((res: string) => {
const reason = integration.category === "widget" ? res : integration._notSupportedReason;
console.log(
this.userId +
" tried to modify " +
integration.displayName +
" with error: " +
integration._notSupportedReason
);
this.translate
.get(
"You do not appear to have permission to modify widgets in this room"
)
.subscribe((res: string) => {
const reason =
integration.category === "widget"
? res
: integration._notSupportedReason;
this.toaster.pop("error", reason);
});
return;
@ -143,36 +195,56 @@ export class RiotHomeComponent {
SessionStorage.editIntegration = integration;
SessionStorage.editsRequested++;
console.log(this.userId + " is trying to modify " + integration.displayName);
console.log(
this.userId + " is trying to modify " + integration.displayName
);
if (integration.category === "bot") {
this.modal.open(ConfigSimpleBotComponent, overlayConfigFactory({
bot: <FE_SimpleBot>integration,
roomId: this.roomId,
isBlocking: true,
size: 'lg',
}, SimpleBotConfigDialogContext));
const widgetConfigRef = this.modal.open(ConfigSimpleBotComponent, {
backdrop: "static",
size: "lg",
});
const widgetConfigInterface =
widgetConfigRef.componentInstance as SimpleBotConfigDialogContext;
widgetConfigInterface.bot = <FE_SimpleBot>integration;
widgetConfigInterface.roomId = this.roomId;
} else {
console.log("Navigating to edit screen for " + integration.category + " " + integration.type);
this.router.navigate(['riot-app', integration.category, integration.type], {queryParams: {roomId: this.roomId}});
console.log(
"Navigating to edit screen for " +
integration.category +
" " +
integration.type
);
this.router.navigate(
["riot-app", integration.category, integration.type],
{ queryParams: { roomId: this.roomId } }
);
}
}
private prepareIntegrations() {
this.scalar.isRoomEncrypted(this.roomId).then(payload => {
this.scalar
.isRoomEncrypted(this.roomId)
.then((payload) => {
this.isRoomEncrypted = payload.response;
return this.integrationsApi.getIntegrations(this.roomId);
}).then(response => {
const integrations: FE_Integration[] = _.flatten(Object.keys(response).map(k => response[k]));
const supportedIntegrations: FE_Integration[] = _.filter(integrations, i => IntegrationsRegistry.isSupported(i));
})
.then((response) => {
const integrations: FE_Integration[] = _.flatten(
Object.keys(response).map((k) => response[k])
);
const supportedIntegrations: FE_Integration[] = _.filter(
integrations,
(i) => IntegrationsRegistry.isSupported(i)
);
// Flag integrations that aren't supported in encrypted rooms
if (this.isRoomEncrypted) {
for (const integration of supportedIntegrations) {
if (!integration.isEncryptionSupported) {
integration._isSupported = false;
integration._notSupportedReason = "This integration is not supported in encrypted rooms";
integration._notSupportedReason =
"This integration is not supported in encrypted rooms";
}
}
}
@ -180,26 +252,42 @@ 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.category) !== -1);
this.integrationsForCategory[category] = _.filter(
supportedIntegrations,
(i) => supportedTypes.indexOf(i.category) !== -1
);
}
let promises = supportedIntegrations.map(i => this.updateIntegrationState(i));
let promises = supportedIntegrations.map((i) =>
this.updateIntegrationState(i)
);
return Promise.all(promises);
}).then(() => {
})
.then(() => {
this.isLoading = false;
// HACK: We wait for the digest cycle so we actually have components to look at
setTimeout(() => this.tryOpenConfigScreen(), 20);
}).catch(err => {
})
.catch((err) => {
console.error(err);
this.isError = true;
this.isLoading = false;
this.translate.get('Unable to set up Dimension. This version of Element may not supported or there may be a problem with the server.').subscribe((res: string) => {this.errorMessage = res});
this.translate
.get(
"Unable to set up Dimension. This version of Element may not supported or there may be a problem with the server."
)
.subscribe((res: string) => {
this.errorMessage = res;
});
});
this.stickerApi.getPacks().then(packs => {
this.stickerApi
.getPacks()
.then((packs) => {
this.hasStickerPacks = packs.length > 0;
}).catch(err => {
})
.catch((err) => {
console.error(err);
});
}
@ -210,12 +298,16 @@ export class RiotHomeComponent {
if (!this.requestedScreen) return;
if (this.requestedScreen === "type_m.stickerpicker") {
console.log("Intercepting config screen handling to open sticker picker config");
this.router.navigate(['riot-app', 'stickerpicker']);
console.log(
"Intercepting config screen handling to open sticker picker config"
);
this.router.navigate(["riot-app", "stickerpicker"]);
return;
}
const targetIntegration = IntegrationsRegistry.getIntegrationForScreen(this.requestedScreen);
const targetIntegration = IntegrationsRegistry.getIntegrationForScreen(
this.requestedScreen
);
if (targetIntegration) {
category = targetIntegration.category;
type = targetIntegration.type;
@ -226,7 +318,14 @@ export class RiotHomeComponent {
console.log("Searching for integration for requested screen");
for (const integration of this.getIntegrations()) {
if (integration.category === category && integration.type === type) {
console.log("Configuring integration " + this.requestedIntegrationId + " category=" + category + " type=" + type);
console.log(
"Configuring integration " +
this.requestedIntegrationId +
" category=" +
category +
" type=" +
type
);
SessionStorage.editIntegration = integration;
SessionStorage.editIntegrationId = this.requestedIntegrationId;
this.modifyIntegration(integration);
@ -234,81 +333,136 @@ export class RiotHomeComponent {
}
}
console.log("Failed to find integration component for category=" + category + " type=" + type);
console.log(
"Failed to find integration component for category=" +
category +
" type=" +
type
);
}
private async updateIntegrationState(integration: FE_Integration) {
if (!integration.isOnline) {
integration._isSupported = false;
this.translate.get('This integration is offline or unavailable').subscribe((res: string) => {integration._notSupportedReason = res});
this.translate
.get("This integration is offline or unavailable")
.subscribe((res: string) => {
integration._notSupportedReason = res;
});
return;
}
if (!integration.requirements) return;
let promises = integration.requirements.map(r => this.checkRequirement(r));
let promises = integration.requirements.map((r) =>
this.checkRequirement(r)
);
if (integration.category === "bot") {
const state = await this.scalar.getMembershipState(this.roomId, (<FE_SimpleBot>integration).userId);
const state = await this.scalar.getMembershipState(
this.roomId,
(<FE_SimpleBot>integration).userId
);
if (state && state.response && state.response.membership) {
integration._inRoom = ["join", "invite"].indexOf(state.response.membership) !== -1;
integration._inRoom =
["join", "invite"].indexOf(state.response.membership) !== -1;
} else integration._inRoom = false;
}
return Promise.all(promises).then(() => {
return Promise.all(promises).then(
() => {
integration._isSupported = true;
integration._notSupportedReason = null;
}, error => {
},
(error) => {
console.error(error);
integration._isSupported = false;
integration._notSupportedReason = error;
});
}
);
}
private checkRequirement(requirement: FE_IntegrationRequirement) {
switch (requirement.condition) {
case "publicRoom":
return this.scalar.getJoinRule(this.roomId).then(payload => {
return this.scalar.getJoinRule(this.roomId).then((payload) => {
if (!payload.response) {
let message: string;
this.translate.get('Could not communicate with Element').subscribe((res: string) => {message = res});
this.translate
.get("Could not communicate with Element")
.subscribe((res: string) => {
message = res;
});
return Promise.reject(message);
}
const isPublic = payload.response.join_rule === "public";
if (isPublic !== requirement.expectedValue) {
let message: string;
let message1: string;
this.translate.get(['The room must be', 'to use this integration']).subscribe((res: string) => {message = res[0]; message1 = res[1]});
return Promise.reject(message + (isPublic ? "non-public" : "public") + message1);
this.translate
.get(["The room must be", "to use this integration"])
.subscribe((res: string) => {
message = res[0];
message1 = res[1];
});
return Promise.reject(
message + (isPublic ? "non-public" : "public") + message1
);
} else return Promise.resolve();
});
case "canSendEventTypes":
const processPayload = payload => {
const processPayload = (payload) => {
const response = <any>payload.response;
if (response === true) return Promise.resolve();
if (response.error || response.error.message) {
let message: string;
this.translate.get('You cannot modify widgets in this room').subscribe((res: string) => {message = res});
this.translate
.get("You cannot modify widgets in this room")
.subscribe((res: string) => {
message = res;
});
return Promise.reject(message);
}
let message: string;
this.translate.get('Error communicating with Element').subscribe((res: string) => {message = res});
this.translate
.get("Error communicating with Element")
.subscribe((res: string) => {
message = res;
});
return Promise.reject(message);
};
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(() => {
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) {
let message: string;
this.translate.get('Expected to not be able to send specific event types').subscribe((res: string) => {message = res});
this.translate
.get("Expected to not be able to send specific event types")
.subscribe((res: string) => {
message = res;
});
return Promise.reject(message);
}
}).catch(err => {
})
.catch((err) => {
console.error(err);
if (requirement.expectedValue) {
let message: string;
this.translate.get('Expected to be able to send specific event types').subscribe((res: string) => {message = res});
this.translate
.get("Expected to be able to send specific event types")
.subscribe((res: string) => {
message = res;
});
return Promise.reject(message);
}
});
@ -317,7 +471,12 @@ export class RiotHomeComponent {
default:
let message: string;
let message1: string;
this.translate.get(['Requirement', 'not found']).subscribe((res: string) => {message = res[0]; message1 = res[1]});
this.translate
.get(["Requirement", "not found"])
.subscribe((res: string) => {
message = res[0];
message1 = res[1];
});
return Promise.reject(message + requirement.condition + message1);
}
}

View File

@ -1,7 +1,7 @@
// styles in src/style directory are applied to the whole page
@import "../assets//fonts/opensans100-roboto300";
@import "../../node_modules/angular2-toaster/toaster";
@import "../../node_modules/bootstrap/dist/css/bootstrap.min.css";
@import "~bootstrap/scss/bootstrap";
@import "~ngx-ui-switch/ui-switch.component.scss";
@import "themes/themes";
@import "components/ibox";