translation

- the traslation feature without the changes from other branches
This commit is contained in:
Ahmad 2020-10-23 13:30:20 +02:00
parent db2298172f
commit 9dc4e99aca
132 changed files with 3077 additions and 1144 deletions

670
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -21,6 +21,8 @@
},
"author": "Travis Ralston",
"dependencies": {
"@ngx-translate/core": "^12.1.2",
"@ngx-translate/http-loader": "^6.0.0",
"@types/bluebird": "^3.5.27",
"@types/body-parser": "^1.17.0",
"@types/node": "^12.0.10",
@ -46,10 +48,10 @@
"semver": "^6.0.0",
"sequelize": "^5.18.4",
"sequelize-typescript": "^1.0.0",
"sharp": "^0.21.1",
"sharp": "^0.26.0",
"split-host": "^0.1.1",
"spotify-uri": "^1.0.0",
"sqlite3": "^4.0.9",
"sqlite3": "^4.2.0",
"telegraf": "^3.30.1",
"typescript": "^3.5.2",
"typescript-ioc": "^1.2.5",
@ -100,7 +102,7 @@
"mini-css-extract-plugin": "^0.7.0",
"ng2-breadcrumbs": "^0.1.281",
"ngx-modialog": "^5.0.1",
"node-sass": "^4.12.0",
"node-sass": "^4.14.1",
"postcss-cssnext": "^3.1.0",
"postcss-import": "^12.0.1",
"postcss-loader": "^3.0.0",

View File

@ -1,11 +1,11 @@
<ul class="adminNav">
<li (click)="goto('')" [ngClass]="[isActive('', true) ? 'active' : '']">Dashboard</li>
<li (click)="goto('widgets')" [ngClass]="[isActive('widgets') ? 'active' : '']">Widgets</li>
<li (click)="goto('neb')" [ngClass]="[isActive('neb') ? 'active' : '']">go-neb</li>
<li (click)="goto('custom-bots')" [ngClass]="[isActive('custom-bots') ? 'active' : '']">Custom Bots</li>
<li (click)="goto('bridges')" [ngClass]="[isActive('bridges') ? 'active' : '']">Bridges</li>
<li (click)="goto('stickerpacks')" [ngClass]="[isActive('stickerpacks') ? 'active' : '']">Sticker Packs</li>
<li (click)="goto('terms')" [ngClass]="[isActive('terms') ? 'active' : '']">Terms of Service</li>
<li (click)="goto('')" [ngClass]="[isActive('', true) ? 'active' : '']">{{'Dashboard' | translate}}</li>
<li (click)="goto('widgets')" [ngClass]="[isActive('widgets') ? 'active' : '']">{{'Widgets' | translate}}</li>
<li (click)="goto('neb')" [ngClass]="[isActive('neb') ? 'active' : '']">{{'go-neb' | translate}}</li>
<li (click)="goto('custom-bots')" [ngClass]="[isActive('custom-bots') ? 'active' : '']">{{'Custom Bots' | translate}}</li>
<li (click)="goto('bridges')" [ngClass]="[isActive('bridges') ? 'active' : '']">{{'Bridges' | translate}}</li>
<li (click)="goto('stickerpacks')" [ngClass]="[isActive('stickerpacks') ? 'active' : '']">{{'Sticker Packs' | translate}}</li>
<li (click)="goto('terms')" [ngClass]="[isActive('terms') ? 'active' : '']">{{'Terms of Service' | translate}}</li>
</ul>
<span class="version">{{ version }}</span>

View File

@ -5,25 +5,24 @@
<my-ibox boxTitle="Bridges">
<div class="my-ibox-content">
<p>
Bridges provide a way for rooms to interact with and/or bring in events from a third party network. For
example, an IRC bridge can allow IRC and matrix users to communicate with each other.
{{'Bridges provide a way for rooms to interact with and/or bring in events from a third party network. For example, an IRC bridge can allow IRC and matrix users to communicate with each other.' | translate}}
</p>
<table class="table table-striped table-condensed table-bordered">
<thead>
<tr>
<th>Name</th>
<th>Description</th>
<th class="text-center" style="width: 120px;">Actions</th>
<th>{{'Name' | translate}}</th>
<th>{{'Description' | translate}}</th>
<th class="text-center" style="width: 120px;">{{'Actions' | translate}}</th>
</tr>
</thead>
<tbody>
<tr *ngIf="!bridges || bridges.length === 0">
<td colspan="3"><i>No bridges.</i></td>
<td colspan="3"><i>{{'No bridges.' | translate}}</i></td>
</tr>
<tr *ngFor="let bridge of bridges trackById">
<td>{{ bridge.displayName }}</td>
<td>{{ bridge.description }}</td>
<td>{{ bridge.displayName | translate }}</td>
<td>{{ bridge.description | translate }}</td>
<td class="text-center">
<span class="editButton" [routerLink]="[bridge.type]" title="edit">
<i class="fa fa-pencil-alt"></i>

View File

@ -2,6 +2,7 @@ import { Component, OnInit } from "@angular/core";
import { ToasterService } from "angular2-toaster";
import { FE_Bridge } from "../../shared/models/integration";
import { AdminIntegrationsApiService } from "../../shared/services/admin/admin-integrations-api.service";
import { TranslateService } from "@ngx-translate/core";
@Component({
templateUrl: "./bridges.component.html",
@ -13,7 +14,8 @@ export class AdminBridgesComponent implements OnInit {
public bridges: FE_Bridge<any>[];
constructor(private adminIntegrations: AdminIntegrationsApiService,
private toaster: ToasterService) {
private toaster: ToasterService, public translate: TranslateService) {
this.translate = translate;
}
public ngOnInit() {
@ -22,7 +24,7 @@ export class AdminBridgesComponent implements OnInit {
this.isLoading = false;
}).catch(err => {
console.error(err);
this.toaster.pop("error", "Failed to load bridges");
this.translate.get('Failed to load bridges').subscribe((res: string) => {this.toaster.pop("error", res); });
});
}
}

View File

@ -5,21 +5,20 @@
<my-ibox boxTitle="Gitter Bridge Configurations">
<div class="my-ibox-content">
<p>
<a href="https://github.com/matrix-org/matrix-appservice-gitter" target="_blank">matrix-appservice-gitter</a>
is a Gitter bridge that supports bridging Gitter rooms to Matrix. Users on Matrix are represented as a
single bot user in Gitter, however Gitter users are represented as real-looking Matrix users in the room.
<a href="https://github.com/matrix-org/matrix-appservice-gitter" target="_blank">{{'matrix-appservice-gitter' | translate}}</a>
{{'is a Gitter bridge that supports bridging Gitter rooms to Matrix. Users on Matrix are represented as a single bot user in Gitter, however Gitter users are represented as real-looking Matrix users in the room.' | translate}}
</p>
<table class="table table-striped table-condensed table-bordered">
<thead>
<tr>
<th>Name</th>
<th class="text-center" style="width: 120px;">Actions</th>
<th>{{'Name' | translate}}</th>
<th class="text-center" style="width: 120px;">{{'Actions' | translate}}</th>
</tr>
</thead>
<tbody>
<tr *ngIf="!configurations || configurations.length === 0">
<td colspan="2"><i>No bridge configurations.</i></td>
<td colspan="2"><i>{{'No bridge configurations.' | translate}}</i></td>
</tr>
<tr *ngFor="let bridge of configurations trackById">
<td>
@ -37,11 +36,11 @@
</table>
<button type="button" class="btn btn-success btn-sm" (click)="addModularHostedBridge()"
[disabled]="(configurations && configurations.length > 0) || isUpdating">
<i class="fa fa-plus"></i> Add matrix.org's bridge
<i class="fa fa-plus"></i>{{'Add matrix.org\'s bridge' | translate}}
</button>
<button type="button" class="btn btn-success btn-sm" (click)="addSelfHostedBridge()"
[disabled]="(configurations && configurations.length > 0) || isUpdating">
<i class="fa fa-plus"></i> Add self-hosted bridge
<i class="fa fa-plus"></i>{{'Add self-hosted bridge' | translate}}
</button>
</div>
</my-ibox>

View File

@ -9,6 +9,7 @@ import { AdminGitterApiService } from "../../../shared/services/admin/admin-gitt
import { FE_GitterBridge } from "../../../shared/models/gitter";
import { FE_Upstream } from "../../../shared/models/admin-responses";
import { AdminUpstreamApiService } from "../../../shared/services/admin/admin-upstream-api.service";
import { TranslateService } from "@ngx-translate/core";
@Component({
templateUrl: "./gitter.component.html",
@ -25,7 +26,9 @@ export class AdminGitterBridgeComponent implements OnInit {
constructor(private gitterApi: AdminGitterApiService,
private upstreamApi: AdminUpstreamApiService,
private toaster: ToasterService,
private modal: Modal) {
private modal: Modal,
public translate: TranslateService) {
this.translate = translate;
}
public ngOnInit() {
@ -38,7 +41,7 @@ export class AdminGitterBridgeComponent implements OnInit {
this.configurations = await this.gitterApi.getBridges();
} catch (err) {
console.error(err);
this.toaster.pop("error", "Error loading bridges");
this.translate.get('Error loading bridges').subscribe((res: string) => {this.toaster.pop("error", res); } );
}
}
@ -48,12 +51,12 @@ export class AdminGitterBridgeComponent implements OnInit {
const createBridge = (upstream: FE_Upstream) => {
return this.gitterApi.newFromUpstream(upstream).then(bridge => {
this.configurations.push(bridge);
this.toaster.pop("success", "matrix.org's Gitter bridge added");
this.translate.get('matrix.org\'s Gitter bridge added').subscribe((res: string) => {this.toaster.pop("success", res); });
this.isUpdating = false;
}).catch(err => {
console.error(err);
this.isUpdating = false;
this.toaster.pop("error", "Error adding matrix.org's Gitter Bridge");
this.translate.get('Error adding matrix.org\'s Gitter Bridge').subscribe((res: string) => {this.toaster.pop("error", res); } );
});
};
@ -66,7 +69,7 @@ export class AdminGitterBridgeComponent implements OnInit {
createBridge(upstream);
}).catch(err => {
console.error(err);
this.toaster.pop("error", "Error creating matrix.org's Gitter Bridge");
this.translate.get('Error creating matrix.org\'s Gitter Bridge').subscribe((res: string) => {this.toaster.pop("error", res); } );
});
} else createBridge(vectorUpstreams[0]);
}
@ -80,7 +83,7 @@ export class AdminGitterBridgeComponent implements OnInit {
}, ManageSelfhostedGitterBridgeDialogContext)).result.then(() => {
this.reload().catch(err => {
console.error(err);
this.toaster.pop("error", "Failed to get an update Gitter bridge list");
this.translate.get('Failed to get an update Gitter bridge list').subscribe((res: string) => {this.toaster.pop("error", res); } );
});
});
}
@ -95,7 +98,7 @@ export class AdminGitterBridgeComponent implements OnInit {
}, ManageSelfhostedGitterBridgeDialogContext)).result.then(() => {
this.reload().catch(err => {
console.error(err);
this.toaster.pop("error", "Failed to get an update Gitter bridge list");
this.translate.get('Failed to get an update Gitter bridge list').subscribe((res: string) => {this.toaster.pop("error", res); } );
});
});
}

View File

@ -1,16 +1,17 @@
<div class="dialog">
<div class="dialog-header">
<h4>{{ isAdding ? "Add a new" : "Edit" }} self-hosted Gitter bridge</h4>
<h4> {{'self-hosted Gitter bridge' | translate}} ({{ isAdding ? "Add a new" : "Edit" }})</h4>
</div>
<div class="dialog-content">
<p>
Self-hosted Gitter bridges already have provisioning enabled. Be careful not to expose the API to the public
internet.
{{'Self-hosted Gitter bridges already have provisioning enabled. Be careful not to expose the API to the public internet.' | translate}}
</p>
<label class="label-block">
Provisioning URL
<span class="text-muted ">The provisioning URL for the bridge. This is usually the same as the URL your homeserver uses to communicate with the bridge.</span>
{{'Provisioning URL' | translate}}
<span class="text-muted ">
{{'The provisioning URL for the bridge. This is usually the same as the URL your homeserver uses to communicate with the bridge.' | translate}}
</span>
<input type="text" class="form-control"
placeholder="http://localhost:9000"
[(ngModel)]="provisionUrl" [disabled]="isSaving"/>
@ -18,10 +19,10 @@
</div>
<div class="dialog-footer">
<button type="button" (click)="add()" title="close" class="btn btn-primary btn-sm">
<i class="far fa-save"></i> Save
<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
<i class="far fa-times-circle"></i> {{'Cancel' | translate}}
</button>
</div>
</div>

View File

@ -3,6 +3,7 @@ import { ToasterService } from "angular2-toaster";
import { DialogRef, ModalComponent } from "ngx-modialog";
import { BSModalContext } from "ngx-modialog/plugins/bootstrap";
import { AdminGitterApiService } from "../../../../shared/services/admin/admin-gitter-api.service";
import { TranslateService } from "@ngx-translate/core";
export class ManageSelfhostedGitterBridgeDialogContext extends BSModalContext {
public provisionUrl: string;
@ -22,7 +23,9 @@ export class AdminGitterBridgeManageSelfhostedComponent implements ModalComponen
constructor(public dialog: DialogRef<ManageSelfhostedGitterBridgeDialogContext>,
private gitterApi: AdminGitterApiService,
private toaster: ToasterService) {
private toaster: ToasterService,
public translate: TranslateService) {
this.translate = translate;
this.provisionUrl = dialog.context.provisionUrl;
this.bridgeId = dialog.context.bridgeId;
this.isAdding = !this.bridgeId;
@ -32,21 +35,21 @@ export class AdminGitterBridgeManageSelfhostedComponent implements ModalComponen
this.isSaving = true;
if (this.isAdding) {
this.gitterApi.newSelfhosted(this.provisionUrl).then(() => {
this.toaster.pop("success", "Gitter bridge added");
this.translate.get('Gitter bridge added').subscribe((res: string) => {this.toaster.pop("success", res); });
this.dialog.close();
}).catch(err => {
console.error(err);
this.isSaving = false;
this.toaster.pop("error", "Failed to create Gitter bridge");
this.translate.get('Failed to create Gitter bridge').subscribe((res: string) => { this.toaster.pop("error", res); });
});
} else {
this.gitterApi.updateSelfhosted(this.bridgeId, this.provisionUrl).then(() => {
this.toaster.pop("success", "Gitter bridge updated");
this.translate.get('Gitter bridge updated').subscribe((res: string) => {this.toaster.pop("success", res); });
this.dialog.close();
}).catch(err => {
console.error(err);
this.isSaving = false;
this.toaster.pop("error", "Failed to update Gitter bridge");
this.translate.get('Failed to update Gitter bridge').subscribe((res: string) => {this.toaster.pop("error", res); });
});
}
}

View File

@ -1,13 +1,13 @@
<div class="dialog">
<div class="dialog-header">
<h4>Add a new self-hosted IRC Bridge</h4>
<h4>{{'Add a new self-hosted IRC Bridge' | translate}}</h4>
</div>
<div class="dialog-content">
<p>Self-hosted IRC bridges must have <code>provisioning</code> enabled in the configuration.</p>
<p>{{'Self-hosted IRC bridges must have' | translate}}<code>{{'provisioning' | translate}}</code> {{'enabled in the configuration.' | translate}}</p>
<label class="label-block">
Provisioning URL
<span class="text-muted ">The provisioning URL for the bridge. This is usually the same as the URL given in the registration. This API is not authenticated and should be treated with caution.</span>
{{'Provisioning URL' | translate}}
<span class="text-muted ">{{'The provisioning URL for the bridge. This is usually the same as the URL given in the registration. This API is not authenticated and should be treated with caution.' | translate}}</span>
<input type="text" class="form-control"
placeholder="http://localhost:9999"
[(ngModel)]="provisionUrl" [disabled]="isSaving"/>
@ -15,10 +15,10 @@
</div>
<div class="dialog-footer">
<button type="button" (click)="add()" title="close" class="btn btn-primary btn-sm">
<i class="far fa-save"></i> Save
<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
<i class="far fa-times-circle"></i> {{'Cancel' | translate}}
</button>
</div>
</div>

View File

@ -3,6 +3,7 @@ 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 {
}
@ -18,18 +19,20 @@ export class AdminIrcBridgeAddSelfhostedComponent implements ModalComponent<AddS
constructor(public dialog: DialogRef<AddSelfhostedIrcBridgeDialogContext>,
private ircApi: AdminIrcApiService,
private toaster: ToasterService) {
private toaster: ToasterService,
public translate: TranslateService) {
this.translate = translate;
}
public add() {
this.isSaving = true;
this.ircApi.newSelfhosted(this.provisionUrl).then(() => {
this.toaster.pop("success", "IRC Bridge added");
this.translate.get('IRC Bridge added').subscribe((res: string) => {this.toaster.pop("success", res); });
this.dialog.close();
}).catch(err => {
console.error(err);
this.isSaving = false;
this.toaster.pop("error", "Failed to create IRC bridge");
this.translate.get('Failed to create IRC bridge').subscribe((res: string) => {this.toaster.pop("error", res); });
});
}
}

View File

@ -5,22 +5,21 @@
<my-ibox boxTitle="IRC Bridge Configurations">
<div class="my-ibox-content">
<p>
<a href="https://github.com/matrix-org/matrix-appservice-irc" target="_blank">matrix-appservice-irc</a>
is an IRC bridge that supports multiple IRC networks. Dimension is capable of using multiple IRC
bridges to better distribute the load across multiple networks in large deployments.
<a href="https://github.com/matrix-org/matrix-appservice-irc" target="_blank">{{'matrix-appservice-irc' | translate}}</a>
{{'is an IRC bridge that supports multiple IRC networks. Dimension is capable of using multiple IRC bridges to better distribute the load across multiple networks in large deployments.' | translate}}
</p>
<table class="table table-striped table-condensed table-bordered">
<thead>
<tr>
<th>Name</th>
<th>Enabled Networks</th>
<th class="text-center" style="width: 120px;">Actions</th>
<th>{{'Enabled Networks' | translate}}</th>
<th class="text-center" style="width: 120px;">{{'Actions' | translate}}</th>
</tr>
</thead>
<tbody>
<tr *ngIf="!configurations || configurations.length === 0">
<td colspan="3"><i>No bridge configurations.</i></td>
<td colspan="3"><i>{{'No bridge configurations.' | translate}}</i></td>
</tr>
<tr *ngFor="let bridge of configurations trackById">
<td>
@ -33,7 +32,7 @@
</td>
<td *ngIf="!bridge.isOnline" class="error-text" colspan="2">
<i class="fa fa-exclamation-triangle"></i>
This bridge is offline or unavailable.
{{'This bridge is offline or unavailable.' | translate}}
</td>
<td class="text-center" *ngIf="bridge.isOnline">
<span class="editButton" (click)="editNetworks(bridge)">
@ -45,10 +44,10 @@
</table>
<button type="button" class="btn btn-success btn-sm" (click)="addModularHostedBridge()"
*ngIf="!hasModularBridge">
<i class="fa fa-plus"></i> Add matrix.org's bridge
<i class="fa fa-plus"></i> {{'Add matrix.org\'s bridge' | translate}}
</button>
<button type="button" class="btn btn-success btn-sm" (click)="addSelfHostedBridge()">
<i class="fa fa-plus"></i> Add self-hosted bridge
<i class="fa fa-plus"></i> {{'Add self-hosted bridge' | translate}}
</button>
</div>
</my-ibox>

View File

@ -10,6 +10,7 @@ import {
AddSelfhostedIrcBridgeDialogContext,
AdminIrcBridgeAddSelfhostedComponent
} from "./add-selfhosted/add-selfhosted.component";
import { TranslateService } from "@ngx-translate/core";
@Component({
templateUrl: "./irc.component.html",
@ -27,7 +28,9 @@ export class AdminIrcBridgeComponent implements OnInit {
constructor(private upstreamApi: AdminUpstreamApiService,
private ircApi: AdminIrcApiService,
private toaster: ToasterService,
private modal: Modal) {
private modal: Modal,
public translate: TranslateService) {
this.translate = translate;
}
public ngOnInit() {
@ -48,7 +51,7 @@ export class AdminIrcBridgeComponent implements OnInit {
}
} catch (err) {
console.error(err);
this.toaster.pop("error", "Error loading bridges");
this.translate.get('Error loading bridges').subscribe((res: string) => {this.toaster.pop("error", res); });
}
}
@ -67,13 +70,13 @@ export class AdminIrcBridgeComponent implements OnInit {
const createBridge = (upstream: FE_Upstream) => {
return this.ircApi.newFromUpstream(upstream).then(bridge => {
this.configurations.push(bridge);
this.toaster.pop("success", "matrix.org's IRC bridge added", "Click the pencil icon to enable networks.");
this.translate.get(['Click the pencil icon to enable networks.', 'matrix.org\'s IRC bridge added']).subscribe((res: string) => {this.toaster.pop("success", res[0], res[1]); });
this.isUpdating = false;
this.hasModularBridge = true;
}).catch(err => {
console.error(err);
this.isUpdating = false;
this.toaster.pop("error", "Error adding matrix.org's IRC Bridge");
this.translate.get('Error adding matrix.org\'s IRC Bridge').subscribe((res: string) => {this.toaster.pop("error", res); });
});
};
const vectorUpstreams = this.upstreams.filter(u => u.type === "vector");
@ -85,7 +88,7 @@ export class AdminIrcBridgeComponent implements OnInit {
createBridge(upstream);
}).catch(err => {
console.error(err);
this.toaster.pop("error", "Error creating matrix.org's IRC Bridge");
this.translate.get('Error creating matrix.org\'s IRC Bridge').subscribe((res: string) => {this.toaster.pop("error", res); });
});
} else createBridge(vectorUpstreams[0]);
}
@ -97,7 +100,7 @@ export class AdminIrcBridgeComponent implements OnInit {
}, AddSelfhostedIrcBridgeDialogContext)).result.then(() => {
this.reload().catch(err => {
console.error(err);
this.toaster.pop("error", "Failed to get an update IRC bridge list");
this.translate.get('Failed to get an update IRC bridge list').subscribe((res: string) => {this.toaster.pop("error", res); });
});
});
}

View File

@ -6,8 +6,8 @@
<table class="table table-striped table-condensed table-bordered">
<thead>
<tr>
<th>Network</th>
<th>Enabled</th>
<th>{{'Network' | translate}}</th>
<th>{{'Enabled' | translate}}</th>
</tr>
</thead>
<tbody>
@ -23,7 +23,7 @@
</div>
<div class="dialog-footer">
<button type="button" (click)="dialog.close()" title="close" class="btn btn-primary btn-sm">
<i class="far fa-times-circle"></i> Close
<i class="far fa-times-circle"></i> {{'Close' | translate}}
</button>
</div>
</div>

View File

@ -4,6 +4,7 @@ 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;
@ -29,7 +30,9 @@ export class AdminIrcBridgeNetworksComponent implements ModalComponent<IrcNetwor
constructor(public dialog: DialogRef<IrcNetworksDialogContext>,
private ircApi: AdminIrcApiService,
private toaster: ToasterService) {
private toaster: ToasterService,
public translate: TranslateService) {
this.translate = translate;
this.bridge = dialog.context.bridge;
const networkIds = Object.keys(this.bridge.availableNetworks);
@ -51,13 +54,13 @@ export class AdminIrcBridgeNetworksComponent implements ModalComponent<IrcNetwor
this.isUpdating = true;
this.ircApi.setNetworkEnabled(this.bridge.id, network.id, network.isEnabled).then(() => {
this.isUpdating = false;
this.toaster.pop("success", "Network " + (network.isEnabled ? "enabled" : "disabled"));
this.translate.get(['Enabled', 'disabled']).subscribe((res: string) => {this.toaster.pop("success", "Network " + (network.isEnabled ? res[0] : res[1])); });
}).catch(err => {
console.error(err);
this.isUpdating = false;
network.isEnabled = !network.isEnabled;
this.bridge.availableNetworks[network.id].isEnabled = network.isEnabled;
this.toaster.pop("error", "Failed to update network");
this.translate.get('Failed to update network').subscribe((res: string) => {this.toaster.pop("error", res); });
});
}
}

View File

@ -1,16 +1,15 @@
<div class="dialog">
<div class="dialog-header">
<h4>{{ isAdding ? "Add a new" : "Edit" }} self-hosted Slack bridge</h4>
<h4> {{'self-hosted Slack bridge' | translate}} ({{ isAdding ? "Add a new" : "Edit" }})</h4>
</div>
<div class="dialog-content">
<p>
Self-hosted Slack bridges already have provisioning enabled. Be careful not to expose the API to the public
internet.
{{'Self-hosted Slack bridges already have provisioning enabled. Be careful not to expose the API to the public internet.' | translate}}
</p>
<label class="label-block">
Provisioning URL
<span class="text-muted ">The provisioning URL for the bridge. This is usually the same as the URL your homeserver uses to communicate with the bridge.</span>
{{'Provisioning URL' | translate}}
<span class="text-muted ">{{'The provisioning URL for the bridge. This is usually the same as the URL your homeserver uses to communicate with the bridge.' | translate}}</span>
<input type="text" class="form-control"
placeholder="http://localhost:9000"
[(ngModel)]="provisionUrl" [disabled]="isSaving"/>
@ -18,10 +17,10 @@
</div>
<div class="dialog-footer">
<button type="button" (click)="add()" title="close" class="btn btn-primary btn-sm">
<i class="far fa-save"></i> Save
<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
<i class="far fa-times-circle"></i> {{'Cancel' | translate}}
</button>
</div>
</div>

View File

@ -3,6 +3,7 @@ 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;
@ -22,7 +23,9 @@ export class AdminSlackBridgeManageSelfhostedComponent implements ModalComponent
constructor(public dialog: DialogRef<ManageSelfhostedSlackBridgeDialogContext>,
private slackApi: AdminSlackApiService,
private toaster: ToasterService) {
private toaster: ToasterService,
public translate: TranslateService) {
this.translate = translate;
this.provisionUrl = dialog.context.provisionUrl;
this.bridgeId = dialog.context.bridgeId;
this.isAdding = !this.bridgeId;
@ -32,21 +35,21 @@ export class AdminSlackBridgeManageSelfhostedComponent implements ModalComponent
this.isSaving = true;
if (this.isAdding) {
this.slackApi.newSelfhosted(this.provisionUrl).then(() => {
this.toaster.pop("success", "Slack bridge added");
this.translate.get('Slack bridge added').subscribe((res: string) => {this.toaster.pop("success", res); });
this.dialog.close();
}).catch(err => {
console.error(err);
this.isSaving = false;
this.toaster.pop("error", "Failed to create Slack bridge");
this.translate.get('Failed to create Slack bridge').subscribe((res: string) => {this.toaster.pop("error", res); });
});
} else {
this.slackApi.updateSelfhosted(this.bridgeId, this.provisionUrl).then(() => {
this.toaster.pop("success", "Slack bridge updated");
this.translate.get('Slack bridge updated').subscribe((res: string) => {this.toaster.pop("success", res);});
this.dialog.close();
}).catch(err => {
console.error(err);
this.isSaving = false;
this.toaster.pop("error", "Failed to update Slack bridge");
this.translate.get('Failed to update Slack bridge').subscribe((res: string) => {this.toaster.pop("error", res); });
});
}
}

View File

@ -6,21 +6,20 @@
<div class="my-ibox-content">
<p>
<a href="https://github.com/matrix-org/matrix-appservice-slack"
target="_blank">matrix-appservice-slack</a>
is a Slack bridge that supports bridging Slack channels to Matrix. Users authorize the bridge to access
their Slack workspaces and from there they can pick the channels they'd like to bridge.
target="_blank">{{'matrix-appservice-slack' | translate}}</a>
{{'is a Slack bridge that supports bridging Slack channels to Matrix. Users authorize the bridge to access their Slack workspaces and from there they can pick the channels they\'d like to bridge.' | translate}}
</p>
<table class="table table-striped table-condensed table-bordered">
<thead>
<tr>
<th>Name</th>
<th class="text-center" style="width: 120px;">Actions</th>
<th>{{'Name' | translate}}</th>
<th class="text-center" style="width: 120px;">{{'Actions' | translate}}</th>
</tr>
</thead>
<tbody>
<tr *ngIf="!configurations || configurations.length === 0">
<td colspan="2"><i>No bridge configurations.</i></td>
<td colspan="2"><i>{{'No bridge configurations.' | translate}}</i></td>
</tr>
<tr *ngFor="let bridge of configurations trackById">
<td>
@ -38,11 +37,11 @@
</table>
<button type="button" class="btn btn-success btn-sm" (click)="addModularHostedBridge()"
[disabled]="(configurations && configurations.length > 0) || isUpdating">
<i class="fa fa-plus"></i> Add matrix.org's bridge
<i class="fa fa-plus"></i> {{'Add matrix.org\'s bridge' | translate}}
</button>
<button type="button" class="btn btn-success btn-sm" (click)="addSelfHostedBridge()"
[disabled]="(configurations && configurations.length > 0) || isUpdating">
<i class="fa fa-plus"></i> Add self-hosted bridge
<i class="fa fa-plus"></i> {{'Add self-hosted bridge' | translate}}
</button>
</div>
</my-ibox>

View File

@ -9,6 +9,7 @@ import {
} from "./manage-selfhosted/manage-selfhosted.component";
import { FE_SlackBridge } from "../../../shared/models/slack";
import { AdminSlackApiService } from "../../../shared/services/admin/admin-slack-api.service";
import { TranslateService } from "@ngx-translate/core";
@Component({
templateUrl: "./slack.component.html",
@ -25,7 +26,9 @@ export class AdminSlackBridgeComponent implements OnInit {
constructor(private slackApi: AdminSlackApiService,
private upstreamApi: AdminUpstreamApiService,
private toaster: ToasterService,
private modal: Modal) {
private modal: Modal,
public translate: TranslateService) {
this.translate = translate;
}
public ngOnInit() {
@ -38,7 +41,7 @@ export class AdminSlackBridgeComponent implements OnInit {
this.configurations = await this.slackApi.getBridges();
} catch (err) {
console.error(err);
this.toaster.pop("error", "Error loading bridges");
this.translate.get('Error loading bridges').subscribe((res: string) => {this.toaster.pop("error", res); });
}
}
@ -48,12 +51,12 @@ export class AdminSlackBridgeComponent implements OnInit {
const createBridge = (upstream: FE_Upstream) => {
return this.slackApi.newFromUpstream(upstream).then(bridge => {
this.configurations.push(bridge);
this.toaster.pop("success", "matrix.org's Slack bridge added");
this.translate.get('matrix.org\'s Slack bridge added').subscribe((res: string) => {this.toaster.pop("success", res); });
this.isUpdating = false;
}).catch(err => {
console.error(err);
this.isUpdating = false;
this.toaster.pop("error", "Error adding matrix.org's Slack Bridge");
this.translate.get('Error adding matrix.org\'s Slack Bridge').subscribe((res: string) => {this.toaster.pop("error", res); });
});
};
@ -66,7 +69,7 @@ export class AdminSlackBridgeComponent implements OnInit {
createBridge(upstream);
}).catch(err => {
console.error(err);
this.toaster.pop("error", "Error creating matrix.org's Slack Bridge");
this.translate.get('Error creating matrix.org\'s Slack Bridge').subscribe((res: string) => {this.toaster.pop("error", res); });
});
} else createBridge(vectorUpstreams[0]);
}
@ -80,7 +83,7 @@ export class AdminSlackBridgeComponent implements OnInit {
}, ManageSelfhostedSlackBridgeDialogContext)).result.then(() => {
this.reload().catch(err => {
console.error(err);
this.toaster.pop("error", "Failed to get an update Slack bridge list");
this.translate.get('Failed to get an update Slack bridge list').subscribe((res: string) => {this.toaster.pop("error", res); });
});
});
}
@ -95,7 +98,7 @@ export class AdminSlackBridgeComponent implements OnInit {
}, ManageSelfhostedSlackBridgeDialogContext)).result.then(() => {
this.reload().catch(err => {
console.error(err);
this.toaster.pop("error", "Failed to get an update Slack bridge list");
this.translate.get('Failed to get an update Slack bridge list').subscribe((res: string) => {this.toaster.pop("error", res); });
});
});
}

View File

@ -1,46 +1,46 @@
<div class="dialog">
<div class="dialog-header">
<h4>{{ isAdding ? "Add a new" : "Edit" }} self-hosted Telegram bridge</h4>
<h4> {{'self-hosted Telegram bridge' | translate}} ({{ isAdding ? "Add a new" : "Edit" }})</h4>
</div>
<div class="dialog-content">
<p>Self-hosted Telegram bridges must have <code>provisioning</code> enabled in the configuration.</p>
<p>{{'Self-hosted Telegram bridges must have' | translate}} <code>{{'provisioning' | translate}}</code> {{'enabled in the configuration.' | translate}}</p>
<label class="label-block">
Provisioning URL
<span class="text-muted ">The provisioning URL for the bridge. This is the public address for the bridge followed by the provisioning prefix given in the configuration.</span>
{{'Provisioning URL' | translate}}
<span class="text-muted ">{{'The provisioning URL for the bridge. This is the public address for the bridge followed by the provisioning prefix given in the configuration.' | translate}}</span>
<input type="text" class="form-control"
placeholder="http://localhost:9999/_matrix/provision/v1"
[(ngModel)]="provisionUrl" [disabled]="isSaving"/>
</label>
<label class="label-block">
Shared Secret
<span class="text-muted ">The shared secret defined in the configuration for provisioning.</span>
{{'Shared Secret' | translate}}
<span class="text-muted ">{{'The shared secret defined in the configuration for provisioning.' | translate}}</span>
<input type="text" class="form-control"
placeholder="some_secret_value"
[(ngModel)]="sharedSecret" [disabled]="isSaving"/>
</label>
<label class="label-block">
Promote Telegram Puppeting
<span class="text-muted ">If enabled, Dimension will recommend that users log in to their Telegram accounts.</span>
{{'Promote Telegram Puppeting' | translate}}
<span class="text-muted ">{{'If enabled, Dimension will recommend that users log in to their Telegram accounts.' | translate}}</span>
<ui-switch [checked]="allowTgPuppets" size="small" [disabled]="isSaving"
(change)="allowTgPuppets = !allowTgPuppets"></ui-switch>
</label>
<label class="label-block">
Promote Matrix Puppeting
<span class="text-muted ">If enabled, Dimension will recommend that users log in to their Matrix accounts.</span>
{{'Promote Matrix Puppeting' | translate}}
<span class="text-muted ">{{'If enabled, Dimension will recommend that users log in to their Matrix accounts.' | translate}}</span>
<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">
<i class="far fa-save"></i> Save
<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
<i class="far fa-times-circle"></i> {{'Cancel' | translate}}
</button>
</div>
</div>

View File

@ -3,6 +3,7 @@ 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;
@ -28,7 +29,9 @@ export class AdminTelegramBridgeManageSelfhostedComponent implements ModalCompon
constructor(public dialog: DialogRef<ManageSelfhostedTelegramBridgeDialogContext>,
private telegramApi: AdminTelegramApiService,
private toaster: ToasterService) {
private toaster: ToasterService,
public translate: TranslateService) {
this.translate = translate;
this.provisionUrl = dialog.context.provisionUrl;
this.sharedSecret = dialog.context.sharedSecret;
this.allowTgPuppets = dialog.context.allowTgPuppets;
@ -45,21 +48,21 @@ export class AdminTelegramBridgeManageSelfhostedComponent implements ModalCompon
};
if (this.isAdding) {
this.telegramApi.newSelfhosted(this.provisionUrl, this.sharedSecret, options).then(() => {
this.toaster.pop("success", "Telegram bridge added");
this.translate.get('Telegram bridge added').subscribe((res: string) => {this.toaster.pop("success", res); });
this.dialog.close();
}).catch(err => {
console.error(err);
this.isSaving = false;
this.toaster.pop("error", "Failed to create Telegram bridge");
this.translate.get('Failed to create Telegram bridge').subscribe((res: string) => { this.toaster.pop("error", res); });
});
} else {
this.telegramApi.updateSelfhosted(this.bridgeId, this.provisionUrl, this.sharedSecret, options).then(() => {
this.toaster.pop("success", "Telegram bridge updated");
this.translate.get('Telegram bridge updated').subscribe((res: string) => {this.toaster.pop("success", res); });
this.dialog.close();
}).catch(err => {
console.error(err);
this.isSaving = false;
this.toaster.pop("error", "Failed to update Telegram bridge");
this.translate.get('Failed to update Telegram bridge').subscribe((res: string) => {this.toaster.pop("error", res); });
});
}
}

View File

@ -5,24 +5,19 @@
<my-ibox boxTitle="Telegram Bridge Configurations">
<div class="my-ibox-content">
<p>
<a href="https://github.com/tulir/mautrix-telegram" target="_blank">mautrix-telegram</a>
is a Telegram bridge that supports bridging channels/supergroups to Matrix. This can be
done through a "relay bot" (all Matrix users are represented through a single bot in Telegram)
or by making use of a user's real Telegram account (known as "puppeting"). Currently
only one Telegram bridge can be configured at a time.
</p>
<a href="https://github.com/tulir/mautrix-telegram" target="_blank">{{'mautrix-telegram' | translate}}</a>
{{'is a Telegram bridge that supports bridging channels/supergroups to Matrix. This can be done through a \'relay bot\' (all Matrix users are represented through a single bot in Telegram) or by making use of a user\'s real Telegram account (known as \'puppeting\'). Currently only one Telegram bridge can be configured at a time.' | translate}}
<table class="table table-striped table-condensed table-bordered">
<thead>
<tr>
<th>Name</th>
<th>Enabled Features</th>
<th class="text-center" style="width: 120px;">Actions</th>
<th>{{'Name' | translate}}</th>
<th>{{'Enabled Features' | translate}}</th>
<th class="text-center" style="width: 120px;">{{'Actions' | translate}}</th>
</tr>
</thead>
<tbody>
<tr *ngIf="!configurations || configurations.length === 0">
<td colspan="3"><i>No bridge configurations.</i></td>
<td colspan="3"><i>{{'No bridge configurations.' | translate}}</i></td>
</tr>
<tr *ngFor="let bridge of configurations trackById">
<td>
@ -43,7 +38,7 @@
</table>
<button type="button" class="btn btn-success btn-sm" (click)="addSelfHostedBridge()"
[disabled]="configurations && configurations.length > 0">
<i class="fa fa-plus"></i> Add self-hosted bridge
<i class="fa fa-plus"></i> {{'Add self-hosted bridge' | translate}}
</button>
</div>
</my-ibox>

View File

@ -7,6 +7,7 @@ import {
} from "./manage-selfhosted/manage-selfhosted.component";
import { FE_TelegramBridge } from "../../../shared/models/telegram";
import { AdminTelegramApiService } from "../../../shared/services/admin/admin-telegram-api.service";
import { TranslateService } from "@ngx-translate/core";
@Component({
templateUrl: "./telegram.component.html",
@ -20,7 +21,9 @@ export class AdminTelegramBridgeComponent implements OnInit {
constructor(private telegramApi: AdminTelegramApiService,
private toaster: ToasterService,
private modal: Modal) {
private modal: Modal,
public translate: TranslateService) {
this.translate = translate;
}
public ngOnInit() {
@ -32,7 +35,7 @@ export class AdminTelegramBridgeComponent implements OnInit {
this.configurations = await this.telegramApi.getBridges();
} catch (err) {
console.error(err);
this.toaster.pop("error", "Error loading bridges");
this.translate.get('Error loading bridges').subscribe((res: string) => {this.toaster.pop("error", res); });
}
}
@ -47,7 +50,7 @@ export class AdminTelegramBridgeComponent implements OnInit {
}, ManageSelfhostedTelegramBridgeDialogContext)).result.then(() => {
this.reload().catch(err => {
console.error(err);
this.toaster.pop("error", "Failed to get an update Telegram bridge list");
this.translate.get('Failed to get an update Telegram bridge list').subscribe((res: string) => {this.toaster.pop("error", res); });
});
});
}
@ -72,7 +75,7 @@ export class AdminTelegramBridgeComponent implements OnInit {
}, ManageSelfhostedTelegramBridgeDialogContext)).result.then(() => {
this.reload().catch(err => {
console.error(err);
this.toaster.pop("error", "Failed to get an update Telegram bridge list");
this.translate.get('Failed to get an update Telegram bridge list').subscribe((res: string) => {this.toaster.pop("error", res); });
});
});
}

View File

@ -1,21 +1,21 @@
<div class="dialog">
<div class="dialog-header">
<h4>{{ isAdding ? "Add a new" : "Edit" }} self-hosted webhook bridge</h4>
<h4> {{'self-hosted webhook bridge' | translate}} ({{ isAdding ? "Add a new" : "Edit" }})</h4>
</div>
<div class="dialog-content">
<p>Self-hosted webhook bridges must have <code>provisioning</code> enabled in the configuration.</p>
<p>{{'Self-hosted webhook bridges must have' | translate}} <code>{{'provisioning' | translate}}</code> {{'enabled in the configuration.' | translate}}</p>
<label class="label-block">
Provisioning URL
<span class="text-muted ">The public URL for the bridge.</span>
{{'Provisioning URL' | translate}}
<span class="text-muted ">{{'The public URL for the bridge.' | translate}}</span>
<input type="text" class="form-control"
placeholder="https://webhooks.example.org:9000/"
[(ngModel)]="provisionUrl" [disabled]="isSaving"/>
</label>
<label class="label-block">
Shared Secret
<span class="text-muted ">The provisioning secret defined in the configuration.</span>
{{'Shared Secret' | translate}}
<span class="text-muted ">{{'The provisioning secret defined in the configuration.' | translate}}</span>
<input type="text" class="form-control"
placeholder="some_secret_value"
[(ngModel)]="sharedSecret" [disabled]="isSaving"/>
@ -23,10 +23,10 @@
</div>
<div class="dialog-footer">
<button type="button" (click)="add()" title="close" class="btn btn-primary btn-sm">
<i class="far fa-save"></i> Save
<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
<i class="far fa-times-circle"></i> {{'Cancel' | translate}}
</button>
</div>
</div>

View File

@ -3,6 +3,7 @@ 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;
@ -26,7 +27,9 @@ export class AdminWebhooksBridgeManageSelfhostedComponent implements ModalCompon
constructor(public dialog: DialogRef<ManageSelfhostedWebhooksBridgeDialogContext>,
private webhooksApi: AdminWebhooksApiService,
private toaster: ToasterService) {
private toaster: ToasterService,
public translate: TranslateService) {
this.translate = translate;
this.provisionUrl = dialog.context.provisionUrl;
this.sharedSecret = dialog.context.sharedSecret;
this.bridgeId = dialog.context.bridgeId;
@ -37,21 +40,21 @@ export class AdminWebhooksBridgeManageSelfhostedComponent implements ModalCompon
this.isSaving = true;
if (this.isAdding) {
this.webhooksApi.newSelfhosted(this.provisionUrl, this.sharedSecret).then(() => {
this.toaster.pop("success", "Webhook bridge added");
this.translate.get('Webhook bridge added').subscribe((res: string) => {this.toaster.pop("success", res); });
this.dialog.close();
}).catch(err => {
console.error(err);
this.isSaving = false;
this.toaster.pop("error", "Failed to create Webhook bridge");
this.translate.get('Failed to create Webhook bridge').subscribe((res: string) => {this.toaster.pop("error", res); });
});
} else {
this.webhooksApi.updateSelfhosted(this.bridgeId, this.provisionUrl, this.sharedSecret).then(() => {
this.toaster.pop("success", "Webhook bridge updated");
this.translate.get('Webhook bridge updated').subscribe((res: string) => {this.toaster.pop("success", res); });
this.dialog.close();
}).catch(err => {
console.error(err);
this.isSaving = false;
this.toaster.pop("error", "Failed to update Webhook bridge");
this.translate.get('Failed to update Webhook bridge').subscribe((res: string) => {this.toaster.pop("error", res); });
});
}
}

View File

@ -5,20 +5,20 @@
<my-ibox boxTitle="Webhooks Bridge Configuration">
<div class="my-ibox-content">
<p>
<a href="https://github.com/turt2live/matrix-appservice-webhooks" target="_blank">matrix-appservice-webhooks</a>
provides Slack-compatible webhooks for Matrix, making it easy to send updates into a room.
<a href="https://github.com/turt2live/matrix-appservice-webhooks" target="_blank">{{'matrix-appservice-webhooks' | translate}}</a>
{{'provides Slack-compatible webhooks for Matrix, making it easy to send updates into a room.' | translate}}
</p>
<table class="table table-striped table-condensed table-bordered">
<thead>
<tr>
<th>Name</th>
<th class="text-center" style="width: 120px;">Actions</th>
<th>{{'Name' | translate}}</th>
<th class="text-center" style="width: 120px;">{{'Actions' | translate}}</th>
</tr>
</thead>
<tbody>
<tr *ngIf="!configurations || configurations.length === 0">
<td colspan="2"><i>No bridge configurations.</i></td>
<td colspan="2"><i>{{'No bridge configurations.' | translate}}</i></td>
</tr>
<tr *ngFor="let bridge of configurations trackById">
<td>
@ -36,7 +36,7 @@
</table>
<button type="button" class="btn btn-success btn-sm" (click)="addSelfHostedBridge()"
[disabled]="configurations && configurations.length > 0">
<i class="fa fa-plus"></i> Add self-hosted bridge
<i class="fa fa-plus"></i> {{'Add self-hosted bridge' | translate}}
</button>
</div>
</my-ibox>

View File

@ -7,6 +7,7 @@ import {
} from "./manage-selfhosted/manage-selfhosted.component";
import { FE_WebhooksBridge } from "../../../shared/models/webhooks";
import { AdminWebhooksApiService } from "../../../shared/services/admin/admin-webhooks-api.service";
import { TranslateService } from "@ngx-translate/core";
@Component({
templateUrl: "./webhooks.component.html",
@ -20,7 +21,9 @@ export class AdminWebhooksBridgeComponent implements OnInit {
constructor(private webhooksApi: AdminWebhooksApiService,
private toaster: ToasterService,
private modal: Modal) {
private modal: Modal,
public translate: TranslateService) {
this.translate = translate;
}
public ngOnInit() {
@ -32,7 +35,7 @@ export class AdminWebhooksBridgeComponent implements OnInit {
this.configurations = await this.webhooksApi.getBridges();
} catch (err) {
console.error(err);
this.toaster.pop("error", "Error loading bridges");
this.translate.get('Error loading bridges').subscribe((res: string) => {this.toaster.pop("error", res); });
}
}
@ -47,7 +50,7 @@ export class AdminWebhooksBridgeComponent implements OnInit {
}, ManageSelfhostedWebhooksBridgeDialogContext)).result.then(() => {
this.reload().catch(err => {
console.error(err);
this.toaster.pop("error", "Failed to get an update Webhooks bridge list");
this.translate.get('Failed to get an update Webhooks bridge list').subscribe((res: string) => {this.toaster.pop("error", res); });
});
});
}
@ -63,7 +66,7 @@ export class AdminWebhooksBridgeComponent implements OnInit {
}, ManageSelfhostedWebhooksBridgeDialogContext)).result.then(() => {
this.reload().catch(err => {
console.error(err);
this.toaster.pop("error", "Failed to get an update Webhooks bridge list");
this.translate.get('Failed to get an update Webhooks bridge list').subscribe((res: string) => {this.toaster.pop("error", res); });
});
});
}

View File

@ -1,11 +1,11 @@
<div class="dialog">
<div class="dialog-header">
<h4>{{ isAdding ? "Add a new" : "Edit" }} custom bot</h4>
<h4>{{ isAdding ? "Add a new" : "Edit" }} {{ 'custom bot' | translate}}</h4>
</div>
<div class="dialog-content">
<label class="label-block">
User ID
<span class="text-muted">The user ID that Dimension will invite to rooms.</span>
<span class="text-muted">{{'The user ID that Dimension will invite to rooms.' | translate}}</span>
<input type="text" class="form-control"
placeholder="@yourbot:example.org"
[(ngModel)]="bot.userId" [disabled]="isSaving" (blur)="loadProfile()"/>
@ -13,15 +13,15 @@
<label class="label-block">
Description
<span class="text-muted ">A few words here will help people understand what the bot does.</span>
<span class="text-muted ">{{'A few words here will help people understand what the bot does.' | translate}}</span>
<input type="text" class="form-control"
placeholder="Does awesome things"
[(ngModel)]="bot.description" [disabled]="isSaving"/>
</label>
<label class="label-block">
Display Name
<span class="text-muted ">This is the name Dimension will use to tell users which bot this is.</span>
{{'Display Name' | translate}}
<span class="text-muted ">{{'This is the name Dimension will use to tell users which bot this is.' | translate}}</span>
<input type="text" class="form-control"
placeholder="Cool Bot"
[(ngModel)]="bot.name" [disabled]="isSaving"/>
@ -29,7 +29,7 @@
<label class="label-block">
Avatar URL
<span class="text-muted ">This can either be an MXC URI or a plain URL.</span>
<span class="text-muted ">{{'This can either be an MXC URI or a plain URL.' | translate}}</span>
<input type="text" class="form-control"
placeholder="mxc://example.org/C00lAvat4r"
[(ngModel)]="bot.avatarUrl" [disabled]="isSaving"/>
@ -37,7 +37,9 @@
<label class="label-block">
Access Token
<span class="text-muted ">This is used by Dimension to force the bot to leave the room when the user removes the bot. <a href="https://t2bot.io/docs/access_tokens/" target="_blank">Learn more about access tokens</a>.</span>
<span class="text-muted ">{{'This is used by Dimension to force the bot to leave the room when the user removes the bot.' | translate}}
<a href="https://t2bot.io/docs/access_tokens/" target="_blank">{{'Learn more about access tokens.' | translate}}</a>.
</span>
<input type="text" class="form-control"
placeholder="MDaX..."
[(ngModel)]="bot.accessToken" [disabled]="isSaving"/>
@ -45,10 +47,10 @@
</div>
<div class="dialog-footer">
<button type="button" (click)="add()" title="close" class="btn btn-primary btn-sm">
<i class="far fa-save"></i> Save
<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
<i class="far fa-times-circle"></i>{{'Cancel' | translate}}
</button>
</div>
</div>

View File

@ -4,6 +4,7 @@ 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 {
bot: FE_CustomSimpleBot;
@ -23,7 +24,9 @@ export class AdminAddCustomBotComponent implements ModalComponent<AddCustomBotDi
constructor(public dialog: DialogRef<AddCustomBotDialogContext>,
private botApi: AdminCustomSimpleBotsApiService,
private toaster: ToasterService) {
private toaster: ToasterService,
public translate: TranslateService) {
this.translate = translate;
this.bot = this.dialog.context.bot || <FE_CustomSimpleBot>{};
this.isAdding = !this.dialog.context.bot;
}
@ -45,23 +48,23 @@ export class AdminAddCustomBotComponent implements ModalComponent<AddCustomBotDi
public add() {
if (!this.bot.name) {
this.toaster.pop("warning", "Please enter a name for the bot");
this.translate.get('Please enter a name for the bot').subscribe((res: string) => {this.toaster.pop("warning", res); });
return;
}
if (!this.bot.avatarUrl) {
this.toaster.pop("warning", "Please enter an avatar URL for the bot");
this.translate.get('Please enter an avatar URL for the bot').subscribe((res: string) => {this.toaster.pop("warning", res); });
return;
}
if (!this.bot.userId) {
this.toaster.pop("warning", "Please enter a user ID for the bot");
this.translate.get('Please enter a user ID for the bot').subscribe((res: string) => {this.toaster.pop("warning", res); });
return;
}
if (!this.bot.description) {
this.toaster.pop("warning", "Please enter a description for the bot");
this.translate.get('Please enter a description for the bot').subscribe((res: string) => {this.toaster.pop("warning", res); });
return;
}
if (!this.bot.accessToken) {
this.toaster.pop("warning", "Please enter an access token for the bot");
this.translate.get('Please enter an access token for the bot').subscribe((res: string) => {this.toaster.pop("warning", res); });
return;
}
@ -85,12 +88,12 @@ export class AdminAddCustomBotComponent implements ModalComponent<AddCustomBotDi
}
promise.then(() => {
this.toaster.pop("success", "Bot updated");
this.translate.get('Bot updated').subscribe((res: string) => {this.toaster.pop("success", res); });
this.dialog.close();
}).catch(error => {
this.isSaving = false;
console.error(error);
this.toaster.pop("error", "Error updating bot");
this.translate.get('Error updating bot').subscribe((res: string) => {this.toaster.pop("error", res); });
});
}
}

View File

@ -2,25 +2,21 @@
<my-spinner></my-spinner>
</div>
<div *ngIf="!isLoading">
<my-ibox boxTitle="Custom bots">
<my-ibox boxTitle="{{'Custom bots' | translate}}">
<div class="my-ibox-content">
<p>
Custom bots give you the ability to add your own bots to Dimension for users to add
to their rooms. These bots can't have any configuration to them and must be able to
accept room invites on their own. All Dimension will do when a user wants to add the
bot is invite it to the room.
<p>{{'Custom bots give you the ability to add your own bots to Dimension for users to add to their rooms. These bots can\'t have any configuration to them and must be able to accept room invites on their own. All Dimension will do when a user wants to add the bot is invite it to the room.' | translate}}
</p>
<table class="table table-striped table-condensed table-bordered">
<thead>
<tr>
<th>Name</th>
<th class="text-center" style="width: 120px;">Actions</th>
<th>{{'Name' | translate}}</th>
<th class="text-center" style="width: 120px;">{{'Actions' | translate}}</th>
</tr>
</thead>
<tbody>
<tr *ngIf="!bots || bots.length === 0">
<td colspan="2"><i>No custom bots.</i></td>
<td colspan="2"><i>{{'No custom bots.' | translate}}</i></td>
</tr>
<tr *ngFor="let bot of bots trackById">
<td>
@ -38,7 +34,7 @@
</tbody>
</table>
<button type="button" class="btn btn-success btn-sm" (click)="addBot()">
<i class="fa fa-plus"></i> Add custom bot
<i class="fa fa-plus"></i>{{ 'Add custom bot' | translate}}
</button>
</div>
</my-ibox>

View File

@ -4,6 +4,7 @@ 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";
@Component({
templateUrl: "./custom-bots.component.html",
@ -17,11 +18,13 @@ export class AdminCustomBotsComponent {
constructor(private botApi: AdminCustomSimpleBotsApiService,
private toaster: ToasterService,
private modal: Modal) {
private modal: Modal,
public translate: TranslateService) {
this.translate = translate;
this.reload().then(() => this.isLoading = false).catch(error => {
console.error(error);
this.toaster.pop("error", "Error loading go-neb configuration");
this.translate.get('Error loading go-neb configuration').subscribe((res: string) => {this.toaster.pop("error", res); });
});
}
@ -39,7 +42,7 @@ export class AdminCustomBotsComponent {
}, AddCustomBotDialogContext)).result.then(() => {
this.reload().catch(err => {
console.error(err);
this.toaster.pop("error", "Failed to get an updated bot list");
this.translate.get('Failed to get an updated bot list').subscribe((res: string) => {this.toaster.pop("error", res); });
});
});
}
@ -53,7 +56,7 @@ export class AdminCustomBotsComponent {
}, AddCustomBotDialogContext)).result.then(() => {
this.reload().catch(err => {
console.error(err);
this.toaster.pop("error", "Failed to get an updated bot list");
this.translate.get('Failed to get an updated bot list').subscribe((res: string) => {this.toaster.pop("error", res); });
});
});
}
@ -63,11 +66,11 @@ export class AdminCustomBotsComponent {
bot.isEnabled = !bot.isEnabled;
this.botApi.updateBot(bot.id, bot).then(() => {
this.isUpdating = false;
this.toaster.pop("success", "Bot " + (bot.isEnabled ? "enabled" : "disabled"));
this.translate.get(['Enabled', 'disabled']).subscribe((res: string) => {this.toaster.pop("success", "Bot " + (bot.isEnabled ? res[0] : res[1])); });
}).catch(error => {
console.error(error);
bot.isEnabled = !bot.isEnabled;
this.toaster.pop("error", "Error updating bot");
this.translate.get('Error updating bot').subscribe((res: string) => {this.toaster.pop("error", res); });
})
}
}

View File

@ -2,42 +2,41 @@
<my-spinner></my-spinner>
</div>
<div *ngIf="!isLoading">
<my-ibox boxTitle="Configuration">
<my-ibox boxTitle="{{'Configuration' | translate}}">
<div class="my-ibox-content">
<p>
Parts of your configuration are displayed below. To change these values, edit your configuration and
restart Dimension.
{{'Parts of your configuration are displayed below. To change these values, edit your configuration and restart Dimension.' | translate}}
</p>
<div class="row">
<div class="col-md-4">
<strong>Administrators</strong>
<strong>{{'Administrators' | translate}}</strong>
<ul>
<li *ngFor="let user of config.admins trackById">{{ user }}</li>
</ul>
</div>
<div class="col-md-4">
<strong>Widget Blacklist</strong>
<strong>{{'Widget Blacklist' | translate}}</strong>
<ul>
<li *ngFor="let ip of config.widgetBlacklist trackById">{{ ip }}</li>
</ul>
</div>
<div class="col-md-4">
<strong>Homeserver</strong><br/>
<strong>{{'Homeserver' | translate}}</strong><br/>
Name: {{ config.homeserver.name }}<br/>
Federation URL: {{ config.homeserver.federationUrl }}<br/>
Federation Hostname: {{ config.homeserver.federationHostname }}<br/>
Client/Server URL: {{ config.homeserver.clientServerUrl }}<br/>
Utility User ID: {{ config.homeserver.userId }}
{{'Federation URL' | translate}}: {{ config.homeserver.federationUrl }}<br/>
{{'Federation Hostname' | translate}}: {{ config.homeserver.federationHostname }}<br/>
{{'Client/Server URL'| translate}}: {{ config.homeserver.clientServerUrl }}<br/>
{{'Utility User ID' | translate}}: {{ config.homeserver.userId }}
</div>
</div>
<div class="row">
<div class="col-md-4">
<strong>Sessions</strong><br/>
Tokens registered: {{ config.sessionInfo.numTokens }}<br/>
<strong>{{'Sessions' | translate}}</strong><br/>
{{'Tokens registered' | translate}}: {{ config.sessionInfo.numTokens }}<br/>
<button class="btn btn-danger btn-sm" type="button" (click)="logoutAll()">
Logout Everyone
{{'Logout Everyone' | translate}}
</button>
</div>
</div>

View File

@ -7,6 +7,7 @@ import {
AdminLogoutConfirmationDialogComponent,
LogoutConfirmationDialogContext
} from "./logout-confirmation/logout-confirmation.component";
import { TranslateService } from "@ngx-translate/core";
@Component({
templateUrl: "./home.component.html",
@ -19,7 +20,9 @@ export class AdminHomeComponent {
constructor(private adminApi: AdminApiService,
private toaster: ToasterService,
private modal: Modal) {
private modal: Modal,
public translate: TranslateService) {
this.translate = translate;
adminApi.getConfig().then(config => {
this.config = config;
this.isLoading = false;
@ -31,11 +34,11 @@ export class AdminHomeComponent {
isBlocking: true,
}, LogoutConfirmationDialogContext)).result.then(() => {
this.adminApi.logoutAll().then(() => {
this.toaster.pop("success", "Everyone has been logged out");
this.translate.get('Everyone has been logged out').subscribe((res: string) => {this.toaster.pop("success", res); });
this.config.sessionInfo.numTokens = 0;
}).catch(err => {
console.error(err);
this.toaster.pop("error", "Error logging everyone out");
this.translate.get('Error logging everyone out').subscribe((res: string) => {this.toaster.pop("error", res); });
});
});
}

View File

@ -1,20 +1,18 @@
<div class="dialog">
<div class="dialog-header">
<h4>Logout confirmation</h4>
<h4>{{'Logout confirmation' | translate}}</h4>
</div>
<div class="dialog-content">
<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.
{{'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">
<i class="far fa-times-circle"></i> Cancel
<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">
<i class="far fa-times-circle"></i> Logout Everyone
<i class="far fa-times-circle"></i> {{'Logout Everyone' | translate}}
</button>
</div>
</div>

View File

@ -1,27 +1,26 @@
<my-ibox boxTitle="New self-hosted go-neb">
<my-ibox boxTitle="{{'New self-hosted go-neb' | translate}}">
<div class="my-ibox-content">
<p>
Self-hosted go-neb instances are powered by application services installed on your homeserver. The
application service is responsible for creating the bots dynamically.
{{'Self-hosted go-neb instances are powered by application services installed on your homeserver. The application service is responsible for creating the bots dynamically.' | translate}}
</p>
<label class="label-block">
User Prefix
<span class="text-muted ">This is the prefix used for all bot users.</span>
{{'User Prefix' | translate}}
<span class="text-muted ">{{'This is the prefix used for all bot users.' | translate}}</span>
<input type="text" class="form-control"
placeholder="@_neb"
[(ngModel)]="userPrefix" [disabled]="isSaving"/>
</label>
<label class="label-block">
API URL
<span class="text-muted ">The admin/api url for go-neb. Be sure to not expose the admin API to the outside world because this endpoint is not authenticated.</span>
{{'API URL' | translate}}
<span class="text-muted ">{{'The admin/api url for go-neb. Be sure to not expose the admin API to the outside world because this endpoint is not authenticated.' | translate}}</span>
<input type="text" class="form-control"
placeholder="http://localhost:4050"
[(ngModel)]="adminUrl" [disabled]="isSaving"/>
</label>
<button type="button" (click)="save()" title="save" class="btn btn-primary btn-sm" [disabled]="isSaving">
<i class="far fa-save"></i> Save
<i class="far fa-save"></i> {{'Save' | translate}}
</button>
</div>
</my-ibox>

View File

@ -8,6 +8,7 @@ import {
AdminNebAppserviceConfigComponent,
AppserviceConfigDialogContext
} from "../appservice-config/appservice-config.component";
import { TranslateService } from "@ngx-translate/core";
@Component({
@ -25,7 +26,9 @@ export class AdminAddSelfhostedNebComponent {
private toaster: ToasterService,
private router: Router,
private activatedRoute: ActivatedRoute,
private modal: Modal) {
private modal: Modal,
public translate: TranslateService) {
this.translate = translate;
}
public save(): void {
@ -33,8 +36,7 @@ export class AdminAddSelfhostedNebComponent {
this.asApi.createAppservice(this.userPrefix).then(appservice => {
return this.nebApi.newAppserviceConfiguration(this.adminUrl, appservice);
}).then(neb => {
this.toaster.pop("success", "New go-neb created");
this.translate.get('New go-neb created').subscribe((res: string) => {this.toaster.pop("success", res); });
this.modal.open(AdminNebAppserviceConfigComponent, overlayConfigFactory({
neb: neb,
@ -44,7 +46,7 @@ export class AdminAddSelfhostedNebComponent {
}).catch(err => {
console.error(err);
this.isSaving = false;
this.toaster.pop("error", "Error creating appservice");
this.translate.get('Error creating appservice').subscribe((res: string) => {this.toaster.pop("error", res); });
});
}
}

View File

@ -1,22 +1,22 @@
<div class="dialog">
<div class="dialog-header">
<h4>go-neb appservice configuration</h4>
<h4>{{'go-neb appservice configuration' | translate}}</h4>
</div>
<div class="dialog-content" *ngIf="isLoading">
<my-spinner></my-spinner>
</div>
<div class="dialog-content" *ngIf="!isLoading">
Copy and paste this configuration to <code>appservice-{{appservice.id}}.yaml</code> on your homeserver and
register it as an application service.
{{'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
<i class="far fa-times-circle"></i> {{'Close' | translate}}
</button>
<button type="button" (click)="test()" title="close" class="btn btn-secondary btn-sm">
<i class="fa fa-exchange-alt"></i> Test Configuration
<i class="fa fa-exchange-alt"></i> {{'Test Configuration' | translate}}
</button>
</div>
</div>

View File

@ -4,6 +4,7 @@ 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";
export class AppserviceConfigDialogContext extends BSModalContext {
public neb: FE_NebConfiguration;
@ -19,7 +20,11 @@ export class AdminNebAppserviceConfigComponent implements ModalComponent<Appserv
public neb: FE_NebConfiguration;
public appservice: FE_Appservice;
constructor(public dialog: DialogRef<AppserviceConfigDialogContext>, private adminAppserviceApi: AdminAppserviceApiService, private toaster: ToasterService) {
constructor(public dialog: DialogRef<AppserviceConfigDialogContext>,
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 => {
@ -27,7 +32,7 @@ export class AdminNebAppserviceConfigComponent implements ModalComponent<Appserv
this.isLoading = false;
}).catch(err => {
console.error(err);
this.toaster.pop("error", "Could not load appservice configuration");
this.translate.get('Could not load appservice configuration').subscribe((res: string) => {this.toaster.pop("error", res); });
});
}
@ -48,10 +53,10 @@ export class AdminNebAppserviceConfigComponent implements ModalComponent<Appserv
public test() {
this.adminAppserviceApi.test(this.neb.appserviceId).then(() => {
this.toaster.pop("success", "The appservice appears to be correctly set up");
this.translate.get('The appservice appears to be correctly set up').subscribe((res: string) => {this.toaster.pop("success", res); });
}).catch(err => {
console.error(err);
this.toaster.pop("error", "The appservice is not correctly set up");
this.translate.get('The appservice is not correctly set up').subscribe((res: string) => {this.toaster.pop("error", res); });
});
}
}

View File

@ -1,33 +1,33 @@
<div class="dialog">
<div class="dialog-header">
<h4>Giphy Configuration</h4>
<h4>{{'Giphy Configuration' | translate}}</h4>
</div>
<div class="dialog-content" *ngIf="isLoading">
<my-spinner></my-spinner>
</div>
<div class="dialog-content" *ngIf="!isLoading">
<label class="label-block">
Api Key
<span class="text-muted ">The API key from <a href="https://developers.giphy.com/" target="_blank">developers.giphy.com</a>.</span>
{{'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>
<input type="text" class="form-control"
placeholder="your_api_key_here"
[(ngModel)]="config.api_key" [disabled]="isUpdating"/>
</label>
<label class="label-block">
Image Size
<span class="text-muted ">GIFs can be large, and sometimes it is more desirable to have them downsized.</span>
{{'Image Size' | translate}}
<span class="text-muted ">{{'GIFs can be large, and sometimes it is more desirable to have them downsized.' | translate}}</span>
<label class="checkbox">
<input type="checkbox" [(ngModel)]="config.use_downsized" [disabled]="isUpdating"/>
Use downsized images
{{'Use downsized images' | translate}}
</label>
</label>
</div>
<div class="dialog-footer" *ngIf="!isLoading">
<button type="button" (click)="save()" title="save" class="btn btn-primary btn-sm">
<i class="far fa-save"></i> Save
<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
<i class="far fa-times-circle"></i> {{'Cancel' | translate}}
</button>
</div>
</div>

View File

@ -5,6 +5,7 @@ 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";
interface GiphyConfig {
api_key: string;
@ -25,7 +26,9 @@ export class AdminNebGiphyConfigComponent implements ModalComponent<NebBotConfig
constructor(public dialog: DialogRef<NebBotConfigurationDialogContext>,
private adminNebApi: AdminNebApiService,
private toaster: ToasterService) {
private toaster: ToasterService,
public translate: TranslateService) {
this.translate = translate;
this.neb = dialog.context.neb;
this.integration = dialog.context.integration;
}
@ -36,19 +39,19 @@ export class AdminNebGiphyConfigComponent implements ModalComponent<NebBotConfig
this.isLoading = false;
}).catch(err => {
console.error(err);
this.toaster.pop("error", "Error loading configuration");
this.translate.get('Error loading configuration').subscribe((res: string) => {this.toaster.pop("error", res); });
});
}
public save() {
this.isUpdating = true;
this.adminNebApi.setIntegrationConfiguration(this.neb.id, this.integration.type, this.config).then(() => {
this.toaster.pop("success", "Configuration updated");
this.translate.get('Configuration updated').subscribe((res: string) => {this.toaster.pop("success", res); });
this.dialog.close();
}).catch(err => {
this.isUpdating = false;
console.error(err);
this.toaster.pop("error", "Error updating integration");
this.translate.get('Error updating integration').subscribe((res: string) => {this.toaster.pop("error", res); });
});
}
}

View File

@ -1,21 +1,21 @@
<div class="dialog">
<div class="dialog-header">
<h4>Google Configuration</h4>
<h4>{{'Google Configuration' | translate}}</h4>
</div>
<div class="dialog-content" *ngIf="isLoading">
<my-spinner></my-spinner>
</div>
<div class="dialog-content" *ngIf="!isLoading">
<label class="label-block">
Api Key
<span class="text-muted ">The API key for your Google Application.</span>
{{'Api Key' | translate}}
<span class="text-muted ">{{'The API key for your Google Application.' | translate}}</span>
<input type="text" class="form-control"
placeholder="your_api_key_here"
[(ngModel)]="config.api_key" [disabled]="isUpdating"/>
</label>
<label class="label-block">
Search Engine ID
<span class="text-muted ">The search engine ID</span>
<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"/>
@ -23,10 +23,10 @@
</div>
<div class="dialog-footer" *ngIf="!isLoading">
<button type="button" (click)="save()" title="save" class="btn btn-primary btn-sm">
<i class="far fa-save"></i> Save
<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
<i class="far fa-times-circle"></i> {{'Cancel' | translate}}
</button>
</div>
</div>

View File

@ -5,6 +5,7 @@ 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";
interface GoogleConfig {
api_key: string;
@ -25,7 +26,9 @@ export class AdminNebGoogleConfigComponent implements ModalComponent<NebBotConfi
constructor(public dialog: DialogRef<NebBotConfigurationDialogContext>,
private adminNebApi: AdminNebApiService,
private toaster: ToasterService) {
private toaster: ToasterService,
public translate: TranslateService) {
this.translate = translate;
this.neb = dialog.context.neb;
this.integration = dialog.context.integration;
}
@ -36,19 +39,19 @@ export class AdminNebGoogleConfigComponent implements ModalComponent<NebBotConfi
this.isLoading = false;
}).catch(err => {
console.error(err);
this.toaster.pop("error", "Error loading configuration");
this.translate.get('Error loading configuration').subscribe((res: string) => {this.toaster.pop("error", res); });
});
}
public save() {
this.isUpdating = true;
this.adminNebApi.setIntegrationConfiguration(this.neb.id, this.integration.type, this.config).then(() => {
this.toaster.pop("success", "Configuration updated");
this.translate.get('Configuration updated').subscribe((res: string) => {this.toaster.pop("success", res); });
this.dialog.close();
}).catch(err => {
this.isUpdating = false;
console.error(err);
this.toaster.pop("error", "Error updating integration");
this.translate.get('Error updating integration').subscribe((res: string) => {this.toaster.pop("error", res); });
});
}
}

View File

@ -1,14 +1,14 @@
<div class="dialog">
<div class="dialog-header">
<h4>Guggy Configuration</h4>
<h4>{{'Guggy Configuration' | translate}}</h4>
</div>
<div class="dialog-content" *ngIf="isLoading">
<my-spinner></my-spinner>
</div>
<div class="dialog-content" *ngIf="!isLoading">
<label class="label-block">
Api Key
<span class="text-muted ">The API key for <a href="http://docs.guggy.com/" target="_blank">Guggy's API</a>.</span>
{{'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>
<input type="text" class="form-control"
placeholder="your_api_key_here"
[(ngModel)]="config.api_key" [disabled]="isUpdating"/>
@ -16,10 +16,10 @@
</div>
<div class="dialog-footer" *ngIf="!isLoading">
<button type="button" (click)="save()" title="save" class="btn btn-primary btn-sm">
<i class="far fa-save"></i> Save
<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
<i class="far fa-times-circle"></i> {{'Cancel' | translate}}
</button>
</div>
</div>

View File

@ -5,6 +5,7 @@ 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";
interface GuggyConfig {
api_key: string;
@ -24,7 +25,9 @@ export class AdminNebGuggyConfigComponent implements ModalComponent<NebBotConfig
constructor(public dialog: DialogRef<NebBotConfigurationDialogContext>,
private adminNebApi: AdminNebApiService,
private toaster: ToasterService) {
private toaster: ToasterService,
public translate: TranslateService) {
this.translate = translate;
this.neb = dialog.context.neb;
this.integration = dialog.context.integration;
}
@ -35,19 +38,19 @@ export class AdminNebGuggyConfigComponent implements ModalComponent<NebBotConfig
this.isLoading = false;
}).catch(err => {
console.error(err);
this.toaster.pop("error", "Error loading configuration");
this.translate.get('Error loading configuration').subscribe((res: string) => {this.toaster.pop("error", res); });
});
}
public save() {
this.isUpdating = true;
this.adminNebApi.setIntegrationConfiguration(this.neb.id, this.integration.type, this.config).then(() => {
this.toaster.pop("success", "Configuration updated");
this.translate.get('Configuration updated').subscribe((res: string) => {this.toaster.pop("success", res); });
this.dialog.close();
}).catch(err => {
this.isUpdating = false;
console.error(err);
this.toaster.pop("error", "Error updating integration");
this.translate.get('Error updating integration').subscribe((res: string) => {this.toaster.pop("error", res); });
});
}
}

View File

@ -1,21 +1,21 @@
<div class="dialog">
<div class="dialog-header">
<h4>Imgur Configuration</h4>
<h4>{{'Imgur Configuration' | translate}}</h4>
</div>
<div class="dialog-content" *ngIf="isLoading">
<my-spinner></my-spinner>
</div>
<div class="dialog-content" *ngIf="!isLoading">
<label class="label-block">
Client ID
<span class="text-muted ">The client ID of your <a href="https://apidocs.imgur.com/" target="_blank">Imgur Application</a>.</span>
{{'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>
<input type="text" class="form-control"
placeholder="your_client_id"
[(ngModel)]="config.client_id" [disabled]="isUpdating"/>
</label>
<label class="label-block">
Client Secret
<span class="text-muted ">The client secret of your <a href="https://apidocs.imgur.com/" target="_blank">Imgur Application</a>.</span>
{{'Client Secret' | translate}}
<span class="text-muted ">{{'The client secret of your' | translate}} <a href="https://apidocs.imgur.com/" target="_blank">{{'Imgur Application' | translate}}</a>.</span>
<input type="text" class="form-control"
placeholder="your_client_secret"
[(ngModel)]="config.client_secret" [disabled]="isUpdating"/>
@ -23,10 +23,10 @@
</div>
<div class="dialog-footer" *ngIf="!isLoading">
<button type="button" (click)="save()" title="save" class="btn btn-primary btn-sm">
<i class="far fa-save"></i> Save
<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
<i class="far fa-times-circle"></i> {{'Cancel' | translate}}
</button>
</div>
</div>

View File

@ -5,6 +5,7 @@ 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";
interface ImgurConfig {
client_id: string;
@ -25,7 +26,9 @@ export class AdminNebImgurConfigComponent implements ModalComponent<NebBotConfig
constructor(public dialog: DialogRef<NebBotConfigurationDialogContext>,
private adminNebApi: AdminNebApiService,
private toaster: ToasterService) {
private toaster: ToasterService,
public translate: TranslateService) {
this.translate = translate;
this.neb = dialog.context.neb;
this.integration = dialog.context.integration;
}
@ -36,19 +39,19 @@ export class AdminNebImgurConfigComponent implements ModalComponent<NebBotConfig
this.isLoading = false;
}).catch(err => {
console.error(err);
this.toaster.pop("error", "Error loading configuration");
this.translate.get('Error loading configuration').subscribe((res: string) => {this.toaster.pop("error", res); });
});
}
public save() {
this.isUpdating = true;
this.adminNebApi.setIntegrationConfiguration(this.neb.id, this.integration.type, this.config).then(() => {
this.toaster.pop("success", "Configuration updated");
this.translate.get('Configuration updated').subscribe((res: string) => {this.toaster.pop("success", res); });
this.dialog.close();
}).catch(err => {
this.isUpdating = false;
console.error(err);
this.toaster.pop("error", "Error updating integration");
this.translate.get('Error updating integration').subscribe((res: string) => {this.toaster.pop("error", res); });
});
}
}

View File

@ -4,15 +4,14 @@
<div *ngIf="!isLoading">
<my-ibox boxTitle="go-neb configuration">
<div class="my-ibox-content">
<p>go-neb supports many different types of bots, each of which is listed below. Here you can configure which
bots this go-neb instance should use.</p>
<p>{{'go-neb supports many different types of bots, each of which is listed below. Here you can configure which bots this go-neb instance should use.' | translate}}</p>
<table class="table table-striped table-condensed table-bordered">
<thead>
<tr>
<th>Name</th>
<th>Description</th>
<th class="text-center">Actions</th>
<th>{{'Description' | translate}}</th>
<th class="text-center">{{'Actions' | translate}}</th>
</tr>
</thead>
<tbody>

View File

@ -11,6 +11,7 @@ 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";
@Component({
@ -30,7 +31,9 @@ export class AdminEditNebComponent implements OnInit, OnDestroy {
constructor(private nebApi: AdminNebApiService,
private route: ActivatedRoute,
private modal: Modal,
private toaster: ToasterService) {
private toaster: ToasterService,
public translate: TranslateService) {
this.translate = translate;
}
public ngOnInit() {
@ -58,12 +61,12 @@ export class AdminEditNebComponent implements OnInit, OnDestroy {
try {
await this.nebApi.toggleIntegration(this.nebConfig.id, bot.type, bot.isEnabled);
this.isUpdating = false;
this.toaster.pop("success", "Integration updated");
this.translate.get('Integration updated').subscribe((res: string) => {this.toaster.pop("success", res); });
} catch (err) {
console.error(err);
bot.isEnabled = !bot.isEnabled; // revert change
this.isUpdating = false;
this.toaster.pop("error", "Error updating integration");
this.translate.get('Error updating integration').subscribe((res: string) => {this.toaster.pop("error", res); });
return;
}
@ -76,7 +79,7 @@ export class AdminEditNebComponent implements OnInit, OnDestroy {
await this.nebApi.setIntegrationConfiguration(this.nebConfig.id, bot.type, {});
} catch (err) {
console.error(err);
this.toaster.pop("warning", "Failed to configure the integration", "Manual troubleshooting may be requred");
this.translate.get(['Failed to configure the integration', 'Manual troubleshooting may be requred' ]).subscribe((res: string) => {this.toaster.pop("warning", res[0], res[1]); });
return;
}
}
@ -120,7 +123,7 @@ export class AdminEditNebComponent implements OnInit, OnDestroy {
this.isLoading = false;
}).catch(err => {
console.error(err);
this.toaster.pop('error', "Could not get go-neb configuration");
this.translate.get('Could not get go-neb configuration').subscribe((res: string) => {this.toaster.pop('error', res); });
});
}
}

View File

@ -2,24 +2,21 @@
<my-spinner></my-spinner>
</div>
<div *ngIf="!isLoading">
<my-ibox boxTitle="go-neb configurations">
<my-ibox boxTitle="{{'go-neb configurations' | translate}}">
<div class="my-ibox-content">
<p><a href="https://github.com/matrix-org/go-neb" target="_blank">go-neb</a> is a multi-purpose bot that can
provide various services, such as reaction GIFs and Github notifications. There are two options for
go-neb support in Dimension: using matrix.org's or self-hosting it. Each go-neb instance can have
multiple services associated with it (ie: one go-neb here can do everything).</p>
<p><a href="https://github.com/matrix-org/go-neb" target="_blank">go-neb</a> {{'is a multi-purpose bot that can provide various services, such as reaction GIFs and Github notifications. There are two options for go-neb support in Dimension: using matrix.org\'s or self-hosting it. Each go-neb instance can have multiple services associated with it (ie: one go-neb here can do everything).' | translate}}</p>
<table class="table table-striped table-condensed table-bordered">
<thead>
<tr>
<th>Name</th>
<th>Enabled Bots</th>
<th class="text-center" style="width: 120px;">Actions</th>
<th>{{'Enabled Bots' | translate}}</th>
<th class="text-center" style="width: 120px;">{{'Actions' | translate}}</th>
</tr>
</thead>
<tbody>
<tr *ngIf="!configurations || configurations.length === 0">
<td colspan="3"><i>No go-neb configurations.</i></td>
<td colspan="3"><i>{{'No go-neb configurations.' | translate}}</i></td>
</tr>
<tr *ngFor="let neb of configurations trackById">
<td>
@ -43,10 +40,10 @@
</tbody>
</table>
<button type="button" class="btn btn-success btn-sm" (click)="addModularHostedNeb()" *ngIf="!hasModularNeb">
<i class="fa fa-plus"></i> Add matrix.org's go-neb
<i class="fa fa-plus"></i> {{'Add matrix.org\'s go-neb' | translate}}
</button>
<button type="button" class="btn btn-success btn-sm" (click)="addSelfHostedNeb()">
<i class="fa fa-plus"></i> Add self-hosted go-neb
<i class="fa fa-plus"></i> {{'Add self-hosted go-neb' | translate}}
</button>
</div>
</my-ibox>

View File

@ -10,6 +10,7 @@ import {
AppserviceConfigDialogContext
} from "./appservice-config/appservice-config.component";
import { Modal, overlayConfigFactory } from "ngx-modialog";
import { TranslateService } from "@ngx-translate/core";
@Component({
templateUrl: "./neb.component.html",
@ -30,11 +31,13 @@ export class AdminNebComponent {
private toaster: ToasterService,
private router: Router,
private activatedRoute: ActivatedRoute,
private modal: Modal) {
private modal: Modal,
public translate: TranslateService) {
this.translate = translate;
this.reload().then(() => this.isLoading = false).catch(error => {
console.error(error);
this.toaster.pop("error", "Error loading go-neb configuration");
this.translate.get('Error loading go-neb configuration').subscribe((res: string) => {this.toaster.pop("error", res); });
});
}
@ -97,13 +100,13 @@ export class AdminNebComponent {
const createNeb = (upstream: FE_Upstream) => {
return this.nebApi.newUpstreamConfiguration(upstream).then(neb => {
this.configurations.push(neb);
this.toaster.pop("success", "matrix.org's go-neb added", "Click the pencil icon to enable the bots.");
this.translate.get(['matrix.org\'s go-neb added', 'Click the pencil icon to enable the bots.']).subscribe((res: string) => {this.toaster.pop("success", res[0], res[1]); });
this.isAddingModularNeb = false;
this.hasModularNeb = true;
}).catch(error => {
console.error(error);
this.isAddingModularNeb = false;
this.toaster.pop("error", "Error adding matrix.org's go-neb");
this.translate.get('Error adding matrix.org\'s go-neb').subscribe((res: string) => {this.toaster.pop("error", res); });
});
};
@ -116,7 +119,7 @@ export class AdminNebComponent {
createNeb(upstream);
}).catch(err => {
console.error(err);
this.toaster.pop("error", "Error creating matrix.org go-neb");
this.translate.get('Error creating matrix.org go-neb').subscribe((res: string) => {this.toaster.pop("error", res); });
});
} else createNeb(vectorUpstreams[0]);
}

View File

@ -13,7 +13,7 @@
</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
<i class="far fa-times-circle"></i> {{'Close' | translate}}
</button>
</div>
</div>

View File

@ -5,9 +5,7 @@
<my-ibox boxTitle="Sticker Packs">
<div class="my-ibox-content">
<p>
Sticker packs provide a way to convey memes or feelings to others in a room. From here you're able
to select which sticker packs users of this Dimension instance can use. If no sticker packs are enabled
then the 'sticker picker' widget will be disabled.
{{'Sticker packs provide a way to convey memes or feelings to others in a room. From here you\'re able to select which sticker packs users of this Dimension instance can use. If no sticker packs are enabled then the \'sticker picker\' widget will be disabled.' | translate}}
</p>
<div class="input-group input-group-sm telegram-import">
@ -17,7 +15,7 @@
<span class="input-group-btn">
<button class="btn btn-primary" (click)="startTelegramImport()" [disabled]="!tgUrl || isImporting">
<i class="fa fa-download"></i>
Import from Telegram
{{'Import from Telegram' | translate}}
</button>
</span>
</div>
@ -26,24 +24,24 @@
<thead>
<tr>
<th>Name</th>
<th>Description</th>
<th>Author</th>
<th>License</th>
<th class="text-center" style="width: 120px;">Actions</th>
<th>{{'Description' | translate}}</th>
<th>{{'Author' | translate}}</th>
<th>{{'License' | translate}}</th>
<th class="text-center" style="width: 120px;">{{'Actions' | translate}}</th>
</tr>
</thead>
<tbody>
<tr *ngIf="!packs || packs.length === 0">
<td colspan="5"><i>No sticker packs installed.</i></td>
<td colspan="5"><i>{{'No sticker packs installed.' | translate}}</i></td>
</tr>
<tr *ngFor="let pack of packs trackById">
<td>{{ pack.displayName }}</td>
<td>{{ pack.description }}</td>
<td>{{ pack.displayName | translate}}</td>
<td>{{ pack.description | translate }}</td>
<td *ngIf="pack.author.type !== 'none'">
<a [href]="pack.author.reference" target="_blank">{{ pack.author.name }}</a>
</td>
<td *ngIf="pack.author.type === 'none'">Dimension</td>
<td *ngIf="pack.author.type === 'none'">{{'Dimension' | translate}}</td>
<td><a [href]="pack.license.urlPath" target="_blank">{{ pack.license.name }}</a></td>
<td class="text-center">

View File

@ -4,6 +4,7 @@ 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 { TranslateService } from "@ngx-translate/core";
@Component({
templateUrl: "./sticker-packs.component.html",
@ -19,7 +20,9 @@ export class AdminStickerPacksComponent implements OnInit {
constructor(private adminStickers: AdminStickersApiService,
private toaster: ToasterService,
private modal: Modal) {
private modal: Modal,
public translate: TranslateService) {
this.translate = translate;
}
public ngOnInit() {
@ -28,7 +31,7 @@ export class AdminStickerPacksComponent implements OnInit {
this.isLoading = false;
}).catch(err => {
console.error(err);
this.toaster.pop("error", "Failed to load sticker packs");
this.translate.get('Failed to load sticker packs').subscribe((res: string) => {this.toaster.pop("error", res); });
});
}
@ -37,12 +40,12 @@ export class AdminStickerPacksComponent implements OnInit {
this.isUpdating = true;
this.adminStickers.togglePack(pack.id, pack.isEnabled).then(() => {
this.isUpdating = false;
this.toaster.pop("success", "Sticker pack updated");
this.translate.get('Sticker pack updated').subscribe((res: string) => {this.toaster.pop("success", res); });
}).catch(err => {
console.error(err);
pack.isEnabled = !pack.isEnabled; // revert change
this.isUpdating = false;
this.toaster.pop("error", "Error updating sticker pack");
this.translate.get('Error updating sticker pack').subscribe((res: string) => {this.toaster.pop("error", res); });
});
}
@ -61,11 +64,11 @@ export class AdminStickerPacksComponent implements OnInit {
this.isImporting = false;
this.tgUrl = "";
this.packs.push(pack);
this.toaster.pop("success", "Telegram sticker pack imported");
this.translate.get('Telegram sticker pack imported').subscribe((res: string) => {this.toaster.pop("success", res); });
}).catch(err => {
console.error(err);
this.isImporting = false;
this.toaster.pop("error", "Error importing sticker pack");
this.translate.get('Error importing sticker pack').subscribe((res: string) => {this.toaster.pop("error", res); });
});
}
}

View File

@ -4,18 +4,18 @@
<div *ngIf="!isLoading">
<my-ibox *ngFor="let code of chosenLanguageCodes">
<div class="my-ibox-title">
<h5>{{languages[code].langName}} version</h5>
<h5>{{languages[code].langName}} {{'version' | translate}}</h5>
</div>
<div class="my-ibox-content">
<label class="label-block">
Name
<span class="text-muted ">The translated name of your policy</span>
<span class="text-muted ">{{'The translated name of your policy' | translate}}</span>
<input type="text" class="form-control" placeholder="My Policy" [(ngModel)]="languages[code].name"
[disabled]="isUpdating"/>
</label>
<label class="label-block">
Policy text
<span class="text-muted">This is where you put your policy's content.</span>
{{'Policy text' | translate}}
<span class="text-muted">{{'This is where you put your policy\'s content.' | translate}}</span>
</label>
<ckeditor [editor]="Editor" [(ngModel)]="languages[code].text" [disabled]="isUpdating"></ckeditor>
</div>
@ -33,13 +33,13 @@
<my-ibox [hasTitle]="false">
<div class="my-ibox-content buttons">
<button type="button" (click)="create()" title="save" class="btn btn-primary btn-sm" *ngIf="!isEditing">
<i class="far fa-save"></i> Create draft
<i class="far fa-save"></i> {{'Create draft' | translate}}
</button>
<button type="button" (click)="create()" title="save" class="btn btn-primary btn-sm" *ngIf="isEditing">
<i class="far fa-save"></i> Save draft
<i class="far fa-save"></i> {{'Save draft' | translate}}
</button>
<button type="button" (click)="publish()" title="save" class="btn btn-primary btn-sm" *ngIf="isEditing">
<i class="fas fa-upload"></i> Publish
<i class="fas fa-upload"></i> {{'Publish' | translate}}
</button>
</div>
</my-ibox>

View File

@ -9,6 +9,7 @@ import {
AdminTermsNewEditPublishDialogComponent,
AdminTermsNewEditPublishDialogContext
} from "./publish/publish.component";
import { TranslateService } from "@ngx-translate/core";
interface ILanguage {
name: string,
@ -66,7 +67,9 @@ export class AdminNewEditTermsComponent implements OnInit {
private toaster: ToasterService,
private router: Router,
private activatedRoute: ActivatedRoute,
private modal: Modal) {
private modal: Modal,
public translate: TranslateService) {
this.translate = translate;
}
public ngOnInit() {
@ -94,7 +97,7 @@ export class AdminNewEditTermsComponent implements OnInit {
this.isLoading = false;
}).catch(err => {
console.error(err);
this.toaster.pop("error", "Failed to load policy");
this.translate.get('Failed to load policy').subscribe((res: string) => {this.toaster.pop("error", res); });
});
} else {
this.adminTerms.getAllPolicies().then(policies => {
@ -102,7 +105,7 @@ export class AdminNewEditTermsComponent implements OnInit {
this.isLoading = false;
}).catch(err => {
console.error(err);
this.toaster.pop("error", "Failed to load policies");
this.translate.get('Failed to load policies').subscribe((res: string) => {this.toaster.pop("error", res); });
});
}
}
@ -133,11 +136,11 @@ export class AdminNewEditTermsComponent implements OnInit {
});
await this.adminTerms.publishDraft(this.shortcode, val);
this.toaster.pop("success", "Policy published");
this.translate.get('Policy published').subscribe((res: string) => {this.toaster.pop("success", res); });
this.router.navigate(["../.."], {relativeTo: this.activatedRoute});
} catch (e) {
console.error(e);
this.toaster.pop("error", "Error publishing policy");
this.translate.get('Error publishing policy').subscribe((res: string) => {this.toaster.pop("error", res); });
this.isUpdating = false;
}
});
@ -146,11 +149,11 @@ export class AdminNewEditTermsComponent implements OnInit {
public async create() {
for (const languageCode in this.languages) {
if (this.languages[languageCode].name.trim().length <= 0) {
this.toaster.pop("warning", "Please enter a name for all policies");
this.translate.get('Please enter a name for all policies').subscribe((res: string) => {this.toaster.pop("warning", res); });
return;
}
if (this.languages[languageCode].text.trim().length <= 0) {
this.toaster.pop("warning", "Please enter text for all policies");
this.translate.get('Please enter text for all policies').subscribe((res: string) => {this.toaster.pop("warning", res); });
return;
}
}
@ -164,12 +167,11 @@ export class AdminNewEditTermsComponent implements OnInit {
text: this.languages['en'].text,
url: `${window.location.origin}/widgets/terms/${this.shortcode}/en/draft`,
});
this.toaster.pop("success", "Draft saved");
this.translate.get('Draft saved').subscribe((res: string) => {this.toaster.pop("success", res); });
this.router.navigate(["../.."], {relativeTo: this.activatedRoute});
} catch (e) {
console.error(e);
this.toaster.pop("error", "Error saving policy");
this.translate.get('Error saving policy').subscribe((res: string) => {this.toaster.pop("error", res); });
this.isUpdating = false;
}
return;
@ -188,12 +190,11 @@ export class AdminNewEditTermsComponent implements OnInit {
text: this.languages['en'].text,
url: `${window.location.origin}/widgets/terms/${shortcode}/en/draft`,
});
this.toaster.pop("success", "Draft created");
this.translate.get('Draft created').subscribe((res: string) => {this.toaster.pop("success", res); });
this.router.navigate([".."], {relativeTo: this.activatedRoute});
} catch (e) {
console.error(e);
this.toaster.pop("error", "Error creating document");
this.translate.get('Error creating document').subscribe((res: string) => {this.toaster.pop("error", res); });
this.isUpdating = false;
}
}

View File

@ -1,20 +1,20 @@
<div class="dialog">
<div class="dialog-header">
<h4>Publish policy</h4>
<h4>{{'Publish policy' | translate}}</h4>
</div>
<div class="dialog-content">
<label class="label-block">
Version number
<span class="text-muted ">The version number of this policy</span>
{{'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">
<button type="button" (click)="publish()" title="close" class="btn btn-primary btn-sm">
<i class="fas fa-upload"></i> Publish
<i class="fas fa-upload"></i> {{'Publish' | translate}}
</button>
<button type="button" (click)="dialog.close()" title="save" class="btn btn-secondary btn-sm">
<i class="far fa-times-circle"></i> Close
<i class="far fa-times-circle"></i> {{'Close' | translate}}
</button>
</div>
</div>

View File

@ -2,6 +2,7 @@ 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";
export class AdminTermsNewEditPublishDialogContext extends BSModalContext {
}
@ -14,12 +15,12 @@ export class AdminTermsNewEditPublishDialogComponent implements ModalComponent<A
public version: string;
constructor(public dialog: DialogRef<AdminTermsNewEditPublishDialogContext>, private toaster: ToasterService) {
constructor(public dialog: DialogRef<AdminTermsNewEditPublishDialogContext>, private toaster: ToasterService, public translate: TranslateService) {
}
public publish() {
if (!this.version || !this.version.trim()) {
this.toaster.pop("warning", "Please enter a version number");
this.translate.get('Please enter a version number').subscribe((res: string) => {this.toaster.pop("warning", res); });
return;
}
this.dialog.close(this.version);

View File

@ -2,26 +2,23 @@
<my-spinner></my-spinner>
</div>
<div *ngIf="!isLoading">
<my-ibox boxTitle="Terms of Service">
<my-ibox boxTitle="{{'Terms of Service' | translate}}">
<div class="my-ibox-content">
<p>
Before users can use Dimension they must agree to the terms of service for using your
instance. If you're using any matrix.org bridges, users will be required to accept
the terms of service for your upstream integration managers (scalar.vector.im usually)
in addition to the terms you add here.
{{'Before users can use Dimension they must agree to the terms of service for using your instance. If you\'re using any matrix.org bridges, users will be required to accept the terms of service for your upstream integration managers (scalar.vector.im usually) in addition to the terms you add here.' | translate}}
</p>
<table class="table table-striped table-condensed table-bordered">
<thead>
<tr>
<th>Policy Name</th>
<th>Version</th>
<th class="text-center" style="width: 120px;">Actions</th>
<th>{{'Policy Name' | translate}}</th>
<th>{{'Version' | translate}}</th>
<th class="text-center" style="width: 120px;">{{'Actions' | translate}}</th>
</tr>
</thead>
<tbody>
<tr *ngIf="!policies || policies.length === 0">
<td colspan="3"><i>No policies written.</i></td>
<td colspan="3"><i>{{'No policies written.' | translate}}</i></td>
</tr>
<tr *ngFor="let policy of policies trackById">
<td>{{ policy.languages['en'].name }}</td>
@ -37,7 +34,7 @@
</tbody>
</table>
<button type="button" class="btn btn-success btn-sm" (click)="createPolicy()">
<i class="fa fa-plus"></i> New draft policy
<i class="fa fa-plus"></i> {{'New draft policy' | translate}}
</button>
</div>
</my-ibox>

View File

@ -3,6 +3,7 @@ import { ToasterService } from "angular2-toaster";
import { FE_TermsEditable } from "../../shared/models/terms";
import { AdminTermsApiService } from "../../shared/services/admin/admin-terms-api.service";
import { ActivatedRoute, Router } from "@angular/router";
import { TranslateService } from "@ngx-translate/core";
@Component({
templateUrl: "./terms.component.html",
@ -19,7 +20,9 @@ export class AdminTermsComponent implements OnInit {
constructor(private adminTerms: AdminTermsApiService,
private toaster: ToasterService,
private router: Router,
private activatedRoute: ActivatedRoute) {
private activatedRoute: ActivatedRoute,
public translate: TranslateService) {
this.translate = translate;
}
public ngOnInit() {
@ -31,7 +34,7 @@ export class AdminTermsComponent implements OnInit {
this.isLoading = false;
}).catch(err => {
console.error(err);
this.toaster.pop("error", "Failed to load policies");
this.translate.get('Failed to load policies').subscribe((res: string) => {this.toaster.pop("error", res); });
});
}

View File

@ -1,11 +1,11 @@
<div class="dialog">
<div class="dialog-header">
<h4>Etherpad Widget Configuration</h4>
<h4>{{'Etherpad Widget Configuration' | translate}}</h4>
</div>
<div class="dialog-content">
<label class="label-block">
Default Pad URL Template
<span class="text-muted ">$padName and $roomId will be replaced during creation to help create a unique pad URL.</span>
{{'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>
<input type="text" class="form-control"
placeholder="https://scalar.vector.im/etherpad/p/$padName_$roomId"
[(ngModel)]="widget.options.defaultUrl" [disabled]="isUpdating"/>
@ -13,10 +13,10 @@
</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
<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
<i class="far fa-times-circle"></i> {{'Cancel' | translate}}
</button>
</div>
</div>

View File

@ -4,6 +4,7 @@ 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";
@Component({
templateUrl: "./etherpad.component.html",
@ -15,7 +16,11 @@ export class AdminWidgetEtherpadConfigComponent implements ModalComponent<Widget
public widget: FE_EtherpadWidget;
private originalWidget: FE_EtherpadWidget;
constructor(public dialog: DialogRef<WidgetConfigDialogContext>, private adminIntegrationsApi: AdminIntegrationsApiService, private toaster: ToasterService) {
constructor(public dialog: DialogRef<WidgetConfigDialogContext>,
private adminIntegrationsApi: AdminIntegrationsApiService,
private toaster: ToasterService,
public translate: TranslateService) {
this.translate = translate;
this.originalWidget = dialog.context.widget;
this.widget = JSON.parse(JSON.stringify(this.originalWidget));
}
@ -24,12 +29,12 @@ export class AdminWidgetEtherpadConfigComponent implements ModalComponent<Widget
this.isUpdating = true;
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.translate.get('Widget updated').subscribe((res: string) => {this.toaster.pop("success", res); });
this.dialog.close();
}).catch(err => {
this.isUpdating = false;
console.error(err);
this.toaster.pop("error", "Error updating widget");
this.translate.get('Error updating widget').subscribe((res: string) => {this.toaster.pop("error", res); });
});
}
}

View File

@ -1,24 +1,24 @@
<div class="dialog">
<div class="dialog-header">
<h4>Jitsi Widget Configuration</h4>
<h4>{{'Jitsi Widget Configuration' | translate}}</h4>
</div>
<div class="dialog-content">
<label class="label-block">
Jitsi Domain
<span class="text-muted ">This is the domain that is used to host the conference.</span>
{{'Jitsi Domain' | translate}}
<span class="text-muted ">{{'This is the domain that is used to host the conference.' | translate}}</span>
<input type="text" class="form-control"
placeholder="jitsi.riot.im"
[(ngModel)]="widget.options.jitsiDomain" [disabled]="isUpdating"/>
</label>
<label class="label-block">
Use this domain as the default conference domain
<span class="text-muted ">Some clients can create widgets that are not compatible with Dimension, making Dimension use jitsi.riot.im by default. By enabling this option, you'll force Dimension to use your Jitsi domain at risk of having clients not respect it.</span>
{{'Use this domain as the default conference domain' | translate}}
<span class="text-muted ">{{'Some clients can create widgets that are not compatible with Dimension, making Dimension use jitsi.riot.im by default. By enabling this option, you\'ll force Dimension to use your Jitsi domain at risk of having clients not respect it.' | translate}}</span>
<ui-switch [checked]="widget.options.useDomainAsDefault" size="medium" [disabled]="isUpdating"
(change)="toggleForcedJitsi()"></ui-switch>
</label>
<label class="label-block">
Jitsi Script URL
<span class="text-muted ">This is used to create the Jitsi widget. It is normally at /libs/external_api.min.js from your domain.</span>
{{'Jitsi Script URL' | translate}}
<span class="text-muted ">{{'This is used to create the Jitsi widget. It is normally at /libs/external_api.min.js from your domain.' | translate}}</span>
<input type="text" class="form-control"
placeholder="https://jitsi.riot.im/libs/external_api.min.js"
[(ngModel)]="widget.options.scriptUrl" [disabled]="isUpdating"/>
@ -26,10 +26,10 @@
</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
<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
<i class="far fa-times-circle"></i> {{'Cancel' | translate}}
</button>
</div>
</div>

View File

@ -4,6 +4,7 @@ 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";
@Component({
templateUrl: "./jitsi.component.html",
@ -15,7 +16,8 @@ export class AdminWidgetJitsiConfigComponent implements ModalComponent<WidgetCon
public widget: FE_JitsiWidget;
private originalWidget: FE_JitsiWidget;
constructor(public dialog: DialogRef<WidgetConfigDialogContext>, private adminIntegrationsApi: AdminIntegrationsApiService, private toaster: ToasterService) {
constructor(public dialog: DialogRef<WidgetConfigDialogContext>, private adminIntegrationsApi: AdminIntegrationsApiService, private toaster: ToasterService, public translate: TranslateService) {
this.translate = translate;
this.originalWidget = dialog.context.widget;
this.widget = JSON.parse(JSON.stringify(this.originalWidget));
@ -27,12 +29,12 @@ export class AdminWidgetJitsiConfigComponent implements ModalComponent<WidgetCon
this.isUpdating = true;
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.translate.get('Widget updated').subscribe((res: string) => {this.toaster.pop("success", res); });
this.dialog.close();
}).catch(err => {
this.isUpdating = false;
console.error(err);
this.toaster.pop("error", "Error updating widget");
this.translate.get('Error updating widget').subscribe((res: string) => {this.toaster.pop("error", res); });
});
}

View File

@ -4,21 +4,20 @@
<div *ngIf="!isLoading">
<my-ibox boxTitle="Widgets">
<div class="my-ibox-content">
<p>Widgets are small webpages that can be embedded in a Matrix room. Here you can configure which widgets
Dimension will offer to users.</p>
<p>{{'Widgets are small webpages that can be embedded in a Matrix room. Here you can configure which widgets Dimension will offer to users.' | translate}}</p>
<table class="table table-striped table-condensed table-bordered">
<thead>
<tr>
<th>Name</th>
<th>Description</th>
<th class="text-center">Actions</th>
<th>{{'Description' | translate}}</th>
<th class="text-center">{{'Actions' | translate}}</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let widget of widgets trackById">
<td>{{ widget.displayName }}</td>
<td>{{ widget.description }}</td>
<td>{{ widget.displayName | translate }}</td>
<td>{{ widget.description | translate }}</td>
<td class="text-right">
<span class="editButton" (click)="editWidget(widget)"
*ngIf="widget.isEnabled && hasConfiguration(widget)">

View File

@ -6,6 +6,7 @@ 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 { TranslateService } from "@ngx-translate/core";
export class WidgetConfigDialogContext extends BSModalContext {
public widget: FE_Widget;
@ -21,13 +22,14 @@ export class AdminWidgetsComponent {
public isUpdating = false;
public widgets: FE_Widget[];
constructor(private adminIntegrationsApi: AdminIntegrationsApiService, private toaster: ToasterService, private modal: Modal) {
constructor(private adminIntegrationsApi: AdminIntegrationsApiService, private toaster: ToasterService, private modal: Modal, public translate: TranslateService) {
this.translate = translate;
this.adminIntegrationsApi.getAllWidgets().then(widgets => {
this.isLoading = false;
this.widgets = widgets;
}).catch(err => {
console.error(err);
this.toaster.pop("error", "Failed to load widgets");
this.translate.get('Failed to load widgets').subscribe((res: string) => {this.toaster.pop("error", res); });
});
}
@ -36,12 +38,12 @@ export class AdminWidgetsComponent {
this.isUpdating = true;
this.adminIntegrationsApi.toggleIntegration(widget.category, widget.type, widget.isEnabled).then(() => {
this.isUpdating = false;
this.toaster.pop("success", "Widget updated");
this.translate.get('Widget updated').subscribe((res: string) => {this.toaster.pop("success", res); });
}).catch(err => {
console.error(err);
widget.isEnabled = !widget.isEnabled; // revert change
this.isUpdating = false;
this.toaster.pop("error", "Error updating widget");
this.translate.get('Error updating widget').subscribe((res: string) => {this.toaster.pop("error", res); });
});
}
@ -53,7 +55,7 @@ export class AdminWidgetsComponent {
if (!component) {
console.error("No known dialog component for " + widget.type);
this.toaster.pop("error", "Error opening configuration page");
this.translate.get('Error opening configuration page').subscribe((res: string) => {this.toaster.pop("error", res); });
return;
}

View File

@ -1,5 +1,7 @@
import { Component } from "@angular/core";
import "../style/app.scss";
import { TranslateService } from "@ngx-translate/core";
import { HttpClient } from "@angular/common/http";
@Component({
selector: "my-app", // <my-app></my-app>
@ -8,7 +10,13 @@ import "../style/app.scss";
})
export class AppComponent {
constructor() {
console.log("Dimension AppComponent constructed");
constructor(public translate: TranslateService, public http: HttpClient) {
translate.addLangs(['en', 'de']);
translate.setDefaultLang('de');
if (navigator.language === 'de') {
translate.use('de');
} else {
translate.use('en');
}
}
}

View File

@ -7,7 +7,7 @@ import { UiSwitchModule } from "angular2-ui-switch";
import { NgbModule } from "@ng-bootstrap/ng-bootstrap";
import { routing } from "./app.routing";
import { FormsModule } from "@angular/forms";
import { HttpClientModule } from "@angular/common/http";
import { HttpClient, HttpClientModule } from "@angular/common/http";
import { BrowserModule } from "@angular/platform-browser";
import { AppComponent } from "./app.component";
import { HomeComponent } from "./home/home.component";
@ -118,6 +118,13 @@ import { CKEditorModule } from "@ckeditor/ckeditor5-angular";
import { AdminNewEditTermsComponent } from "./admin/terms/new-edit/new-edit.component";
import { AdminTermsNewEditPublishDialogComponent } from "./admin/terms/new-edit/publish/publish.component";
import { TermsWidgetWrapperComponent } from "./widget-wrappers/terms/terms.component";
import { TranslateLoader, TranslateModule } from "@ngx-translate/core";
import { TranslateHttpLoader } from "@ngx-translate/http-loader";
// AoT requires an exported function for factories
export function HttpLoaderFactory(http: HttpClient) {
return new TranslateHttpLoader(http);
}
@NgModule({
imports: [
@ -133,6 +140,13 @@ import { TermsWidgetWrapperComponent } from "./widget-wrappers/terms/terms.compo
BootstrapModalModule,
BreadcrumbsModule,
CKEditorModule,
TranslateModule.forRoot({
loader: {
provide: TranslateLoader,
useFactory: HttpLoaderFactory,
deps: [HttpClient]
}
})
],
declarations: [
AppComponent,

View File

@ -183,7 +183,7 @@ const routes: Routes = [
{
path: "etherpad",
component: EtherpadWidgetConfigComponent,
data: {breadcrumb: "Etherpad Widgets", name: "Etherpad Widgets"},
data: {breadcrumb: "Notes Widgets", name: "Notes Widgets"},
},
{
path: "googlecalendar",

View File

@ -6,6 +6,7 @@ import { IntegrationsApiService } from "../../shared/services/integrations/integ
import { ToasterService } from "angular2-toaster";
import { ServiceLocator } from "../../shared/registry/locator.service";
import { ScalarClientApiService } from "../../shared/services/scalar/scalar-client-api.service";
import { TranslateService } from "@ngx-translate/core";
export class BridgeComponent<T> implements OnInit, OnDestroy {
@ -14,7 +15,6 @@ export class BridgeComponent<T> implements OnInit, OnDestroy {
public bridge: FE_Bridge<T>;
public newConfig: T;
public roomId: string;
private routeQuerySubscription: Subscription;
protected toaster = ServiceLocator.injector.get(ToasterService);
@ -22,7 +22,8 @@ export class BridgeComponent<T> implements OnInit, OnDestroy {
protected route = ServiceLocator.injector.get(ActivatedRoute);
protected scalarClientApi = ServiceLocator.injector.get(ScalarClientApiService);
constructor(private integrationType: string) {
constructor(private integrationType: string, public translate: TranslateService) {
this.translate = translate;
this.isLoading = true;
this.isUpdating = false;
}
@ -50,19 +51,19 @@ export class BridgeComponent<T> implements OnInit, OnDestroy {
this.isLoading = false;
}).catch(err => {
console.error(err);
this.toaster.pop("error", "Failed to load configuration");
this.translate.get("Failed to load configuration").subscribe((res: string) => {this.toaster.pop("error", res); });
});
}
public save(): void {
this.isUpdating = true;
this.integrationsApi.setIntegrationConfiguration("bridge", this.integrationType, this.roomId, this.newConfig).then(() => {
this.toaster.pop("success", "Configuration updated");
this.translate.get("Configuration updated").subscribe((res: string) => {this.toaster.pop("success", res); });
this.bridge.config = this.newConfig;
this.isUpdating = false;
}).catch(err => {
console.error(err);
this.toaster.pop("error", "Error updating configuration");
this.translate.get("Error updating configuration").subscribe((res: string) => {this.toaster.pop("error", res); });
this.isUpdating = false;
});
}

View File

@ -2,18 +2,18 @@
<ng-template #bridgeParamsTemplate>
<my-ibox [isCollapsible]="false">
<h5 class="my-ibox-title">
Bridge to Gitter
{{'Bridge to Gitter' | translate}}
</h5>
<div class="my-ibox-content">
<div *ngIf="isBridged">
This room is bridged to "{{ bridge.config.link.gitterRoomName }}" on Gitter.
{{'This room is bridged to on Gitter' | translate}} "{{ bridge.config.link.gitterRoomName }}" {{'on Gitter' | translate}}.
<button type="button" class="btn btn-sm btn-danger" [disabled]="isBusy" (click)="unbridgeRoom()">
Unbridge
{{'Unbridge' | translate}}
</button>
</div>
<div *ngIf="!isBridged">
<label class="label-block">
Gitter Room
{{'Gitter Room' | translate}}
<input title="room name" type="text" class="form-control form-control-sm col-md-3"
[(ngModel)]="gitterRoomName" [disabled]="isBusy" placeholder="my-org/room"/>
</label>

View File

@ -3,6 +3,7 @@ import { BridgeComponent } from "../bridge.component";
import { FE_GitterLink } from "../../../shared/models/gitter";
import { GitterApiService } from "../../../shared/services/integrations/gitter-api.service";
import { ScalarClientApiService } from "../../../shared/services/scalar/scalar-client-api.service";
import { TranslateService } from "@ngx-translate/core";
interface GitterConfig {
botUserId: string;
@ -18,8 +19,9 @@ export class GitterBridgeConfigComponent extends BridgeComponent<GitterConfig> {
public gitterRoomName: string;
public isBusy: boolean;
constructor(private gitter: GitterApiService, private scalar: ScalarClientApiService) {
super("gitter");
constructor(private gitter: GitterApiService, private scalar: ScalarClientApiService, public translate: TranslateService) {
super("gitter", translate);
this.translate = translate;
}
public get isBridged(): boolean {
@ -35,7 +37,7 @@ export class GitterBridgeConfigComponent extends BridgeComponent<GitterConfig> {
if (!e.response || !e.response.error || !e.response.error._error ||
e.response.error._error.message.indexOf("already in the room") === -1) {
this.isBusy = false;
this.toaster.pop("error", "Error inviting bridge");
this.translate.get('Error inviting bridge').subscribe((res: string) => {this.toaster.pop("error", res); });
return;
}
}
@ -43,11 +45,11 @@ export class GitterBridgeConfigComponent extends BridgeComponent<GitterConfig> {
this.gitter.bridgeRoom(this.roomId, this.gitterRoomName).then(link => {
this.bridge.config.link = link;
this.isBusy = false;
this.toaster.pop("success", "Bridge requested");
this.translate.get('Bridge requested').subscribe((res: string) => {this.toaster.pop("success", res); });
}).catch(error => {
this.isBusy = false;
console.error(error);
this.toaster.pop("error", "Error requesting bridge");
this.translate.get('Error requesting bridge').subscribe((res: string) => {this.toaster.pop("error", res); });
});
}
@ -56,11 +58,11 @@ export class GitterBridgeConfigComponent extends BridgeComponent<GitterConfig> {
this.gitter.unbridgeRoom(this.roomId).then(() => {
this.bridge.config.link = null;
this.isBusy = false;
this.toaster.pop("success", "Bridge removed");
this.translate.get('Bridge removed').subscribe((res: string) => {this.toaster.pop("success", res); });
}).catch(error => {
this.isBusy = false;
console.error(error);
this.toaster.pop("error", "Error removing bridge");
this.translate.get('Error removing bridge').subscribe((res: string) => {this.toaster.pop("error", res); });
});
}
}

View File

@ -2,18 +2,16 @@
<ng-template #bridgeParamsTemplate>
<my-ibox [isCollapsible]="true">
<h5 class="my-ibox-title">
Add an IRC channel
{{'Add an IRC channel' | translate}}
</h5>
<div class="my-ibox-content">
<div class="alert alert-info">
Bridging a channel requires authorization from a channel operator. When entering a channel below, a
bot will
join the channel to ensure it exists and has operators available.
{{'Bridging a channel requires authorization from a channel operator. When entering a channel below, a bot will join the channel to ensure it exists and has operators available.' | translate}}
</div>
<div *ngIf="channelStep === 1">
<label class="label-block">
Network
{{'Network' | translate}}
<select class="form-control form-control-sm" [(ngModel)]="networkId" [disabled]="loadingOps">
<option *ngFor="let network of getNetworks()" [ngValue]="network.id">
{{ network.name }}
@ -21,7 +19,7 @@
</select>
</label>
<label class="label-block">
Channel Name
{{'Channel Name' | translate}}
</label>
<div class="input-group input-group-sm">
<div class="input-group-addon">#</div>
@ -31,15 +29,15 @@
<div style="margin-top: 25px">
<button type="button" class="btn btn-sm btn-primary" [disabled]="loadingOps"
(click)="loadOps()">
Next
{{'Next' | translate}}
</button>
</div>
</div>
<div *ngIf="channelStep === 2">
<label class="label-block">
Operator
<span class="text-muted ">The person selected here will be asked to approve or deny the bridge request.</span>
{{'Operator' | translate}}
<span class="text-muted ">{{'The person selected here will be asked to approve or deny the bridge request.' | translate}}</span>
<select class="form-control form-control-sm" [(ngModel)]="op" [disabled]="requestingBridge">
<option *ngFor="let op of ops" [ngValue]="op">{{ op }}</option>
</select>
@ -47,7 +45,7 @@
<div style="margin-top: 25px">
<button type="button" class="btn btn-sm btn-primary" [disabled]="requestingBridge"
(click)="requestBridge()">
Request Bridge
{{'Request Bridge' | translate}}
</button>
</div>
</div>
@ -55,20 +53,20 @@
</my-ibox>
<my-ibox [isCollapsible]="true">
<h5 class="my-ibox-title">
IRC Networks
{{'IRC Networks' | translate}}
</h5>
<div class="my-ibox-content">
<table class="table table-striped table-condensed table-bordered">
<thead>
<tr>
<th>Channel</th>
<th>Network</th>
<th class="actions-col">Actions</th>
<th>{{'Channel' | translate}}</th>
<th>{{'Network' | translate}}</th>
<th class="actions-col">{{'Actions' | translate}}</th>
</tr>
</thead>
<tbody>
<tr *ngIf="getChannels().length === 0">
<td colspan="3">No bridged channels</td>
<td colspan="3">{{'No bridged channels' | translate}}</td>
</tr>
<tr *ngFor="let channel of getChannels()">
<td>
@ -80,7 +78,7 @@
<button type="button" class="btn btn-sm btn-outline-danger"
[disabled]="isUpdating || channel.pending"
(click)="removeChannel(channel)">
<i class="far fa-trash-alt"></i> Remove
<i class="far fa-trash-alt"></i> {{'Remove' | translate}}
</button>
</td>
</tr>

View File

@ -2,6 +2,7 @@ import { Component } from "@angular/core";
import { BridgeComponent } from "../bridge.component";
import { FE_IrcBridgeAvailableNetworks } from "../../../shared/models/irc";
import { IrcApiService } from "../../../shared/services/integrations/irc-api.service";
import { TranslateService } from "@ngx-translate/core";
interface IrcConfig {
availableNetworks: FE_IrcBridgeAvailableNetworks;
@ -34,8 +35,9 @@ export class IrcBridgeConfigComponent extends BridgeComponent<IrcConfig> {
public op: string;
public pending: LocalChannel[] = [];
constructor(private irc: IrcApiService) {
super("irc");
constructor(private irc: IrcApiService, public translate: TranslateService) {
super("irc", translate);
this.translate = translate;
}
private resetForm() {
@ -55,7 +57,7 @@ export class IrcBridgeConfigComponent extends BridgeComponent<IrcConfig> {
public loadOps() {
if (!this.channel.trim()) {
this.toaster.pop("warning", "Please enter a channel name");
this.translate.get('Please enter a channel name').subscribe((res: string) => {this.toaster.pop("warning", res); });
return;
}
@ -68,7 +70,7 @@ export class IrcBridgeConfigComponent extends BridgeComponent<IrcConfig> {
}).catch(err => {
console.error(err);
this.loadingOps = false;
this.toaster.pop("error", "Error loading channel operators");
this.translate.get('Error loading channel operators').subscribe((res: string) => {this.toaster.pop("error", res); });
});
}
@ -86,7 +88,7 @@ export class IrcBridgeConfigComponent extends BridgeComponent<IrcConfig> {
} catch (err) {
console.error(err);
this.requestingBridge = false;
this.toaster.pop("error", "Failed to make the bridge an administrator", "Please ensure you are an 'Admin' for the room");
this.translate.get(['Failed to make the bridge an administrator', 'Please ensure you are an \'Admin\' for the room']).subscribe((res: string) => {this.toaster.pop("error", res[0], res[1]); });
return;
}
@ -99,11 +101,11 @@ export class IrcBridgeConfigComponent extends BridgeComponent<IrcConfig> {
pending: true,
});
this.resetForm();
this.toaster.pop("success", "Link requested!", "The operator selected will have to approve the bridge for it to work");
this.translate.get(['Link requested!', 'The operator selected will have to approve the bridge for it to work']).subscribe((res: string) => {this.toaster.pop("success", res[0], res[1]); });
}).catch(err => {
console.error(err);
this.requestingBridge = false;
this.toaster.pop("error", "Failed to request a link");
this.translate.get('Failed to request a link').subscribe((res: string) => {this.toaster.pop("error", res); });
});
}
@ -133,10 +135,10 @@ export class IrcBridgeConfigComponent extends BridgeComponent<IrcConfig> {
this.isUpdating = false;
const idx = this.bridge.config.links[channel.networkId].findIndex(c => c.channelName === channel.name);
if (idx !== -1) this.bridge.config.links[channel.networkId].splice(idx, 1);
this.toaster.pop("success", "Link removed");
this.translate.get('Link removed').subscribe((res: string) => {this.toaster.pop("success", res); });
}).catch(err => {
console.error(err);
this.toaster.pop("error", "Failed to remove link");
this.translate.get('Failed to remove link').subscribe((res: string) => {this.toaster.pop("error", res); });
});
}
}

View File

@ -2,30 +2,28 @@
<ng-template #bridgeParamsTemplate>
<my-ibox [isCollapsible]="false">
<h5 class="my-ibox-title">
Bridge to Slack
{{'Bridge to Slack' | translate}}
</h5>
<div class="my-ibox-content" *ngIf="loadingTeams">
<my-spinner></my-spinner>
</div>
<div class="my-ibox-content" *ngIf="!loadingTeams">
<div *ngIf="isBridged && bridge.config.link.isWebhook">
This room is bridged to Slack using webhooks. Webhook bridging is legacy and doesn't support as
rich bridging as the new approach. It is recommended to re-create the bridge with the new process.
{{'This room is bridged to Slack using webhooks. Webhook bridging is legacy and doesn\'t support as rich bridging as the new approach. It is recommended to re-create the bridge with the new process.' | translate}}
<br/>
<button type="button" class="btn btn-sm btn-danger" [disabled]="isBusy" (click)="unbridgeRoom()">
Unbridge
{{'Unbridge' | translate}}
</button>
</div>
<div *ngIf="isBridged && !bridge.config.link.isWebhook">
This room is bridged to "{{ bridge.config.link.channelName }}" on Slack.
<button type="button" class="btn btn-sm btn-danger" [disabled]="isBusy" (click)="unbridgeRoom()">
Unbridge
{{'Unbridge' | translate}}
</button>
</div>
<div *ngIf="!isBridged && needsAuth">
<p>
In order to bridge Slack channels, you'll need to authorize the bridge to access your teams
and channels. Please click the button below to do so.
{{'In order to bridge Slack channels, you\'ll need to authorize the bridge to access your teams and channels. Please click the button below to do so.' | translate}}
</p>
<a [href]="authUrl" rel="noopener" target="_blank">
<img src="/img/slack_auth_button.png" class="slack-auth-button" alt="sign in with slack"/>
@ -33,7 +31,7 @@
</div>
<div *ngIf="!isBridged && !needsAuth">
<label class="label-block">
Team
{{'Team' | translate}}
<select class="form-control form-control-sm" [(ngModel)]="teamId"
(change)="loadChannels()" [disabled]="isBusy">
<option *ngFor="let team of teams" [ngValue]="team.id">
@ -42,7 +40,7 @@
</select>
</label>
<label class="label-block">
Channel
{{'Channel' | translate}}
<select class="form-control form-control-sm" [(ngModel)]="channelId" [disabled]="isBusy">
<option *ngFor="let channel of channels" [ngValue]="channel.id">
{{ channel.name }}

View File

@ -4,6 +4,7 @@ import { FE_SlackChannel, FE_SlackLink, FE_SlackTeam } from "../../../shared/mod
import { SlackApiService } from "../../../shared/services/integrations/slack-api.service";
import { ScalarClientApiService } from "../../../shared/services/scalar/scalar-client-api.service";
import { DomSanitizer, SafeUrl } from "@angular/platform-browser";
import { TranslateService } from "@ngx-translate/core";
interface SlackConfig {
botUserId: string;
@ -27,8 +28,9 @@ export class SlackBridgeConfigComponent extends BridgeComponent<SlackConfig> imp
private timerId: any;
constructor(private slack: SlackApiService, private scalar: ScalarClientApiService, private sanitizer: DomSanitizer) {
super("slack");
constructor(private slack: SlackApiService, private scalar: ScalarClientApiService, private sanitizer: DomSanitizer, public translate: TranslateService) {
super("slack", translate);
this.translate = translate;
}
public ngOnInit() {
@ -58,7 +60,7 @@ export class SlackBridgeConfigComponent extends BridgeComponent<SlackConfig> imp
this.loadingTeams = false;
}).catch(error2 => {
console.error(error2);
this.toaster.pop("error", "Error getting Slack authorization information");
this.translate.get('Error getting Slack authorization information').subscribe((res: string) => {this.toaster.pop("error", res); });
});
this.timerId = setInterval(() => {
@ -67,7 +69,7 @@ export class SlackBridgeConfigComponent extends BridgeComponent<SlackConfig> imp
}
} else {
console.error(error);
this.toaster.pop("error", "Error getting teams");
this.translate.get('Error getting teams').subscribe((res: string) => {this.toaster.pop("error", res); });
}
});
}
@ -84,7 +86,7 @@ export class SlackBridgeConfigComponent extends BridgeComponent<SlackConfig> imp
this.isBusy = false;
}).catch(error => {
console.error(error);
this.toaster.pop("error", "Error getting channels for team");
this.translate.get('Error getting channels for team').subscribe((res: string) => {this.toaster.pop("error", res); });
this.isBusy = false;
});
}
@ -98,7 +100,7 @@ export class SlackBridgeConfigComponent extends BridgeComponent<SlackConfig> imp
if (!e.response || !e.response.error || !e.response.error._error ||
e.response.error._error.message.indexOf("already in the room") === -1) {
this.isBusy = false;
this.toaster.pop("error", "Error inviting bridge");
this.translate.get('Error inviting bridge').subscribe((res: string) => {this.toaster.pop("error", res); });
return;
}
}
@ -106,11 +108,11 @@ export class SlackBridgeConfigComponent extends BridgeComponent<SlackConfig> imp
this.slack.bridgeRoom(this.roomId, this.teamId, this.channelId).then(link => {
this.bridge.config.link = link;
this.isBusy = false;
this.toaster.pop("success", "Bridge requested");
this.translate.get('Bridge requested').subscribe((res: string) => {this.toaster.pop("success", res); });
}).catch(error => {
this.isBusy = false;
console.error(error);
this.toaster.pop("error", "Error requesting bridge");
this.translate.get('Error requesting bridge').subscribe((res: string) => {this.toaster.pop("error", res); });
});
}
@ -119,11 +121,11 @@ export class SlackBridgeConfigComponent extends BridgeComponent<SlackConfig> imp
this.slack.unbridgeRoom(this.roomId).then(() => {
this.bridge.config.link = null;
this.isBusy = false;
this.toaster.pop("success", "Bridge removed");
this.translate.get('Bridge removed').subscribe((res: string) => {this.toaster.pop("success", res); });
}).catch(error => {
this.isBusy = false;
console.error(error);
this.toaster.pop("error", "Error removing bridge");
this.translate.get('Error removing bridge').subscribe((res: string) => {this.toaster.pop("error", res); });
});
}
}

View File

@ -1,18 +1,17 @@
<div class="dialog">
<div class="dialog-header">
<h4>Telegram chat is already bridged</h4>
<h4>{{'Telegram chat is already bridged' | translate}}</h4>
</div>
<div class="dialog-content">
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?
{{'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">
Unbridge and continue
{{'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
<i class="far fa-times-circle"></i> {{'No, don\'t bridge' | translate}}
</button>
</div>
</div>

View File

@ -1,14 +1,13 @@
<div class="dialog">
<div class="dialog-header">
<h4>Telegram chat is already bridged</h4>
<h4>{{'Telegram chat is already bridged' | translate}}</h4>
</div>
<div class="dialog-content">
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.
{{'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">
<i class="far fa-times-circle"></i> Close
<i class="far fa-times-circle"></i> {{'Close' | translate}}
</button>
</div>
</div>

View File

@ -2,25 +2,25 @@
<ng-template #bridgeParamsTemplate>
<my-ibox [isCollapsible]="false">
<h5 class="my-ibox-title">
Bridge to Telegram
{{'Bridge to Telegram' | translate}}
</h5>
<div class="my-ibox-content">
<div *ngIf="isBridged">
This room is bridged to "{{ chatName }}" (<code>{{ chatId }}</code>) on Telegram.
{{'This room is bridged to on Telegram' | translate}} "{{ chatName }}" (<code>{{ chatId }}</code>) {{'on Telegram' | translate}}.
<div *ngIf="canUnbridge">
<button type="button" class="btn btn-sm btn-danger" [disabled]="isUpdating"
(click)="unbridgeRoom()">
Unbridge
{{'Unbridge' | translate}}
</button>
</div>
<span *ngIf="!canUnbridge">
You do not have the necessary permissions in this room to unbridge the channel.
{{'You do not have the necessary permissions in this room to unbridge the channel.' | translate}}
</span>
</div>
<div *ngIf="!isBridged">
<label class="label-block">
Chat ID
<span class="text-muted">After inviting <a href="https://t.me/{{ botUsername }}" target="_blank">@{{ botUsername }}</a> to your Telegram chat, run the command <code>/id</code> in the Telegram room to get the chat ID.</span>
<span class="text-muted">{{'After inviting' | translate}} <a href="https://t.me/{{ botUsername }}" target="_blank">@{{ botUsername }}</a> {{'to your Telegram chat, run the command' | translate}} <code>/id</code> {{'in the Telegram room to get the chat ID.' | translate}}</span>
<input title="chat ID" type="text" class="form-control form-control-sm col-md-3"
[(ngModel)]="chatId" [disabled]="isUpdating"/>
</label>

View File

@ -8,6 +8,7 @@ import {
CannotUnbridgeDialogContext,
TelegramCannotUnbridgeComponent
} from "./cannot-unbridge/cannot-unbridge.component";
import { TranslateService } from "@ngx-translate/core";
interface TelegramConfig {
puppet: {
@ -39,8 +40,9 @@ export class TelegramBridgeConfigComponent extends BridgeComponent<TelegramConfi
public isUpdating: boolean;
constructor(private telegram: TelegramApiService, private modal: Modal) {
super("telegram");
constructor(private telegram: TelegramApiService, private modal: Modal, public translate: TranslateService) {
super("telegram", translate);
this.translate = translate;
}
public get isBridged(): boolean {
@ -103,20 +105,20 @@ export class TelegramBridgeConfigComponent extends BridgeComponent<TelegramConfi
this.bridge.config.portalInfo = portalInfo;
this.bridge.config.linked = [portalInfo.chatId];
this.isUpdating = false;
this.toaster.pop("success", "Bridge updated");
this.translate.get('Bridge updated').subscribe((res: string) => {this.toaster.pop("success", res); });
}).catch(error => {
this.isUpdating = false;
console.error(error);
const body = error.json ? error.json() : null;
let message = "Error bridging room";
let message = 'Error bridging room';
if (body) {
if (body["dim_errcode"] === "CHAT_ALREADY_BRIDGED") message = "That Telegram chat is already bridged to another room";
if (body["dim_errcode"] === "ROOM_ALREADY_BRIDGED") message = "This room is already bridged to a Telegram chat";
if (body["dim_errcode"] === "BOT_NOT_IN_CHAT") message = "The Telegram bot has not been invited to the chat";
if (body["dim_errcode"] === "NOT_ENOUGH_PERMISSIONS") message = "You do not have permission to bridge that chat";
if (body["dim_errcode"] === "CHAT_ALREADY_BRIDGED") message = 'That Telegram chat is already bridged to another room';
if (body["dim_errcode"] === "ROOM_ALREADY_BRIDGED") message = 'This room is already bridged to a Telegram chat';
if (body["dim_errcode"] === "BOT_NOT_IN_CHAT") message = 'The Telegram bot has not been invited to the chat';
if (body["dim_errcode"] === "NOT_ENOUGH_PERMISSIONS") message = 'You do not have permission to bridge that chat';
}
this.toaster.pop("error", message);
this.translate.get(message).subscribe((res: string) => {this.toaster.pop("error", res); });
});
}
@ -126,18 +128,17 @@ export class TelegramBridgeConfigComponent extends BridgeComponent<TelegramConfi
this.bridge.config.portalInfo = portalInfo;
this.bridge.config.linked = [];
this.isUpdating = false;
this.toaster.pop("success", "Bridge removed");
this.translate.get('Bridge removed').subscribe((res: string) => {this.toaster.pop("success", res); });
}).catch(error => {
this.isUpdating = false;
console.error(error);
const body = error.json ? error.json() : null;
let message = "Error removing bridge";
let message = 'Error removing bridge';
if (body) {
if (body["dim_errcode"] === "BOT_NOT_IN_CHAT") message = "The Telegram bot has not been invited to the chat";
if (body["dim_errcode"] === "NOT_ENOUGH_PERMISSIONS") message = "You do not have permission to unbridge that chat";
if (body["dim_errcode"] === "BOT_NOT_IN_CHAT") message = 'The Telegram bot has not been invited to the chat';
if (body["dim_errcode"] === "NOT_ENOUGH_PERMISSIONS") message = 'You do not have permission to unbridge that chat';
}
this.toaster.pop("error", message);
this.translate.get(message).subscribe((res: string) => {this.toaster.pop("error", res); });
});
}
}

View File

@ -2,17 +2,17 @@
<ng-template #bridgeParamsTemplate>
<my-ibox [isCollapsible]="true">
<h5 class="my-ibox-title">
Add a new webhook
{{'Add a new webhook' | translate}}
</h5>
<div class="my-ibox-content">
<label class="label-block">
Webhook Name
{{'Webhook Name' | translate}}
<input title="webhook name" type="text" class="form-control form-control-sm"
[(ngModel)]="webhookName" [disabled]="isBusy">
</label>
<div style="margin-top: 25px">
<button type="button" class="btn btn-sm btn-primary" [disabled]="isBusy" (click)="newHook()">
Create
{{'Create' | translate}}
</button>
</div>
</div>
@ -26,25 +26,25 @@
<thead>
<tr>
<th>Name</th>
<th>Type</th>
<th>{{'Type' | translate}}</th>
<th>URL</th>
<th class="actions-col">Actions</th>
<th class="actions-col">{{'Actions' | translate}}</th>
</tr>
</thead>
<tbody>
<tr *ngIf="newConfig.webhooks.length === 0">
<td colspan="4">No webhooks</td>
<td colspan="4">{{'No webhooks' | translate}}</td>
</tr>
<tr *ngFor="let hook of newConfig.webhooks">
<td *ngIf="hook.label">{{ hook.label }}</td>
<td *ngIf="!hook.label"><i>No name</i></td>
<td *ngIf="!hook.label"><i>{{'No name' | translate}}</i></td>
<td>{{ hook.type }}</td>
<td class="webhook-url"><a [href]="hook.url" target="_blank">{{ hook.url }}</a></td>
<td class="actions-col">
<button type="button" class="btn btn-sm btn-outline-danger"
[disabled]="isBusy"
(click)="removeHook(hook)">
<i class="far fa-trash-alt"></i> Delete
<i class="far fa-trash-alt"></i> {{'Delete' | translate}}
</button>
</td>
</tr>

View File

@ -3,6 +3,7 @@ import { BridgeComponent } from "../bridge.component";
import { FE_Webhook } from "../../../shared/models/webhooks";
import { WebhooksApiService } from "../../../shared/services/integrations/webhooks-api.service";
import { ScalarClientApiService } from "../../../shared/services/scalar/scalar-client-api.service";
import { TranslateService } from "@ngx-translate/core";
interface WebhooksConfig {
webhooks: FE_Webhook[];
@ -18,8 +19,8 @@ export class WebhooksBridgeConfigComponent extends BridgeComponent<WebhooksConfi
public webhookName: string;
public isBusy = false;
constructor(private webhooks: WebhooksApiService, private scalar: ScalarClientApiService) {
super("webhooks");
constructor(private webhooks: WebhooksApiService, private scalar: ScalarClientApiService, public translate: TranslateService) {
super("webhooks", translate);
}
public async newHook() {
@ -31,7 +32,7 @@ export class WebhooksBridgeConfigComponent extends BridgeComponent<WebhooksConfi
if (!e.response || !e.response.error || !e.response.error._error ||
e.response.error._error.message.indexOf("already in the room") === -1) {
this.isBusy = false;
this.toaster.pop("error", "Error inviting bridge");
this.translate.get('Error inviting bridge').subscribe((res: string) => {this.toaster.pop("error", res); });
return;
}
}
@ -40,11 +41,11 @@ export class WebhooksBridgeConfigComponent extends BridgeComponent<WebhooksConfi
this.newConfig.webhooks.push(hook);
this.isBusy = false;
this.webhookName = "";
this.toaster.pop("success", "Webhook created");
this.translate.get('Webhook created').subscribe((res: string) => {this.toaster.pop("success", res); });
}).catch(err => {
console.error(err);
this.isBusy = false;
this.toaster.pop("error", "Error creating webhook");
this.translate.get('Error creating webhook').subscribe((res: string) => {this.toaster.pop("error", res); });
});
}
@ -54,11 +55,11 @@ export class WebhooksBridgeConfigComponent extends BridgeComponent<WebhooksConfi
const idx = this.newConfig.webhooks.indexOf(hook);
if (idx !== -1) this.newConfig.webhooks.splice(idx, 1);
this.isBusy = false;
this.toaster.pop("success", "Webhook deleted");
this.translate.get('Webhook deleted').subscribe((res: string) => {this.toaster.pop("success", res); });
}).catch(err => {
console.error(err);
this.isBusy = false;
this.toaster.pop("error", "Error deleting webhook");
this.translate.get('Error deleting webhook').subscribe((res: string) => {this.toaster.pop("error", res); });
});
}
}

View File

@ -6,6 +6,7 @@ import { IntegrationsApiService } from "../../shared/services/integrations/integ
import { ToasterService } from "angular2-toaster";
import { ServiceLocator } from "../../shared/registry/locator.service";
import { ScalarClientApiService } from "../../shared/services/scalar/scalar-client-api.service";
import { TranslateService } from "@ngx-translate/core";
export class ComplexBotComponent<T> implements OnInit, OnDestroy {
@ -22,7 +23,7 @@ export class ComplexBotComponent<T> implements OnInit, OnDestroy {
protected route = ServiceLocator.injector.get(ActivatedRoute);
protected scalarClientApi = ServiceLocator.injector.get(ScalarClientApiService);
constructor(private integrationType: string) {
constructor(private integrationType: string, public translate: TranslateService) {
this.isLoading = true;
this.isUpdating = false;
}
@ -50,20 +51,20 @@ export class ComplexBotComponent<T> implements OnInit, OnDestroy {
this.isLoading = false;
}).catch(err => {
console.error(err);
this.toaster.pop("error", "Failed to load configuration");
this.translate.get("Failed to load configuration").subscribe((res: string) => {this.toaster.pop("error", res); });
});
}
public save(): void {
this.isUpdating = true;
this.integrationsApi.setIntegrationConfiguration("complex-bot", this.integrationType, this.roomId, this.newConfig).then(() => {
this.toaster.pop("success", "Configuration updated");
this.translate.get("Configuration updated").subscribe((res: string) => {this.toaster.pop("success", res); });
this.bot.config = this.newConfig;
this.newConfig = JSON.parse(JSON.stringify(this.bot.config));
this.isUpdating = false;
}).catch(err => {
console.error(err);
this.toaster.pop("error", "Error updating configuration");
this.translate.get("Error updating configuration").subscribe((res: string) => {this.toaster.pop("error", res); });
this.isUpdating = false;
});
}

View File

@ -2,7 +2,7 @@
<ng-template #botParamsTemplate>
<my-ibox>
<h5 class="my-ibox-title">
Feeds
{{'Feeds' | translate}}
</h5>
<div class="my-ibox-content">
<form (submit)="interceptSave()" novalidate name="saveForm">
@ -10,8 +10,8 @@
<thead>
<tr>
<th>URL</th>
<th>Added by</th>
<th class="actions-col">Actions</th>
<th>{{'Added by' | translate}}</th>
<th class="actions-col">{{'Actions' | translate}}</th>
</tr>
</thead>
<tbody>
@ -22,7 +22,7 @@
<button type="button" class="btn btn-sm btn-outline-danger"
[disabled]="isUpdating || !feed.isSelf"
(click)="removeFeed(feed)">
<i class="far fa-trash-alt"></i> Remove
<i class="far fa-trash-alt"></i> {{'Remove' | translate}}
</button>
</td>
</tr>
@ -38,7 +38,7 @@
<button type="button" class="btn btn-outline-success"
[disabled]="isUpdating"
(click)="addFeed()">
<i class="fa fa-plus"></i> Add
<i class="fa fa-plus"></i> {{'Add' | translate}}
</button>
</span>
</div>
@ -48,7 +48,7 @@
</table>
<div style="margin-top: 25px">
<button type="submit" class="btn btn-sm btn-primary" [disabled]="isUpdating">
<i class="far fa-save"></i> Save
<i class="far fa-save"></i> {{'Save' | translate}}
</button>
</div>
</form>

View File

@ -1,6 +1,7 @@
import { ComplexBotComponent } from "../complex-bot.component";
import { Component } from "@angular/core";
import { SessionStorage } from "../../../shared/SessionStorage";
import { TranslateService } from "@ngx-translate/core";
interface RssConfig {
feeds: {
@ -24,13 +25,14 @@ export class RssComplexBotConfigComponent extends ComplexBotComponent<RssConfig>
public newFeedUrl = "";
constructor() {
super("rss");
constructor(public translate: TranslateService) {
super("rss", translate);
this.translate = translate;
}
public addFeed(): void {
if (!this.newFeedUrl.trim()) {
this.toaster.pop('warning', 'Please enter a feed URL');
this.translate.get('Please enter a feed URL').subscribe((res: string) => {this.toaster.pop('warning', res); });
return;
}

View File

@ -2,50 +2,49 @@
<ng-template #botParamsTemplate>
<my-ibox [isCollapsible]="true">
<h5 class="my-ibox-title">
.travis.yml configuration and template information
{{'.travis.yml configuration and template information' | translate}}
</h5>
<div class="my-ibox-content">
<p>
The following section needs to be added to your <code>.travis.yml</code> file in your repositories:
{{'The following section needs to be added to your' | translate}} <code>.travis.yml</code> {{'file in your repositories:' | translate}}
</p>
<pre>{{ travisYaml }}</pre>
<p>
The following variables can be used in your template. This template is used to post a message to the
room when your webhook is activated.
{{'The following variables can be used in your template. This template is used to post a message to theroom when your webhook is activated.' | translate}}
</p>
<ul>
<li><code>{{ '%{repository_slug}' }}</code> - The repository identifier (eg: "matrix-org/synapse")</li>
<li><code>{{ '%{repository_name}' }}</code> - The repository name (eg: "synapse")</li>
<li><code>{{ '%{build_number}' }}</code> - The build number</li>
<li><code>{{ '%{build_id}' }}</code> - The build ID</li>
<li><code>{{ '%{branch}' }}</code> - The branch name</li>
<li><code>{{ '%{commit}' }}</code> - A short version of the commit SHA</li>
<li><code>{{ '%{commit_subject}' }}</code> - The first line of the commit message</li>
<li><code>{{ '%{commit_message}' }}</code> - The full commit message</li>
<li><code>{{ '%{author}' }}</code> - The author of the commit</li>
<li><code>{{ '%{result}' }}</code> - The result of the build</li>
<li><code>{{ '%{message}' }}</code> - The message from Travis CI about the build</li>
<li><code>{{ '%{duration}' }}</code> - The total duration of all builds in the matrix</li>
<li><code>{{ '%{elapsed_timed}' }}</code> - The time it took to run the build</li>
<li><code>{{ '%{compare_url}' }}</code> - A URL to see the changes which triggered the build</li>
<li><code>{{ '%{build_url}' }}</code> - A URL to see the build information</li>
<li><code>{{ '%{repository_slug}' }}</code> - {{'The repository identifier' | translate}} (eg: "matrix-org/synapse")</li>
<li><code>{{ '%{repository_name}' }}</code> - {{'The repository name' | translate}} (eg: "synapse")</li>
<li><code>{{ '%{build_number}' }}</code> - {{'The build number' | translate}}</li>
<li><code>{{ '%{build_id}' }}</code> - {{'The build ID' | translate}}</li>
<li><code>{{ '%{branch}' }}</code> - {{'The branch name' | translate}}</li>
<li><code>{{ '%{commit}' }}</code> - {{'A short version of the commit SHA' | translate}}</li>
<li><code>{{ '%{commit_subject}' }}</code> - {{'The first line of the commit message' | translate}}</li>
<li><code>{{ '%{commit_message}' }}</code> - {{'The full commit message' | translate}}</li>
<li><code>{{ '%{author}' }}</code> - {{'The author of the commit' | translate}}</li>
<li><code>{{ '%{result}' }}</code> - {{'The result of the build' | translate}}</li>
<li><code>{{ '%{message}' }}</code> - {{'The message from Travis CI about the build' | translate}}</li>
<li><code>{{ '%{duration}' }}</code> - {{'The total duration of all builds in the matrix' | translate}}</li>
<li><code>{{ '%{elapsed_timed}' }}</code> - {{'The time it took to run the build' | translate}}</li>
<li><code>{{ '%{compare_url}' }}</code> - {{'A URL to see the changes which triggered the build' | translate}}</li>
<li><code>{{ '%{build_url}' }}</code> - {{'A URL to see the build information' | translate}}</li>
</ul>
</div>
</my-ibox>
<my-ibox>
<h5 class="my-ibox-title">
Repositories
{{'Repositories' | translate}}
</h5>
<div class="my-ibox-content">
<form (submit)="interceptSave()" novalidate name="saveForm">
<table class="table table-striped table-condensed table-bordered">
<thead>
<tr>
<th>Repository</th>
<th>Template</th>
<th>Added by</th>
<th class="actions-col">Actions</th>
<th>{{'Repository' | translate}}</th>
<th>{{'Template' | translate}}</th>
<th>{{'Added by' | translate}}</th>
<th class="actions-col">{{'Actions' | translate}}</th>
</tr>
</thead>
<tbody>
@ -61,7 +60,7 @@
<button type="button" class="btn btn-sm btn-outline-danger"
[disabled]="isUpdating || !repo.isSelf"
(click)="removeRepo(repo)">
<i class="far fa-trash-alt"></i> Remove
<i class="far fa-trash-alt"></i> {{'Remove' | translate}}
</button>
</td>
</tr>
@ -77,7 +76,7 @@
<button type="button" class="btn btn-outline-success"
[disabled]="isUpdating"
(click)="addRepo()">
<i class="fa fa-plus"></i> Add
<i class="fa fa-plus"></i> {{'Add' | translate}}
</button>
</span>
</div>
@ -87,7 +86,7 @@
</table>
<div style="margin-top: 25px">
<button type="submit" class="btn btn-sm btn-primary" [disabled]="isUpdating">
<i class="far fa-save"></i> Save
<i class="far fa-save"></i> {{'Save' | translate}}
</button>
</div>
</form>

View File

@ -1,6 +1,7 @@
import { ComplexBotComponent } from "../complex-bot.component";
import { Component } from "@angular/core";
import { SessionStorage } from "../../../shared/SessionStorage";
import { TranslateService } from "@ngx-translate/core";
interface TravisCiConfig {
webhookId: string;
@ -27,8 +28,9 @@ export class TravisCiComplexBotConfigComponent extends ComplexBotComponent<Travi
public newRepoKey = "";
constructor() {
super("travisci");
constructor(public translate: TranslateService) {
super("travisci", translate);
this.translate = translate;
}
public get webhookUrl(): string {
@ -50,7 +52,7 @@ export class TravisCiComplexBotConfigComponent extends ComplexBotComponent<Travi
public addRepo(): void {
if (!this.newRepoKey.trim()) {
this.toaster.pop('warning', 'Please enter a repository');
this.translate.get('Please enter a repository').subscribe((res: string) => {this.toaster.pop('warning', res); });
return;
}

View File

@ -8,7 +8,7 @@
</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
<i class="far fa-times-circle"></i> {{'Close' | translate}}
</button>
</div>
</div>

View File

@ -5,6 +5,7 @@ import { ScalarClientApiService } from "../../shared/services/scalar/scalar-clie
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";
export class SimpleBotConfigDialogContext extends BSModalContext {
public bot: FE_SimpleBot;
@ -24,7 +25,9 @@ export class ConfigSimpleBotComponent {
constructor(public dialog: DialogRef<SimpleBotConfigDialogContext>,
private toaster: ToasterService,
private scalar: ScalarClientApiService,
private integrationsApi: IntegrationsApiService) {
private integrationsApi: IntegrationsApiService,
public translate: TranslateService) {
this.translate = translate;
this.bot = dialog.context.bot;
this.roomId = dialog.context.roomId;
@ -41,8 +44,11 @@ export class ConfigSimpleBotComponent {
this.bot._isUpdating = true;
promise.then(() => {
this.bot._isUpdating = false;
if (this.bot._inRoom) this.toaster.pop("success", this.bot.displayName + " was invited to the room");
else this.toaster.pop("success", this.bot.displayName + " was removed from the room");
if (this.bot._inRoom) {
this.translate.get('was invited to the room').subscribe((res: string) => {this.toaster.pop("success", this.bot.displayName + res); });
} else {
this.translate.get('was removed from the room').subscribe((res: string) => {this.toaster.pop("success", this.bot.displayName + res); });
}
}).catch(err => {
this.bot._inRoom = !this.bot._inRoom; // revert the status change
this.bot._isUpdating = false;
@ -51,9 +57,8 @@ export class ConfigSimpleBotComponent {
let errorMessage = null;
if (err.json) errorMessage = err.json().error;
if (err.response && err.response.error) errorMessage = err.response.error.message;
if (!errorMessage) errorMessage = "Could not update integration status";
this.toaster.pop("error", errorMessage);
if (!errorMessage) errorMessage = "";
this.translate.get('Could not update integration status').subscribe((res: string) => {this.toaster.pop("error", res); });
});
}
}

View File

@ -4,7 +4,7 @@
<div *ngIf="!isLoading">
<my-ibox boxTitle="Sticker Packs" *ngIf="packs.length <= 0 && !customEnabled">
<div class="my-ibox-content">
<h5 style="text-align: center;">Sticker packs are not enabled on this Dimension instance.</h5>
<h5 style="text-align: center;">{{'Sticker packs are not enabled on this Dimension instance.' | translate}}</h5>
</div>
</my-ibox>
<my-ibox boxTitle="Add Sticker Packs" *ngIf="customEnabled">
@ -12,14 +12,14 @@
<form (submit)="importPack()" novalidate name="importForm">
<label class="label-block">
Stickerpack URL
<span class="text-muted">Start a conversation with {{stickerBot}} to create your own stickerpack.</span>
<span class="text-muted">{{'Start a conversation with' | translate}} {{stickerBot}} {{'to create your own stickerpack.' | translate}}</span>
<input type="text" class="form-control" name="packUrl"
placeholder="{{managerUrl}}/pack/..."
[(ngModel)]="packUrl" [disabled]="isImporting"/>
</label>
<div style="margin-top: 25px">
<button type="submit" class="btn btn-sm btn-success" [disabled]="isImporting">
<i class="fa fa-plus"></i> Add stickerpack
<i class="fa fa-plus"></i> {{'Add stickerpack' | translate}}
</button>
</div>
</form>
@ -33,11 +33,11 @@
<ui-switch [checked]="pack.isSelected" size="medium" [disabled]="isUpdating"
(change)="toggleSelected(pack)" class="toggle-switch"></ui-switch>
<span class="name">{{ pack.displayName }}</span>
<span class="description">{{ pack.description }}</span>
<span class="name">{{ pack.displayName | translate}}</span>
<span class="description">{{ pack.description | translate}}</span>
<span class="author" *ngIf="pack.author.type !== 'none'">Created by <a
[href]="pack.author.reference">{{ pack.author.name }}</a> under </span>
<span class="author" *ngIf="pack.author.type !== 'none'">{{'Created by' | translate}} <a
[href]="pack.author.reference">{{ pack.author.name }}</a> {{'under' | translate}} </span>
<span class="license"><a [href]="pack.license.urlPath">{{ pack.license.name }}</a></span>
</div>
</div>

View File

@ -5,6 +5,7 @@ import { ToasterService } from "angular2-toaster";
import { MediaService } from "../../shared/services/media.service";
import { ScalarClientApiService } from "../../shared/services/scalar/scalar-client-api.service";
import { WIDGET_STICKER_PICKER } from "../../shared/models/widget";
import { TranslateService } from "@ngx-translate/core";
@Component({
templateUrl: "stickerpicker.component.html",
@ -27,7 +28,9 @@ export class StickerpickerComponent implements OnInit {
private media: MediaService,
private scalarClient: ScalarClientApiService,
private toaster: ToasterService,
private window: Window) {
private window: Window,
public translate?: TranslateService) {
this.translate = translate;
this.isLoading = true;
this.isUpdating = false;
}
@ -38,7 +41,7 @@ export class StickerpickerComponent implements OnInit {
this.isLoading = false;
} catch (e) {
console.error(e);
this.toaster.pop("error", "Failed to load sticker packs");
this.translate.get('Failed to load sticker packs').subscribe((res: string) => {this.toaster.pop("error", res); });
}
this.stickerApi.getConfig().then(config => {
@ -55,12 +58,12 @@ export class StickerpickerComponent implements OnInit {
this.packs.splice(0, 0, pack);
this.packUrl = "";
this.isImporting = false;
this.toaster.pop("success", "Stickerpack added");
this.translate.get('Stickerpack added').subscribe((res: string) => {this.toaster.pop("success", res); });
this.addWidget();
}).catch(err => {
console.error(err);
this.isImporting = false;
this.toaster.pop("error", "Error adding stickerpack");
this.translate.get('Error adding stickerpack').subscribe((res: string) => {this.toaster.pop("error", res); });
});
}
@ -73,14 +76,13 @@ export class StickerpickerComponent implements OnInit {
this.isUpdating = true;
this.stickerApi.togglePackSelection(pack.id, pack.isSelected).then(() => {
this.isUpdating = false;
this.toaster.pop("success", "Stickers updated");
this.translate.get('Stickers updated').subscribe((res: string) => {this.toaster.pop("success", res); });
if (this.packs.filter(p => p.isSelected).length > 0) this.addWidget();
}).catch(err => {
console.error(err);
pack.isSelected = !pack.isSelected; // revert change
this.isUpdating = false;
this.toaster.pop("error", "Error updating stickers");
this.translate.get('Error updating stickers').subscribe((res: string) => {this.toaster.pop("error", res); });
});
}

View File

@ -4,7 +4,7 @@
<div *ngIf="!widgetComponent.isLoading">
<my-ibox [isCollapsible]="true" [defaultCollapsed]="widgetComponent.defaultExpandedWidgetId">
<h5 class="my-ibox-title">
<i class="far fa-plus-square"></i> Add {{ widgetComponent.defaultName }}
<i class="far fa-plus-square"></i> {{ widgetComponent.defaultName | translate }} {{'Add' | translate}}
</h5>
<div class="my-ibox-content">
<form (submit)="widgetComponent.addWidget()" novalidate name="addForm">
@ -13,7 +13,7 @@
<div style="margin-top: 25px">
<button type="submit" class="btn btn-sm btn-success" [disabled]="widgetComponent.isUpdating">
<i class="fa fa-plus"></i> Add Widget
<i class="fa fa-plus"></i> {{'Add Widget' | translate}}
</button>
</div>
</form>
@ -32,11 +32,11 @@
<div style="margin-top: 25px">
<button type="submit" class="btn btn-sm btn-primary" [disabled]="widgetComponent.isUpdating">
<i class="far fa-save"></i> Save Widget
<i class="far fa-save"></i>{{'Save Widget' | translate}}
</button>
<button type="button" class="btn btn-sm btn-outline-danger" [disabled]="widgetComponent.isUpdating"
<button type="button" class="btn btn-sm ml-1 btn-outline-danger" [disabled]="widgetComponent.isUpdating"
(click)="widgetComponent.removeWidget(widget)">
<i class="far fa-trash-alt"></i> Remove Widget
<i class="far fa-trash-alt"></i>{{'Remove Widget' | translate}}
</button>
</div>
</form>

View File

@ -1,14 +1,14 @@
<my-widget-config [widgetComponent]="this">
<ng-template #widgetParamsTemplate let-widget="widget">
<label class="label-block">
Widget Name
{{'Widget Name' | translate}}
<input type="text" class="form-control"
placeholder="{{ defaultName }}"
placeholder="{{ defaultName | translate}}"
[(ngModel)]="widget.dimension.newName" name="widget-name-{{widget.id}}"
[disabled]="isUpdating"/>
</label>
<label class="label-block">
Widget URL
{{'Widget URL' | translate}}
<input type="text" class="form-control"
placeholder="https://matrix.org"
[(ngModel)]="widget.dimension.newUrl" name="widget-url-{{widget.id}}"

View File

@ -1,13 +1,14 @@
import { WidgetComponent } from "../widget.component";
import { WIDGET_CUSTOM } from "../../../shared/models/widget";
import { Component } from "@angular/core";
import { TranslateService } from "@ngx-translate/core";
@Component({
templateUrl: "custom.widget.component.html",
styleUrls: ["custom.widget.component.scss"],
})
export class CustomWidgetConfigComponent extends WidgetComponent {
constructor() {
super(WIDGET_CUSTOM, "Custom Widget", "generic");
constructor(public translate: TranslateService) {
super(WIDGET_CUSTOM, "Custom Widget", "generic", translate);
}
}

View File

@ -1,14 +1,14 @@
<my-widget-config [widgetComponent]="this">
<ng-template #widgetParamsTemplate let-widget="widget">
<label class="label-block">
Pad Name
{{'Pad Name' | translate}}
<input type="text" class="form-control"
placeholder="{{ defaultName }}"
[(ngModel)]="widget.dimension.newName" name="widget-name-{{widget.id}}"
[disabled]="isUpdating"/>
</label>
<label class="label-block">
Pad URL
{{'Pad URL' | translate}}
<input type="text" class="form-control"
placeholder="https://scalar.vector.im/etherpad/p/MyCoolPadName"
[(ngModel)]="widget.dimension.newUrl" name="widget-url-{{widget.id}}"

View File

@ -5,6 +5,7 @@ import { FE_EtherpadWidget } from "../../../shared/models/integration";
import { SessionStorage } from "../../../shared/SessionStorage";
import { NameService } from "../../../shared/services/name.service";
import * as url from "url";
import { TranslateService } from "@ngx-translate/core";
@Component({
templateUrl: "etherpad.widget.component.html",
@ -14,8 +15,8 @@ export class EtherpadWidgetConfigComponent extends WidgetComponent {
private etherpadWidget: FE_EtherpadWidget = <FE_EtherpadWidget>SessionStorage.editIntegration;
constructor(private nameService: NameService) {
super(WIDGET_ETHERPAD, "Etherpad", "generic", "etherpad", "padName");
constructor(private nameService: NameService, public translate: TranslateService) {
super(WIDGET_ETHERPAD, "Notes", "generic", translate ,"etherpad", "padName");
}
protected OnWidgetsDiscovered(widgets: EditableWidget[]): void {

View File

@ -1,7 +1,7 @@
<my-widget-config [widgetComponent]="this">
<ng-template #widgetParamsTemplate let-widget="widget">
<label class="label-block">
Shared Calendar ID
{{'Shared Calendar ID' | translate}}
<input type="text" class="form-control"
placeholder="en.uk#holiday@group.v.calendar.google.com"
[(ngModel)]="widget.dimension.newData.shareId" name="widget-url-{{widget.id}}"

View File

@ -1,14 +1,15 @@
import { DISABLE_AUTOMATIC_WRAPPING, WidgetComponent } from "../widget.component";
import { EditableWidget, WIDGET_GOOGLE_CALENDAR } from "../../../shared/models/widget";
import { Component } from "@angular/core";
import { TranslateService } from "@ngx-translate/core";
@Component({
templateUrl: "gcal.widget.component.html",
styleUrls: ["gcal.widget.component.scss"],
})
export class GoogleCalendarWidgetConfigComponent extends WidgetComponent {
constructor() {
super(WIDGET_GOOGLE_CALENDAR, "Google Calendar", DISABLE_AUTOMATIC_WRAPPING, "googleCalendar");
constructor(public translate: TranslateService) {
super(WIDGET_GOOGLE_CALENDAR, "Google Calendar", DISABLE_AUTOMATIC_WRAPPING, translate , "googleCalendar");
}
protected OnNewWidgetPrepared(widget: EditableWidget) {

View File

@ -1,7 +1,7 @@
<my-widget-config [widgetComponent]="this">
<ng-template #widgetParamsTemplate let-widget="widget">
<label class="label-block">
Document URL
{{'Document URL' | translate}}
<input type="text" class="form-control"
placeholder="https://docs.google.com/document/d/1V0olL42WJ84LNYn0kFBJaPmlRxQ4Trx97a5wfVMuJC8/edit"
[(ngModel)]="widget.dimension.newUrl" name="widget-url-{{widget.id}}"

View File

@ -1,13 +1,14 @@
import { WidgetComponent } from "../widget.component";
import { WIDGET_GOOGLE_DOCS } from "../../../shared/models/widget";
import { Component } from "@angular/core";
import { TranslateService } from "@ngx-translate/core";
@Component({
templateUrl: "gdoc.widget.component.html",
styleUrls: ["gdoc.widget.component.scss"],
})
export class GoogleDocsWidgetConfigComponent extends WidgetComponent {
constructor() {
super(WIDGET_GOOGLE_DOCS, "Google Doc", "generic", "googleDocs");
constructor(public translate: TranslateService) {
super(WIDGET_GOOGLE_DOCS, "Google Doc", "generic", translate , "googleDocs");
}
}

View File

@ -1,15 +1,15 @@
<my-widget-config [widgetComponent]="this">
<ng-template #widgetParamsTemplate let-widget="widget">
<label class="label-block">
Grafana URL
<span class="text-muted">To get a URL, go to Grafana and click "share" on a graph.</span>
{{'Grafana URL' | translate}}
<span class="text-muted">{{'To get a URL, go to Grafana and click \'share\' on a graph.' | translate}}</span>
<input type="text" class="form-control"
placeholder="https://example.com/grafana/dashboard/db/example?orgId=1&panelId=1&fullscreen"
[(ngModel)]="widget.dimension.newData.url" name="widget-url-{{widget.id}}"
[disabled]="isUpdating"/>
</label>
<label class="label-block">
Widget Name
{{'Widget Name' | translate}}
<input type="text" class="form-control"
placeholder="{{ defaultName }}"
[(ngModel)]="widget.dimension.newName" name="widget-name-{{widget.id}}"

Some files were not shown because too many files have changed in this diff Show More