ESLint config, fix easy eslint errors

This commit is contained in:
Tony Stipanic 2021-09-02 01:01:01 +02:00
parent 87d15d8e01
commit f06ead08d8
No known key found for this signature in database
GPG Key ID: 3026BCCB6C9CC6BD
81 changed files with 1625 additions and 1115 deletions

View File

@ -14,6 +14,9 @@
], ],
"createDefaultProgram": true "createDefaultProgram": true
}, },
"plugins": [
"@typescript-eslint"
],
"extends": [ "extends": [
"plugin:@angular-eslint/recommended", "plugin:@angular-eslint/recommended",
"plugin:@angular-eslint/template/process-inline-templates" "plugin:@angular-eslint/template/process-inline-templates"
@ -34,7 +37,74 @@
"prefix": "app", "prefix": "app",
"style": "kebab-case" "style": "kebab-case"
} }
] ],
"@typescript-eslint/dot-notation": "off",
"@typescript-eslint/explicit-member-accessibility": [
"off",
{
"accessibility": "explicit"
}
],
"@typescript-eslint/indent": "error",
"@typescript-eslint/member-delimiter-style": [
"off",
{
"multiline": {
"delimiter": "none",
"requireLast": true
},
"singleline": {
"delimiter": "semi",
"requireLast": false
}
}
],
"@typescript-eslint/member-ordering": "off",
"@typescript-eslint/naming-convention": "off",
"@typescript-eslint/no-empty-function": "off",
"@typescript-eslint/no-inferrable-types": "error",
"@typescript-eslint/no-unused-expressions": "error",
"@typescript-eslint/no-use-before-define": "off",
"@typescript-eslint/quotes": "off",
"@typescript-eslint/semi": [
"off",
null
],
"@typescript-eslint/type-annotation-spacing": "error",
"brace-style": [
"error",
"1tbs"
],
"curly": "off",
"eol-last": "off",
"eqeqeq": [
"error",
"always"
],
"guard-for-in": "off",
"id-blacklist": "off",
"id-match": "off",
"max-len": "off",
"no-bitwise": "off",
"no-caller": "error",
"no-console": "off",
"no-debugger": "error",
"no-empty": "off",
"no-eval": "error",
"no-fallthrough": "error",
"no-new-wrappers": "error",
"no-redeclare": "error",
"no-shadow": [
"error",
{
"hoist": "all"
}
],
"no-trailing-spaces": "error",
"no-underscore-dangle": "off",
"no-unused-labels": "error",
"no-var": "error",
"radix": "error"
} }
}, },
{ {

View File

@ -9,13 +9,12 @@
"start:web": "ng serve --configuration development --port 8082", "start:web": "ng serve --configuration development --port 8082",
"start:app": "npm run-script build && node build/app/index.js", "start:app": "npm run-script build && node build/app/index.js",
"start:apponly": "ts-node-dev --respawn --transpile-only --project tsconfig.backend.json ./src/index.ts", "start:apponly": "ts-node-dev --respawn --transpile-only --project tsconfig.backend.json ./src/index.ts",
"node:start:apponly": "npm run-script build:app && node build/app/index.js",
"build": "npm run-script build:web && npm run-script build:app", "build": "npm run-script build:web && npm run-script build:app",
"build:web": "rimraf build/web && ng build --configuration production", "build:web": "rimraf build/web && ng build --configuration production",
"build:app": "rimraf build/app && tsc -p tsconfig.backend.json", "build:app": "rimraf build/app && tsc -p tsconfig.backend.json",
"lint": "npm run-script lint:app && npm run-script lint:web", "lint": "eslint .",
"lint:app": "tslint --project ./tsconfig.app.json", "lint:app": "eslint src",
"lint:web": "tslint --project ./tsconfig.json", "lint:web": "eslint web",
"i18n": "npm run-script i18n:init && npm run-script i18n:extract", "i18n": "npm run-script i18n:init && npm run-script i18n:extract",
"i18n:init": "ngx-translate-extract --input ./web --output ./web/public/assets/i18n/template.json --key-as-default-value --replace --format json", "i18n:init": "ngx-translate-extract --input ./web --output ./web/public/assets/i18n/template.json --key-as-default-value --replace --format json",
"i18n:extract": "ngx-translate-extract --input ./web --output ./web/public/assets/i18n/en.json --clean --format json" "i18n:extract": "ngx-translate-extract --input ./web --output ./web/public/assets/i18n/en.json --clean --format json"

View File

@ -111,7 +111,7 @@ export class DimensionBigBlueButtonService {
@Path("join") @Path("join")
public async join( public async join(
@QueryParam("greenlightUrl") greenlightURL: string, @QueryParam("greenlightUrl") greenlightURL: string,
@QueryParam("fullName") fullName: string, @QueryParam("fullName") fullName: string,
): Promise<BigBlueButtonJoinResponse|ApiError> { ): Promise<BigBlueButtonJoinResponse|ApiError> {
// Parse the greenlight url and retrieve the path // Parse the greenlight url and retrieve the path
const greenlightMeetingID = new URL(greenlightURL).pathname; const greenlightMeetingID = new URL(greenlightURL).pathname;
@ -139,7 +139,7 @@ export class DimensionBigBlueButtonService {
// than following it ourselves // than following it ourselves
// Add authenticity token and full name to the query parameters // Add authenticity token and full name to the query parameters
let queryParams = {authenticity_token: authenticityToken}; const queryParams = {authenticity_token: authenticityToken};
queryParams[`${greenlightMeetingID}[join_name]`] = fullName; queryParams[`${greenlightMeetingID}[join_name]`] = fullName;
// Request the updated URL // Request the updated URL
@ -239,7 +239,7 @@ export class DimensionBigBlueButtonService {
} }
}, },
"layout": { "layout": {
"container": "top", "container": "top",
"index": 0, "index": 0,
"width": 65, "width": 65,
"height": 50, "height": 50,
@ -259,7 +259,7 @@ export class DimensionBigBlueButtonService {
getJoinUrlRequest: BigBlueButtonGetJoinUrlRequest, getJoinUrlRequest: BigBlueButtonGetJoinUrlRequest,
): Promise<BigBlueButtonCreateAndJoinMeetingResponse|ApiError> { ): Promise<BigBlueButtonCreateAndJoinMeetingResponse|ApiError> {
// Check if the meeting exists and is running. If not, return an error for each case // Check if the meeting exists and is running. If not, return an error for each case
let getMeetingInfoParameters = { const getMeetingInfoParameters = {
meetingID: getJoinUrlRequest.meetingId, meetingID: getJoinUrlRequest.meetingId,
} }
@ -290,7 +290,7 @@ export class DimensionBigBlueButtonService {
fullName = getJoinUrlRequest.userId; fullName = getJoinUrlRequest.userId;
} }
let joinQueryParameters = { const joinQueryParameters = {
meetingID: getJoinUrlRequest.meetingId, meetingID: getJoinUrlRequest.meetingId,
password: getJoinUrlRequest.meetingPassword, password: getJoinUrlRequest.meetingPassword,
fullName: fullName, fullName: fullName,

View File

@ -88,7 +88,7 @@ class _DimensionStore {
// Adjust the migration from the new signature to the v2 signature, making easier to upgrade to v3 // Adjust the migration from the new signature to the v2 signature, making easier to upgrade to v3
const migration = require(path) const migration = require(path)
return { name, up: async () => migration.default.up(context), down: async () => migration.default.down(context) } return { name, up: async () => migration.default.up(context), down: async () => migration.default.down(context) }
} }
}, },
context: this.sequelize.getQueryInterface(), context: this.sequelize.getQueryInterface(),
storage: new SequelizeStorage({ sequelize: this.sequelize }), storage: new SequelizeStorage({ sequelize: this.sequelize }),

View File

@ -1,30 +1,30 @@
import { QueryInterface } from "sequelize"; import { QueryInterface } from "sequelize";
export default { export default {
up: (queryInterface: QueryInterface) => { up: (queryInterface: QueryInterface) => {
return Promise.resolve() return Promise.resolve()
.then(() => .then(() =>
queryInterface.sequelize.query( queryInterface.sequelize.query(
"UPDATE dimension_widgets SET avatarUrl = REPLACE(avatarUrl, '/img/', '/assets/img/')" "UPDATE dimension_widgets SET avatarUrl = REPLACE(avatarUrl, '/img/', '/assets/img/')"
) )
) )
.then(() => .then(() =>
queryInterface.sequelize.query( queryInterface.sequelize.query(
"UPDATE dimension_bridges SET avatarUrl = REPLACE(avatarUrl, '/img/', '/assets/img/')" "UPDATE dimension_bridges SET avatarUrl = REPLACE(avatarUrl, '/img/', '/assets/img/')"
) )
); );
}, },
down: (queryInterface: QueryInterface) => { down: (queryInterface: QueryInterface) => {
return Promise.resolve() return Promise.resolve()
.then(() => .then(() =>
queryInterface.sequelize.query( queryInterface.sequelize.query(
"UPDATE dimension_widgets SET avatarUrl = REPLACE(avatarUrl, '/assets/img/', '/img/')" "UPDATE dimension_widgets SET avatarUrl = REPLACE(avatarUrl, '/assets/img/', '/img/')"
) )
) )
.then(() => .then(() =>
queryInterface.sequelize.query( queryInterface.sequelize.query(
"UPDATE dimension_bridges SET avatarUrl = REPLACE(avatarUrl, '/assets/img/', '/img/')" "UPDATE dimension_bridges SET avatarUrl = REPLACE(avatarUrl, '/assets/img/', '/img/')"
) )
); );
}, },
}; };

View File

@ -9,12 +9,12 @@ import User from "./db/models/User";
import { ILoggedInUser } from "./api/security/MatrixSecurity"; import { ILoggedInUser } from "./api/security/MatrixSecurity";
declare global { declare global {
namespace Express { namespace Express {
interface User extends ILoggedInUser { interface User extends ILoggedInUser {
userId: string; userId: string;
token: string; token: string;
}
} }
}
} }
LogService.configure(config.logging); LogService.configure(config.logging);
@ -30,8 +30,8 @@ BotSdk.LogService.setLogger({
}); });
async function startup() { async function startup() {
const schemas = await DimensionStore.updateSchema(); const schemas = await DimensionStore.updateSchema();
LogService.info("DimensionStore", schemas); LogService.info("DimensionStore", schemas);
const webserver = new Webserver(); const webserver = new Webserver();
await webserver.start(); await webserver.start();

View File

@ -12,8 +12,8 @@ try {
try { try {
gitHash = child_process gitHash = child_process
.execSync('git rev-parse --short HEAD') .execSync('git rev-parse --short HEAD')
.toString().trim() .toString().trim()
} catch (error) { } catch (error) {
// The log service isn't set up by the time we require this file // The log service isn't set up by the time we require this file
console.error("version", error); console.error("version", error);

View File

@ -14,7 +14,7 @@ export class AdminBridgesComponent implements OnInit {
public bridges: FE_Bridge<any>[]; public bridges: FE_Bridge<any>[];
constructor(private adminIntegrations: AdminIntegrationsApiService, constructor(private adminIntegrations: AdminIntegrationsApiService,
private toaster: ToasterService, public translate: TranslateService) { private toaster: ToasterService, public translate: TranslateService) {
this.translate = translate; this.translate = translate;
} }
@ -24,7 +24,9 @@ export class AdminBridgesComponent implements OnInit {
this.isLoading = false; this.isLoading = false;
}).catch(err => { }).catch(err => {
console.error(err); console.error(err);
this.translate.get('Failed to load bridges').subscribe((res: string) => {this.toaster.pop("error", res); }); this.translate.get('Failed to load bridges').subscribe((res: string) => {
this.toaster.pop("error", res);
});
}); });
} }
} }

View File

@ -19,21 +19,25 @@ export class AdminIrcBridgeAddSelfhostedComponent {
public provisionUrl: string; public provisionUrl: string;
constructor(public modal: NgbActiveModal, constructor(public modal: NgbActiveModal,
private ircApi: AdminIrcApiService, private ircApi: AdminIrcApiService,
private toaster: ToasterService, private toaster: ToasterService,
public translate: TranslateService) { public translate: TranslateService) {
this.translate = translate; this.translate = translate;
} }
public add() { public add() {
this.isSaving = true; this.isSaving = true;
this.ircApi.newSelfhosted(this.provisionUrl).then(() => { this.ircApi.newSelfhosted(this.provisionUrl).then(() => {
this.translate.get('IRC Bridge added').subscribe((res: string) => {this.toaster.pop("success", res); }); this.translate.get('IRC Bridge added').subscribe((res: string) => {
this.toaster.pop("success", res);
});
this.modal.close(); this.modal.close();
}).catch(err => { }).catch(err => {
console.error(err); console.error(err);
this.isSaving = false; this.isSaving = false;
this.translate.get('Failed to create IRC bridge').subscribe((res: string) => {this.toaster.pop("error", res); }); this.translate.get('Failed to create IRC bridge').subscribe((res: string) => {
this.toaster.pop("error", res);
});
}); });
} }
} }

View File

@ -25,10 +25,10 @@ export class AdminIrcBridgeComponent implements OnInit {
private upstreams: FE_Upstream[]; private upstreams: FE_Upstream[];
constructor(private upstreamApi: AdminUpstreamApiService, constructor(private upstreamApi: AdminUpstreamApiService,
private ircApi: AdminIrcApiService, private ircApi: AdminIrcApiService,
private toaster: ToasterService, private toaster: ToasterService,
private modal: NgbModal, private modal: NgbModal,
public translate: TranslateService) { public translate: TranslateService) {
this.translate = translate; this.translate = translate;
} }
@ -50,7 +50,9 @@ export class AdminIrcBridgeComponent implements OnInit {
} }
} catch (err) { } catch (err) {
console.error(err); console.error(err);
this.translate.get('Error loading bridges').subscribe((res: string) => {this.toaster.pop("error", res); }); this.translate.get('Error loading bridges').subscribe((res: string) => {
this.toaster.pop("error", res);
});
} }
} }
@ -69,13 +71,17 @@ export class AdminIrcBridgeComponent implements OnInit {
const createBridge = (upstream: FE_Upstream) => { const createBridge = (upstream: FE_Upstream) => {
return this.ircApi.newFromUpstream(upstream).then(bridge => { return this.ircApi.newFromUpstream(upstream).then(bridge => {
this.configurations.push(bridge); this.configurations.push(bridge);
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.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.isUpdating = false;
this.hasModularBridge = true; this.hasModularBridge = true;
}).catch(err => { }).catch(err => {
console.error(err); console.error(err);
this.isUpdating = false; this.isUpdating = false;
this.translate.get('Error adding matrix.org\'s IRC Bridge').subscribe((res: string) => {this.toaster.pop("error", res); }); 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"); const vectorUpstreams = this.upstreams.filter(u => u.type === "vector");
@ -87,7 +93,9 @@ export class AdminIrcBridgeComponent implements OnInit {
createBridge(upstream); createBridge(upstream);
}).catch(err => { }).catch(err => {
console.error(err); console.error(err);
this.translate.get('Error creating matrix.org\'s IRC Bridge').subscribe((res: string) => {this.toaster.pop("error", res); }); this.translate.get('Error creating matrix.org\'s IRC Bridge').subscribe((res: string) => {
this.toaster.pop("error", res);
});
}); });
} else createBridge(vectorUpstreams[0]); } else createBridge(vectorUpstreams[0]);
} }
@ -102,7 +110,9 @@ export class AdminIrcBridgeComponent implements OnInit {
this.reload() this.reload()
} catch (err) { } catch (err) {
console.error(err); console.error(err);
this.translate.get('Failed to get an update IRC bridge list').subscribe((res: string) => {this.toaster.pop("error", res); }); this.translate.get('Failed to get an update IRC bridge list').subscribe((res: string) => {
this.toaster.pop("error", res);
});
} }
}) })
} }
@ -117,7 +127,9 @@ export class AdminIrcBridgeComponent implements OnInit {
this.reload() this.reload()
} catch (err) { } catch (err) {
console.error(err); console.error(err);
this.translate.get('Failed to get an update IRC bridge list').subscribe((res: string) => {this.toaster.pop("error", res); }); this.translate.get('Failed to get an update IRC bridge list').subscribe((res: string) => {
this.toaster.pop("error", res);
});
} }
}) })
const selfhostedInstance = selfhostedRef.componentInstance as IrcNetworksDialogContext; const selfhostedInstance = selfhostedRef.componentInstance as IrcNetworksDialogContext;

View File

@ -28,9 +28,9 @@ export class AdminIrcBridgeNetworksComponent {
public networks: LocalNetwork[]; public networks: LocalNetwork[];
constructor(public modal: NgbActiveModal, constructor(public modal: NgbActiveModal,
private ircApi: AdminIrcApiService, private ircApi: AdminIrcApiService,
private toaster: ToasterService, private toaster: ToasterService,
public translate: TranslateService) { public translate: TranslateService) {
this.translate = translate; this.translate = translate;
const networkIds = Object.keys(this.bridge.availableNetworks); const networkIds = Object.keys(this.bridge.availableNetworks);
this.networks = networkIds.map(i => { this.networks = networkIds.map(i => {
@ -51,13 +51,17 @@ export class AdminIrcBridgeNetworksComponent {
this.isUpdating = true; this.isUpdating = true;
this.ircApi.setNetworkEnabled(this.bridge.id, network.id, network.isEnabled).then(() => { this.ircApi.setNetworkEnabled(this.bridge.id, network.id, network.isEnabled).then(() => {
this.isUpdating = false; this.isUpdating = false;
this.translate.get(['Enabled', 'disabled']).subscribe((res: string) => {this.toaster.pop("success", "Network " + (network.isEnabled ? res[0] : res[1])); }); this.translate.get(['Enabled', 'disabled']).subscribe((res: string) => {
this.toaster.pop("success", "Network " + (network.isEnabled ? res[0] : res[1]));
});
}).catch(err => { }).catch(err => {
console.error(err); console.error(err);
this.isUpdating = false; this.isUpdating = false;
network.isEnabled = !network.isEnabled; network.isEnabled = !network.isEnabled;
this.bridge.availableNetworks[network.id].isEnabled = network.isEnabled; this.bridge.availableNetworks[network.id].isEnabled = network.isEnabled;
this.translate.get('Failed to update network').subscribe((res: string) => {this.toaster.pop("error", res); }); this.translate.get('Failed to update network').subscribe((res: string) => {
this.toaster.pop("error", res);
});
}); });
} }
} }

View File

@ -22,9 +22,9 @@ export class AdminSlackBridgeManageSelfhostedComponent {
public isAdding = true; public isAdding = true;
constructor(public modal: NgbActiveModal, constructor(public modal: NgbActiveModal,
private slackApi: AdminSlackApiService, private slackApi: AdminSlackApiService,
private toaster: ToasterService, private toaster: ToasterService,
public translate: TranslateService) { public translate: TranslateService) {
this.translate = translate; this.translate = translate;
} }
@ -32,12 +32,16 @@ export class AdminSlackBridgeManageSelfhostedComponent {
this.isSaving = true; this.isSaving = true;
if (this.isAdding) { if (this.isAdding) {
this.slackApi.newSelfhosted(this.provisionUrl).then(() => { this.slackApi.newSelfhosted(this.provisionUrl).then(() => {
this.translate.get('Slack bridge added').subscribe((res: string) => {this.toaster.pop("success", res); }); this.translate.get('Slack bridge added').subscribe((res: string) => {
this.toaster.pop("success", res);
});
this.modal.close(); this.modal.close();
}).catch(err => { }).catch(err => {
console.error(err); console.error(err);
this.isSaving = false; this.isSaving = false;
this.translate.get('Failed to create Slack bridge').subscribe((res: string) => {this.toaster.pop("error", res); }); this.translate.get('Failed to create Slack bridge').subscribe((res: string) => {
this.toaster.pop("error", res);
});
}); });
} else { } else {
this.slackApi.updateSelfhosted(this.bridgeId, this.provisionUrl).then(() => { this.slackApi.updateSelfhosted(this.bridgeId, this.provisionUrl).then(() => {
@ -46,7 +50,9 @@ export class AdminSlackBridgeManageSelfhostedComponent {
}).catch(err => { }).catch(err => {
console.error(err); console.error(err);
this.isSaving = false; this.isSaving = false;
this.translate.get('Failed to update Slack bridge').subscribe((res: string) => {this.toaster.pop("error", res); }); this.translate.get('Failed to update Slack bridge').subscribe((res: string) => {
this.toaster.pop("error", res);
});
}); });
} }
} }

View File

@ -24,10 +24,10 @@ export class AdminSlackBridgeComponent implements OnInit {
private upstreams: FE_Upstream[]; private upstreams: FE_Upstream[];
constructor(private slackApi: AdminSlackApiService, constructor(private slackApi: AdminSlackApiService,
private upstreamApi: AdminUpstreamApiService, private upstreamApi: AdminUpstreamApiService,
private toaster: ToasterService, private toaster: ToasterService,
private modal: NgbModal, private modal: NgbModal,
public translate: TranslateService) { public translate: TranslateService) {
this.translate = translate; this.translate = translate;
} }
@ -41,7 +41,9 @@ export class AdminSlackBridgeComponent implements OnInit {
this.configurations = await this.slackApi.getBridges(); this.configurations = await this.slackApi.getBridges();
} catch (err) { } catch (err) {
console.error(err); console.error(err);
this.translate.get('Error loading bridges').subscribe((res: string) => {this.toaster.pop("error", res); }); this.translate.get('Error loading bridges').subscribe((res: string) => {
this.toaster.pop("error", res);
});
} }
} }
@ -51,12 +53,16 @@ export class AdminSlackBridgeComponent implements OnInit {
const createBridge = (upstream: FE_Upstream) => { const createBridge = (upstream: FE_Upstream) => {
return this.slackApi.newFromUpstream(upstream).then(bridge => { return this.slackApi.newFromUpstream(upstream).then(bridge => {
this.configurations.push(bridge); this.configurations.push(bridge);
this.translate.get('matrix.org\'s Slack bridge added').subscribe((res: string) => {this.toaster.pop("success", res); }); this.translate.get('matrix.org\'s Slack bridge added').subscribe((res: string) => {
this.toaster.pop("success", res);
});
this.isUpdating = false; this.isUpdating = false;
}).catch(err => { }).catch(err => {
console.error(err); console.error(err);
this.isUpdating = false; this.isUpdating = false;
this.translate.get('Error adding matrix.org\'s Slack Bridge').subscribe((res: string) => {this.toaster.pop("error", res); }); this.translate.get('Error adding matrix.org\'s Slack Bridge').subscribe((res: string) => {
this.toaster.pop("error", res);
});
}); });
}; };
@ -69,7 +75,9 @@ export class AdminSlackBridgeComponent implements OnInit {
createBridge(upstream); createBridge(upstream);
}).catch(err => { }).catch(err => {
console.error(err); console.error(err);
this.translate.get('Error creating matrix.org\'s Slack Bridge').subscribe((res: string) => {this.toaster.pop("error", res); }); this.translate.get('Error creating matrix.org\'s Slack Bridge').subscribe((res: string) => {
this.toaster.pop("error", res);
});
}); });
} else createBridge(vectorUpstreams[0]); } else createBridge(vectorUpstreams[0]);
} }
@ -84,7 +92,9 @@ export class AdminSlackBridgeComponent implements OnInit {
this.reload() this.reload()
} catch (err) { } catch (err) {
console.error(err); console.error(err);
this.translate.get('Failed to get an update Slack bridge list').subscribe((res: string) => {this.toaster.pop("error", res); }); this.translate.get('Failed to get an update Slack bridge list').subscribe((res: string) => {
this.toaster.pop("error", res);
});
} }
}); });
const selfhostedInstance = selfhostedRef.componentInstance as ManageSelfhostedSlackBridgeDialogContext; const selfhostedInstance = selfhostedRef.componentInstance as ManageSelfhostedSlackBridgeDialogContext;
@ -101,7 +111,9 @@ export class AdminSlackBridgeComponent implements OnInit {
this.reload() this.reload()
} catch (err) { } catch (err) {
console.error(err); console.error(err);
this.translate.get('Failed to get an update Slack bridge list').subscribe((res: string) => {this.toaster.pop("error", res); }); this.translate.get('Failed to get an update Slack bridge list').subscribe((res: string) => {
this.toaster.pop("error", res);
});
} }
}); });
const selfhostedInstance = selfhostedRef.componentInstance as ManageSelfhostedSlackBridgeDialogContext; const selfhostedInstance = selfhostedRef.componentInstance as ManageSelfhostedSlackBridgeDialogContext;

View File

@ -28,9 +28,9 @@ export class AdminTelegramBridgeManageSelfhostedComponent {
isAdding = true; isAdding = true;
constructor(public modal: NgbActiveModal, constructor(public modal: NgbActiveModal,
private telegramApi: AdminTelegramApiService, private telegramApi: AdminTelegramApiService,
private toaster: ToasterService, private toaster: ToasterService,
public translate: TranslateService) { public translate: TranslateService) {
this.translate = translate; this.translate = translate;
} }
@ -42,21 +42,29 @@ export class AdminTelegramBridgeManageSelfhostedComponent {
}; };
if (this.isAdding) { if (this.isAdding) {
this.telegramApi.newSelfhosted(this.provisionUrl, this.sharedSecret, options).then(() => { this.telegramApi.newSelfhosted(this.provisionUrl, this.sharedSecret, options).then(() => {
this.translate.get('Telegram bridge added').subscribe((res: string) => {this.toaster.pop("success", res); }); this.translate.get('Telegram bridge added').subscribe((res: string) => {
this.toaster.pop("success", res);
});
this.modal.close(); this.modal.close();
}).catch(err => { }).catch(err => {
console.error(err); console.error(err);
this.isSaving = false; this.isSaving = false;
this.translate.get('Failed to create Telegram bridge').subscribe((res: string) => { this.toaster.pop("error", res); }); this.translate.get('Failed to create Telegram bridge').subscribe((res: string) => {
this.toaster.pop("error", res);
});
}); });
} else { } else {
this.telegramApi.updateSelfhosted(this.bridgeId, this.provisionUrl, this.sharedSecret, options).then(() => { this.telegramApi.updateSelfhosted(this.bridgeId, this.provisionUrl, this.sharedSecret, options).then(() => {
this.translate.get('Telegram bridge updated').subscribe((res: string) => {this.toaster.pop("success", res); }); this.translate.get('Telegram bridge updated').subscribe((res: string) => {
this.toaster.pop("success", res);
});
this.modal.close(); this.modal.close();
}).catch(err => { }).catch(err => {
console.error(err); console.error(err);
this.isSaving = false; this.isSaving = false;
this.translate.get('Failed to update Telegram bridge').subscribe((res: string) => {this.toaster.pop("error", res); }); this.translate.get('Failed to update Telegram bridge').subscribe((res: string) => {
this.toaster.pop("error", res);
});
}); });
} }
} }

View File

@ -20,9 +20,9 @@ export class AdminTelegramBridgeComponent implements OnInit {
public configurations: FE_TelegramBridge[] = []; public configurations: FE_TelegramBridge[] = [];
constructor(private telegramApi: AdminTelegramApiService, constructor(private telegramApi: AdminTelegramApiService,
private toaster: ToasterService, private toaster: ToasterService,
private modal: NgbModal, private modal: NgbModal,
public translate: TranslateService) { public translate: TranslateService) {
this.translate = translate; this.translate = translate;
} }
@ -35,7 +35,9 @@ export class AdminTelegramBridgeComponent implements OnInit {
this.configurations = await this.telegramApi.getBridges(); this.configurations = await this.telegramApi.getBridges();
} catch (err) { } catch (err) {
console.error(err); console.error(err);
this.translate.get('Error loading bridges').subscribe((res: string) => {this.toaster.pop("error", res); }); this.translate.get('Error loading bridges').subscribe((res: string) => {
this.toaster.pop("error", res);
});
} }
} }
@ -49,7 +51,9 @@ export class AdminTelegramBridgeComponent implements OnInit {
this.reload() this.reload()
} catch (err) { } catch (err) {
console.error(err); console.error(err);
this.translate.get('Failed to get an update Telegram bridge list').subscribe((res: string) => {this.toaster.pop("error", res); }); this.translate.get('Failed to get an update Telegram bridge list').subscribe((res: string) => {
this.toaster.pop("error", res);
});
} }
}) })
const selfhostedInstance = selfhostedRef.componentInstance as ManageSelfhostedTelegramBridgeDialogContext; const selfhostedInstance = selfhostedRef.componentInstance as ManageSelfhostedTelegramBridgeDialogContext;
@ -76,7 +80,9 @@ export class AdminTelegramBridgeComponent implements OnInit {
this.reload() this.reload()
} catch (err) { } catch (err) {
console.error(err); console.error(err);
this.translate.get('Failed to get an update Telegram bridge list').subscribe((res: string) => {this.toaster.pop("error", res); }); this.translate.get('Failed to get an update Telegram bridge list').subscribe((res: string) => {
this.toaster.pop("error", res);
});
} }
}) })
const selfhostedInstance = selfhostedRef.componentInstance as ManageSelfhostedTelegramBridgeDialogContext; const selfhostedInstance = selfhostedRef.componentInstance as ManageSelfhostedTelegramBridgeDialogContext;

View File

@ -28,9 +28,9 @@ export class AdminWebhooksBridgeManageSelfhostedComponent {
public isAdding = true; public isAdding = true;
constructor(public modal: NgbActiveModal, constructor(public modal: NgbActiveModal,
private webhooksApi: AdminWebhooksApiService, private webhooksApi: AdminWebhooksApiService,
private toaster: ToasterService, private toaster: ToasterService,
public translate: TranslateService) { public translate: TranslateService) {
this.translate = translate; this.translate = translate;
} }
@ -38,21 +38,29 @@ export class AdminWebhooksBridgeManageSelfhostedComponent {
this.isSaving = true; this.isSaving = true;
if (this.isAdding) { if (this.isAdding) {
this.webhooksApi.newSelfhosted(this.provisionUrl, this.sharedSecret).then(() => { this.webhooksApi.newSelfhosted(this.provisionUrl, this.sharedSecret).then(() => {
this.translate.get('Webhook bridge added').subscribe((res: string) => {this.toaster.pop("success", res); }); this.translate.get('Webhook bridge added').subscribe((res: string) => {
this.toaster.pop("success", res);
});
this.modal.close(); this.modal.close();
}).catch(err => { }).catch(err => {
console.error(err); console.error(err);
this.isSaving = false; this.isSaving = false;
this.translate.get('Failed to create Webhook bridge').subscribe((res: string) => {this.toaster.pop("error", res); }); this.translate.get('Failed to create Webhook bridge').subscribe((res: string) => {
this.toaster.pop("error", res);
});
}); });
} else { } else {
this.webhooksApi.updateSelfhosted(this.bridgeId, this.provisionUrl, this.sharedSecret).then(() => { this.webhooksApi.updateSelfhosted(this.bridgeId, this.provisionUrl, this.sharedSecret).then(() => {
this.translate.get('Webhook bridge updated').subscribe((res: string) => {this.toaster.pop("success", res); }); this.translate.get('Webhook bridge updated').subscribe((res: string) => {
this.toaster.pop("success", res);
});
this.modal.close(); this.modal.close();
}).catch(err => { }).catch(err => {
console.error(err); console.error(err);
this.isSaving = false; this.isSaving = false;
this.translate.get('Failed to update Webhook bridge').subscribe((res: string) => {this.toaster.pop("error", res); }); this.translate.get('Failed to update Webhook bridge').subscribe((res: string) => {
this.toaster.pop("error", res);
});
}); });
} }
} }

View File

@ -20,9 +20,9 @@ export class AdminWebhooksBridgeComponent implements OnInit {
public configurations: FE_WebhooksBridge[] = []; public configurations: FE_WebhooksBridge[] = [];
constructor(private webhooksApi: AdminWebhooksApiService, constructor(private webhooksApi: AdminWebhooksApiService,
private toaster: ToasterService, private toaster: ToasterService,
private modal: NgbModal, private modal: NgbModal,
public translate: TranslateService) { public translate: TranslateService) {
this.translate = translate; this.translate = translate;
} }
@ -35,7 +35,9 @@ export class AdminWebhooksBridgeComponent implements OnInit {
this.configurations = await this.webhooksApi.getBridges(); this.configurations = await this.webhooksApi.getBridges();
} catch (err) { } catch (err) {
console.error(err); console.error(err);
this.translate.get('Error loading bridges').subscribe((res: string) => {this.toaster.pop("error", res); }); this.translate.get('Error loading bridges').subscribe((res: string) => {
this.toaster.pop("error", res);
});
} }
} }
@ -49,7 +51,9 @@ export class AdminWebhooksBridgeComponent implements OnInit {
this.reload() this.reload()
} catch (err) { } catch (err) {
console.error(err); console.error(err);
this.translate.get('Failed to get an update Webhooks bridge list').subscribe((res: string) => {this.toaster.pop("error", res); }); this.translate.get('Failed to get an update Webhooks bridge list').subscribe((res: string) => {
this.toaster.pop("error", res);
});
} }
}); });
const selfhostedInstance = selfhostedRef.componentInstance as ManageSelfhostedWebhooksBridgeDialogContext; const selfhostedInstance = selfhostedRef.componentInstance as ManageSelfhostedWebhooksBridgeDialogContext;
@ -69,7 +73,9 @@ export class AdminWebhooksBridgeComponent implements OnInit {
this.reload() this.reload()
} catch (err) { } catch (err) {
console.error(err); console.error(err);
this.translate.get('Failed to get an update Webhooks bridge list').subscribe((res: string) => {this.toaster.pop("error", res); }); this.translate.get('Failed to get an update Webhooks bridge list').subscribe((res: string) => {
this.toaster.pop("error", res);
});
} }
}); });
const selfhostedInstance = selfhostedRef.componentInstance as ManageSelfhostedWebhooksBridgeDialogContext; const selfhostedInstance = selfhostedRef.componentInstance as ManageSelfhostedWebhooksBridgeDialogContext;

View File

@ -23,9 +23,9 @@ export class AdminAddCustomBotComponent {
private lastProfile: FE_UserProfile; private lastProfile: FE_UserProfile;
constructor(public modal: NgbActiveModal, constructor(public modal: NgbActiveModal,
private botApi: AdminCustomSimpleBotsApiService, private botApi: AdminCustomSimpleBotsApiService,
private toaster: ToasterService, private toaster: ToasterService,
public translate: TranslateService) { public translate: TranslateService) {
this.translate = translate; this.translate = translate;
} }
@ -46,23 +46,33 @@ export class AdminAddCustomBotComponent {
public add() { public add() {
if (!this.bot.name) { if (!this.bot.name) {
this.translate.get('Please enter a name for the bot').subscribe((res: string) => {this.toaster.pop("warning", res); }); this.translate.get('Please enter a name for the bot').subscribe((res: string) => {
this.toaster.pop("warning", res);
});
return; return;
} }
if (!this.bot.avatarUrl) { if (!this.bot.avatarUrl) {
this.translate.get('Please enter an avatar URL for the bot').subscribe((res: string) => {this.toaster.pop("warning", res); }); this.translate.get('Please enter an avatar URL for the bot').subscribe((res: string) => {
this.toaster.pop("warning", res);
});
return; return;
} }
if (!this.bot.userId) { if (!this.bot.userId) {
this.translate.get('Please enter a user ID for the bot').subscribe((res: string) => {this.toaster.pop("warning", res); }); this.translate.get('Please enter a user ID for the bot').subscribe((res: string) => {
this.toaster.pop("warning", res);
});
return; return;
} }
if (!this.bot.description) { if (!this.bot.description) {
this.translate.get('Please enter a description for the bot').subscribe((res: string) => {this.toaster.pop("warning", res); }); this.translate.get('Please enter a description for the bot').subscribe((res: string) => {
this.toaster.pop("warning", res);
});
return; return;
} }
if (!this.bot.accessToken) { if (!this.bot.accessToken) {
this.translate.get('Please enter an access token for the bot').subscribe((res: string) => {this.toaster.pop("warning", res); }); this.translate.get('Please enter an access token for the bot').subscribe((res: string) => {
this.toaster.pop("warning", res);
});
return; return;
} }
@ -86,12 +96,16 @@ export class AdminAddCustomBotComponent {
} }
promise.then(() => { promise.then(() => {
this.translate.get('Bot updated').subscribe((res: string) => {this.toaster.pop("success", res); }); this.translate.get('Bot updated').subscribe((res: string) => {
this.toaster.pop("success", res);
});
this.modal.close(); this.modal.close();
}).catch(error => { }).catch(error => {
this.isSaving = false; this.isSaving = false;
console.error(error); console.error(error);
this.translate.get('Error updating bot').subscribe((res: string) => {this.toaster.pop("error", res); }); this.translate.get('Error updating bot').subscribe((res: string) => {
this.toaster.pop("error", res);
});
}); });
} }
} }

View File

@ -17,14 +17,16 @@ export class AdminCustomBotsComponent {
public isUpdating = false; public isUpdating = false;
constructor(private botApi: AdminCustomSimpleBotsApiService, constructor(private botApi: AdminCustomSimpleBotsApiService,
private toaster: ToasterService, private toaster: ToasterService,
private modal: NgbModal, private modal: NgbModal,
public translate: TranslateService) { public translate: TranslateService) {
this.translate = translate; this.translate = translate;
this.reload().then(() => this.isLoading = false).catch(error => { this.reload().then(() => this.isLoading = false).catch(error => {
console.error(error); console.error(error);
this.translate.get('Error loading go-neb configuration').subscribe((res: string) => {this.toaster.pop("error", res); }); this.translate.get('Error loading go-neb configuration').subscribe((res: string) => {
this.toaster.pop("error", res);
});
}); });
} }
@ -45,7 +47,9 @@ export class AdminCustomBotsComponent {
this.reload() this.reload()
} catch (err) { } catch (err) {
console.error(err); console.error(err);
this.translate.get('Failed to get an updated bot list').subscribe((res: string) => {this.toaster.pop("error", res); }); this.translate.get('Failed to get an updated bot list').subscribe((res: string) => {
this.toaster.pop("error", res);
});
} }
}); });
} }
@ -60,7 +64,9 @@ export class AdminCustomBotsComponent {
this.reload() this.reload()
} catch (err) { } catch (err) {
console.error(err); console.error(err);
this.translate.get('Failed to get an updated bot list').subscribe((res: string) => {this.toaster.pop("error", res); }); this.translate.get('Failed to get an updated bot list').subscribe((res: string) => {
this.toaster.pop("error", res);
});
} }
}); });
const selfhostedInstance = selfhostedRef.componentInstance as AddCustomBotDialogContext; const selfhostedInstance = selfhostedRef.componentInstance as AddCustomBotDialogContext;
@ -73,11 +79,15 @@ export class AdminCustomBotsComponent {
bot.isEnabled = !bot.isEnabled; bot.isEnabled = !bot.isEnabled;
this.botApi.updateBot(bot.id, bot).then(() => { this.botApi.updateBot(bot.id, bot).then(() => {
this.isUpdating = false; this.isUpdating = false;
this.translate.get(['Enabled', 'disabled']).subscribe((res: string) => {this.toaster.pop("success", "Bot " + (bot.isEnabled ? res[0] : res[1])); }); this.translate.get(['Enabled', 'disabled']).subscribe((res: string) => {
this.toaster.pop("success", "Bot " + (bot.isEnabled ? res[0] : res[1]));
});
}).catch(error => { }).catch(error => {
console.error(error); console.error(error);
bot.isEnabled = !bot.isEnabled; bot.isEnabled = !bot.isEnabled;
this.translate.get('Error updating bot').subscribe((res: string) => {this.toaster.pop("error", res); }); this.translate.get('Error updating bot').subscribe((res: string) => {
this.toaster.pop("error", res);
});
}) })
} }
} }

View File

@ -18,9 +18,9 @@ export class AdminHomeComponent {
public config: FE_DimensionConfig; public config: FE_DimensionConfig;
constructor(private adminApi: AdminApiService, constructor(private adminApi: AdminApiService,
private toaster: ToasterService, private toaster: ToasterService,
private modal: NgbModal, private modal: NgbModal,
public translate: TranslateService) { public translate: TranslateService) {
this.translate = translate; this.translate = translate;
adminApi.getConfig().then(config => { adminApi.getConfig().then(config => {
this.config = config; this.config = config;
@ -35,11 +35,15 @@ export class AdminHomeComponent {
selfhostedRef.result.then(async () => { selfhostedRef.result.then(async () => {
try { try {
await this.adminApi.logoutAll(); await this.adminApi.logoutAll();
this.translate.get('Everyone has been logged out').subscribe((res: string) => {this.toaster.pop("success", res); }); this.translate.get('Everyone has been logged out').subscribe((res: string) => {
this.toaster.pop("success", res);
});
this.config.sessionInfo.numTokens = 0; this.config.sessionInfo.numTokens = 0;
} catch (err) { } catch (err) {
console.error(err); console.error(err);
this.translate.get('Error logging everyone out').subscribe((res: string) => {this.toaster.pop("error", res); }); this.translate.get('Error logging everyone out').subscribe((res: string) => {
this.toaster.pop("error", res);
});
} }
}); });
} }

View File

@ -22,12 +22,12 @@ export class AdminAddSelfhostedNebComponent {
public adminUrl = "http://localhost:4050"; public adminUrl = "http://localhost:4050";
constructor(private asApi: AdminAppserviceApiService, constructor(private asApi: AdminAppserviceApiService,
private nebApi: AdminNebApiService, private nebApi: AdminNebApiService,
private toaster: ToasterService, private toaster: ToasterService,
private router: Router, private router: Router,
private activatedRoute: ActivatedRoute, private activatedRoute: ActivatedRoute,
private modal: NgbModal, private modal: NgbModal,
public translate: TranslateService) { public translate: TranslateService) {
this.translate = translate; this.translate = translate;
} }
@ -36,7 +36,9 @@ export class AdminAddSelfhostedNebComponent {
this.asApi.createAppservice(this.userPrefix).then(appservice => { this.asApi.createAppservice(this.userPrefix).then(appservice => {
return this.nebApi.newAppserviceConfiguration(this.adminUrl, appservice); return this.nebApi.newAppserviceConfiguration(this.adminUrl, appservice);
}).then(neb => { }).then(neb => {
this.translate.get('New go-neb created').subscribe((res: string) => {this.toaster.pop("success", res); }); this.translate.get('New go-neb created').subscribe((res: string) => {
this.toaster.pop("success", res);
});
const selfhostedRef = this.modal.open(AdminNebAppserviceConfigComponent, { const selfhostedRef = this.modal.open(AdminNebAppserviceConfigComponent, {
backdrop: 'static', backdrop: 'static',
@ -48,7 +50,9 @@ export class AdminAddSelfhostedNebComponent {
}).catch(err => { }).catch(err => {
console.error(err); console.error(err);
this.isSaving = false; this.isSaving = false;
this.translate.get('Error creating appservice').subscribe((res: string) => {this.toaster.pop("error", res); }); this.translate.get('Error creating appservice').subscribe((res: string) => {
this.toaster.pop("error", res);
});
}); });
} }
} }

View File

@ -20,16 +20,18 @@ export class AdminNebAppserviceConfigComponent {
public appservice: FE_Appservice; public appservice: FE_Appservice;
constructor(public modal: NgbActiveModal, constructor(public modal: NgbActiveModal,
private adminAppserviceApi: AdminAppserviceApiService, private adminAppserviceApi: AdminAppserviceApiService,
private toaster: ToasterService, private toaster: ToasterService,
public translate: TranslateService) { public translate: TranslateService) {
this.translate = translate; this.translate = translate;
this.adminAppserviceApi.getAppservice(this.neb.appserviceId).then(appservice => { this.adminAppserviceApi.getAppservice(this.neb.appserviceId).then(appservice => {
this.appservice = appservice; this.appservice = appservice;
this.isLoading = false; this.isLoading = false;
}).catch(err => { }).catch(err => {
console.error(err); console.error(err);
this.translate.get('Could not load appservice configuration').subscribe((res: string) => {this.toaster.pop("error", res); }); this.translate.get('Could not load appservice configuration').subscribe((res: string) => {
this.toaster.pop("error", res);
});
}); });
} }
@ -50,10 +52,14 @@ export class AdminNebAppserviceConfigComponent {
public test() { public test() {
this.adminAppserviceApi.test(this.neb.appserviceId).then(() => { this.adminAppserviceApi.test(this.neb.appserviceId).then(() => {
this.translate.get('The appservice appears to be correctly set up').subscribe((res: string) => {this.toaster.pop("success", res); }); this.translate.get('The appservice appears to be correctly set up').subscribe((res: string) => {
this.toaster.pop("success", res);
});
}).catch(err => { }).catch(err => {
console.error(err); console.error(err);
this.translate.get('The appservice is not correctly set up').subscribe((res: string) => {this.toaster.pop("error", res); }); this.translate.get('The appservice is not correctly set up').subscribe((res: string) => {
this.toaster.pop("error", res);
});
}); });
} }
} }

View File

@ -24,9 +24,9 @@ export class AdminNebGiphyConfigComponent implements OnInit {
public neb: FE_NebConfiguration; public neb: FE_NebConfiguration;
constructor(public modal: NgbActiveModal, constructor(public modal: NgbActiveModal,
private adminNebApi: AdminNebApiService, private adminNebApi: AdminNebApiService,
private toaster: ToasterService, private toaster: ToasterService,
public translate: TranslateService) { public translate: TranslateService) {
this.translate = translate; this.translate = translate;
} }
@ -36,19 +36,25 @@ export class AdminNebGiphyConfigComponent implements OnInit {
this.isLoading = false; this.isLoading = false;
}).catch(err => { }).catch(err => {
console.error(err); console.error(err);
this.translate.get('Error loading configuration').subscribe((res: string) => {this.toaster.pop("error", res); }); this.translate.get('Error loading configuration').subscribe((res: string) => {
this.toaster.pop("error", res);
});
}); });
} }
public save() { public save() {
this.isUpdating = true; this.isUpdating = true;
this.adminNebApi.setIntegrationConfiguration(this.neb.id, this.integration.type, this.config).then(() => { this.adminNebApi.setIntegrationConfiguration(this.neb.id, this.integration.type, this.config).then(() => {
this.translate.get('Configuration updated').subscribe((res: string) => {this.toaster.pop("success", res); }); this.translate.get('Configuration updated').subscribe((res: string) => {
this.toaster.pop("success", res);
});
this.modal.close(); this.modal.close();
}).catch(err => { }).catch(err => {
this.isUpdating = false; this.isUpdating = false;
console.error(err); console.error(err);
this.translate.get('Error updating integration').subscribe((res: string) => {this.toaster.pop("error", res); }); this.translate.get('Error updating integration').subscribe((res: string) => {
this.toaster.pop("error", res);
});
}); });
} }
} }

View File

@ -24,9 +24,9 @@ export class AdminNebGoogleConfigComponent implements OnInit {
public neb: FE_NebConfiguration; public neb: FE_NebConfiguration;
constructor(public modal: NgbActiveModal, constructor(public modal: NgbActiveModal,
private adminNebApi: AdminNebApiService, private adminNebApi: AdminNebApiService,
private toaster: ToasterService, private toaster: ToasterService,
public translate: TranslateService) { public translate: TranslateService) {
this.translate = translate; this.translate = translate;
} }
@ -36,19 +36,25 @@ export class AdminNebGoogleConfigComponent implements OnInit {
this.isLoading = false; this.isLoading = false;
}).catch(err => { }).catch(err => {
console.error(err); console.error(err);
this.translate.get('Error loading configuration').subscribe((res: string) => {this.toaster.pop("error", res); }); this.translate.get('Error loading configuration').subscribe((res: string) => {
this.toaster.pop("error", res);
});
}); });
} }
public save() { public save() {
this.isUpdating = true; this.isUpdating = true;
this.adminNebApi.setIntegrationConfiguration(this.neb.id, this.integration.type, this.config).then(() => { this.adminNebApi.setIntegrationConfiguration(this.neb.id, this.integration.type, this.config).then(() => {
this.translate.get('Configuration updated').subscribe((res: string) => {this.toaster.pop("success", res); }); this.translate.get('Configuration updated').subscribe((res: string) => {
this.toaster.pop("success", res);
});
this.modal.close(); this.modal.close();
}).catch(err => { }).catch(err => {
this.isUpdating = false; this.isUpdating = false;
console.error(err); console.error(err);
this.translate.get('Error updating integration').subscribe((res: string) => {this.toaster.pop("error", res); }); this.translate.get('Error updating integration').subscribe((res: string) => {
this.toaster.pop("error", res);
});
}); });
} }
} }

View File

@ -23,9 +23,9 @@ export class AdminNebGuggyConfigComponent implements OnInit {
public neb: FE_NebConfiguration; public neb: FE_NebConfiguration;
constructor(public modal: NgbActiveModal, constructor(public modal: NgbActiveModal,
private adminNebApi: AdminNebApiService, private adminNebApi: AdminNebApiService,
private toaster: ToasterService, private toaster: ToasterService,
public translate: TranslateService) { public translate: TranslateService) {
this.translate = translate; this.translate = translate;
} }
@ -35,19 +35,25 @@ export class AdminNebGuggyConfigComponent implements OnInit {
this.isLoading = false; this.isLoading = false;
}).catch(err => { }).catch(err => {
console.error(err); console.error(err);
this.translate.get('Error loading configuration').subscribe((res: string) => {this.toaster.pop("error", res); }); this.translate.get('Error loading configuration').subscribe((res: string) => {
this.toaster.pop("error", res);
});
}); });
} }
public save() { public save() {
this.isUpdating = true; this.isUpdating = true;
this.adminNebApi.setIntegrationConfiguration(this.neb.id, this.integration.type, this.config).then(() => { this.adminNebApi.setIntegrationConfiguration(this.neb.id, this.integration.type, this.config).then(() => {
this.translate.get('Configuration updated').subscribe((res: string) => {this.toaster.pop("success", res); }); this.translate.get('Configuration updated').subscribe((res: string) => {
this.toaster.pop("success", res);
});
this.modal.close(); this.modal.close();
}).catch(err => { }).catch(err => {
this.isUpdating = false; this.isUpdating = false;
console.error(err); console.error(err);
this.translate.get('Error updating integration').subscribe((res: string) => {this.toaster.pop("error", res); }); this.translate.get('Error updating integration').subscribe((res: string) => {
this.toaster.pop("error", res);
});
}); });
} }
} }

View File

@ -24,9 +24,9 @@ export class AdminNebImgurConfigComponent implements OnInit {
public neb: FE_NebConfiguration; public neb: FE_NebConfiguration;
constructor(public modal: NgbActiveModal, constructor(public modal: NgbActiveModal,
private adminNebApi: AdminNebApiService, private adminNebApi: AdminNebApiService,
private toaster: ToasterService, private toaster: ToasterService,
public translate: TranslateService) { public translate: TranslateService) {
this.translate = translate; this.translate = translate;
} }
@ -36,19 +36,25 @@ export class AdminNebImgurConfigComponent implements OnInit {
this.isLoading = false; this.isLoading = false;
}).catch(err => { }).catch(err => {
console.error(err); console.error(err);
this.translate.get('Error loading configuration').subscribe((res: string) => {this.toaster.pop("error", res); }); this.translate.get('Error loading configuration').subscribe((res: string) => {
this.toaster.pop("error", res);
});
}); });
} }
public save() { public save() {
this.isUpdating = true; this.isUpdating = true;
this.adminNebApi.setIntegrationConfiguration(this.neb.id, this.integration.type, this.config).then(() => { this.adminNebApi.setIntegrationConfiguration(this.neb.id, this.integration.type, this.config).then(() => {
this.translate.get('Configuration updated').subscribe((res: string) => {this.toaster.pop("success", res); }); this.translate.get('Configuration updated').subscribe((res: string) => {
this.toaster.pop("success", res);
});
this.modal.close(); this.modal.close();
}).catch(err => { }).catch(err => {
this.isUpdating = false; this.isUpdating = false;
console.error(err); console.error(err);
this.translate.get('Error updating integration').subscribe((res: string) => {this.toaster.pop("error", res); }); this.translate.get('Error updating integration').subscribe((res: string) => {
this.toaster.pop("error", res);
});
}); });
} }
} }

View File

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

View File

@ -26,18 +26,20 @@ export class AdminNebComponent {
public configurations: FE_NebConfiguration[]; public configurations: FE_NebConfiguration[];
constructor(private nebApi: AdminNebApiService, constructor(private nebApi: AdminNebApiService,
private upstreamApi: AdminUpstreamApiService, private upstreamApi: AdminUpstreamApiService,
private appserviceApi: AdminAppserviceApiService, private appserviceApi: AdminAppserviceApiService,
private toaster: ToasterService, private toaster: ToasterService,
private router: Router, private router: Router,
private activatedRoute: ActivatedRoute, private activatedRoute: ActivatedRoute,
private modal: NgbModal, private modal: NgbModal,
public translate: TranslateService) { public translate: TranslateService) {
this.translate = translate; this.translate = translate;
this.reload().then(() => this.isLoading = false).catch(error => { this.reload().then(() => this.isLoading = false).catch(error => {
console.error(error); console.error(error);
this.translate.get('Error loading go-neb configuration').subscribe((res: string) => {this.toaster.pop("error", res); }); this.translate.get('Error loading go-neb configuration').subscribe((res: string) => {
this.toaster.pop("error", res);
});
}); });
} }
@ -100,13 +102,17 @@ export class AdminNebComponent {
const createNeb = (upstream: FE_Upstream) => { const createNeb = (upstream: FE_Upstream) => {
return this.nebApi.newUpstreamConfiguration(upstream).then(neb => { return this.nebApi.newUpstreamConfiguration(upstream).then(neb => {
this.configurations.push(neb); this.configurations.push(neb);
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.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.isAddingModularNeb = false;
this.hasModularNeb = true; this.hasModularNeb = true;
}).catch(error => { }).catch(error => {
console.error(error); console.error(error);
this.isAddingModularNeb = false; this.isAddingModularNeb = false;
this.translate.get('Error adding matrix.org\'s go-neb').subscribe((res: string) => {this.toaster.pop("error", res); }); this.translate.get('Error adding matrix.org\'s go-neb').subscribe((res: string) => {
this.toaster.pop("error", res);
});
}); });
}; };
@ -119,7 +125,9 @@ export class AdminNebComponent {
createNeb(upstream); createNeb(upstream);
}).catch(err => { }).catch(err => {
console.error(err); console.error(err);
this.translate.get('Error creating matrix.org go-neb').subscribe((res: string) => {this.toaster.pop("error", res); }); this.translate.get('Error creating matrix.org go-neb').subscribe((res: string) => {
this.toaster.pop("error", res);
});
}); });
} else createNeb(vectorUpstreams[0]); } else createNeb(vectorUpstreams[0]);
} }

View File

@ -19,9 +19,9 @@ export class AdminStickerPacksComponent implements OnInit {
public isImporting = false; public isImporting = false;
constructor(private adminStickers: AdminStickersApiService, constructor(private adminStickers: AdminStickersApiService,
private toaster: ToasterService, private toaster: ToasterService,
private modal: NgbModal, private modal: NgbModal,
public translate: TranslateService) { public translate: TranslateService) {
this.translate = translate; this.translate = translate;
} }
@ -31,7 +31,9 @@ export class AdminStickerPacksComponent implements OnInit {
this.isLoading = false; this.isLoading = false;
}).catch(err => { }).catch(err => {
console.error(err); console.error(err);
this.translate.get('Failed to load sticker packs').subscribe((res: string) => {this.toaster.pop("error", res); }); this.translate.get('Failed to load sticker packs').subscribe((res: string) => {
this.toaster.pop("error", res);
});
}); });
} }
@ -40,12 +42,16 @@ export class AdminStickerPacksComponent implements OnInit {
this.isUpdating = true; this.isUpdating = true;
this.adminStickers.togglePack(pack.id, pack.isEnabled).then(() => { this.adminStickers.togglePack(pack.id, pack.isEnabled).then(() => {
this.isUpdating = false; this.isUpdating = false;
this.translate.get('Sticker pack updated').subscribe((res: string) => {this.toaster.pop("success", res); }); this.translate.get('Sticker pack updated').subscribe((res: string) => {
this.toaster.pop("success", res);
});
}).catch(err => { }).catch(err => {
console.error(err); console.error(err);
pack.isEnabled = !pack.isEnabled; // revert change pack.isEnabled = !pack.isEnabled; // revert change
this.isUpdating = false; this.isUpdating = false;
this.translate.get('Error updating sticker pack').subscribe((res: string) => {this.toaster.pop("error", res); }); this.translate.get('Error updating sticker pack').subscribe((res: string) => {
this.toaster.pop("error", res);
});
}); });
} }
@ -62,11 +68,15 @@ export class AdminStickerPacksComponent implements OnInit {
this.isImporting = false; this.isImporting = false;
this.tgUrl = ""; this.tgUrl = "";
this.packs.push(pack); this.packs.push(pack);
this.translate.get('Telegram sticker pack imported').subscribe((res: string) => {this.toaster.pop("success", res); }); this.translate.get('Telegram sticker pack imported').subscribe((res: string) => {
this.toaster.pop("success", res);
});
}).catch(err => { }).catch(err => {
console.error(err); console.error(err);
this.isImporting = false; this.isImporting = false;
this.translate.get('Error importing sticker pack').subscribe((res: string) => {this.toaster.pop("error", res); }); this.translate.get('Error importing sticker pack').subscribe((res: string) => {
this.toaster.pop("error", res);
});
}); });
} }

View File

@ -63,16 +63,16 @@ export class AdminNewEditTermsComponent implements OnInit {
} }
constructor(private adminTerms: AdminTermsApiService, constructor(private adminTerms: AdminTermsApiService,
private toaster: ToasterService, private toaster: ToasterService,
private router: Router, private router: Router,
private activatedRoute: ActivatedRoute, private activatedRoute: ActivatedRoute,
private modal: NgbModal, private modal: NgbModal,
public translate: TranslateService) { public translate: TranslateService) {
this.translate = translate; this.translate = translate;
} }
public ngOnInit() { public ngOnInit() {
let params = this.activatedRoute.snapshot.params; const params = this.activatedRoute.snapshot.params;
this.shortcode = params.shortcode; this.shortcode = params.shortcode;
this.isEditing = !!this.shortcode; this.isEditing = !!this.shortcode;
@ -96,7 +96,9 @@ export class AdminNewEditTermsComponent implements OnInit {
this.isLoading = false; this.isLoading = false;
}).catch(err => { }).catch(err => {
console.error(err); console.error(err);
this.translate.get('Failed to load policy').subscribe((res: string) => {this.toaster.pop("error", res); }); this.translate.get('Failed to load policy').subscribe((res: string) => {
this.toaster.pop("error", res);
});
}); });
} else { } else {
this.adminTerms.getAllPolicies().then(policies => { this.adminTerms.getAllPolicies().then(policies => {
@ -104,7 +106,9 @@ export class AdminNewEditTermsComponent implements OnInit {
this.isLoading = false; this.isLoading = false;
}).catch(err => { }).catch(err => {
console.error(err); console.error(err);
this.translate.get('Failed to load policies').subscribe((res: string) => {this.toaster.pop("error", res); }); this.translate.get('Failed to load policies').subscribe((res: string) => {
this.toaster.pop("error", res);
});
}); });
} }
} }
@ -135,11 +139,15 @@ export class AdminNewEditTermsComponent implements OnInit {
}); });
await this.adminTerms.publishDraft(this.shortcode, val); await this.adminTerms.publishDraft(this.shortcode, val);
this.translate.get('Policy published').subscribe((res: string) => {this.toaster.pop("success", res); }); this.translate.get('Policy published').subscribe((res: string) => {
this.toaster.pop("success", res);
});
this.router.navigate(["../.."], {relativeTo: this.activatedRoute}); this.router.navigate(["../.."], {relativeTo: this.activatedRoute});
} catch (e) { } catch (e) {
console.error(e); console.error(e);
this.translate.get('Error publishing policy').subscribe((res: string) => {this.toaster.pop("error", res); }); this.translate.get('Error publishing policy').subscribe((res: string) => {
this.toaster.pop("error", res);
});
this.isUpdating = false; this.isUpdating = false;
} }
}); });
@ -148,11 +156,15 @@ export class AdminNewEditTermsComponent implements OnInit {
public async create() { public async create() {
for (const languageCode in this.languages) { for (const languageCode in this.languages) {
if (this.languages[languageCode].name.trim().length <= 0) { if (this.languages[languageCode].name.trim().length <= 0) {
this.translate.get('Please enter a name for all policies').subscribe((res: string) => {this.toaster.pop("warning", res); }); this.translate.get('Please enter a name for all policies').subscribe((res: string) => {
this.toaster.pop("warning", res);
});
return; return;
} }
if (this.languages[languageCode].text.trim().length <= 0) { if (this.languages[languageCode].text.trim().length <= 0) {
this.translate.get('Please enter text for all policies').subscribe((res: string) => {this.toaster.pop("warning", res); }); this.translate.get('Please enter text for all policies').subscribe((res: string) => {
this.toaster.pop("warning", res);
});
return; return;
} }
} }
@ -166,11 +178,15 @@ export class AdminNewEditTermsComponent implements OnInit {
text: this.languages['en'].text, text: this.languages['en'].text,
url: `${window.location.origin}/widgets/terms/${this.shortcode}/en/draft`, url: `${window.location.origin}/widgets/terms/${this.shortcode}/en/draft`,
}); });
this.translate.get('Draft saved').subscribe((res: string) => {this.toaster.pop("success", res); }); this.translate.get('Draft saved').subscribe((res: string) => {
this.toaster.pop("success", res);
});
this.router.navigate(["../.."], {relativeTo: this.activatedRoute}); this.router.navigate(["../.."], {relativeTo: this.activatedRoute});
} catch (e) { } catch (e) {
console.error(e); console.error(e);
this.translate.get('Error saving policy').subscribe((res: string) => {this.toaster.pop("error", res); }); this.translate.get('Error saving policy').subscribe((res: string) => {
this.toaster.pop("error", res);
});
this.isUpdating = false; this.isUpdating = false;
} }
return; return;
@ -189,11 +205,15 @@ export class AdminNewEditTermsComponent implements OnInit {
text: this.languages['en'].text, text: this.languages['en'].text,
url: `${window.location.origin}/widgets/terms/${shortcode}/en/draft`, url: `${window.location.origin}/widgets/terms/${shortcode}/en/draft`,
}); });
this.translate.get('Draft created').subscribe((res: string) => {this.toaster.pop("success", res); }); this.translate.get('Draft created').subscribe((res: string) => {
this.toaster.pop("success", res);
});
this.router.navigate([".."], {relativeTo: this.activatedRoute}); this.router.navigate([".."], {relativeTo: this.activatedRoute});
} catch (e) { } catch (e) {
console.error(e); console.error(e);
this.translate.get('Error creating document').subscribe((res: string) => {this.toaster.pop("error", res); }); this.translate.get('Error creating document').subscribe((res: string) => {
this.toaster.pop("error", res);
});
this.isUpdating = false; this.isUpdating = false;
} }
} }

View File

@ -19,7 +19,9 @@ export class AdminTermsNewEditPublishDialogComponent {
public publish() { public publish() {
if (!this.version || !this.version.trim()) { if (!this.version || !this.version.trim()) {
this.translate.get('Please enter a version number').subscribe((res: string) => {this.toaster.pop("warning", res); }); this.translate.get('Please enter a version number').subscribe((res: string) => {
this.toaster.pop("warning", res);
});
return; return;
} }
this.modal.close(this.version); this.modal.close(this.version);

View File

@ -26,7 +26,7 @@
<td class="text-center"> <td class="text-center">
<span class="editButton" [routerLink]="['edit', policy.shortcode]" title="edit draft" <span class="editButton" [routerLink]="['edit', policy.shortcode]" title="edit draft"
*ngIf="policy.version == 'draft'"> *ngIf="policy.version === 'draft'">
<i class="fa fa-pencil-alt"></i> <i class="fa fa-pencil-alt"></i>
</span> </span>
</td> </td>

View File

@ -18,10 +18,10 @@ export class AdminTermsComponent implements OnInit {
public policies: FE_TermsEditable[]; public policies: FE_TermsEditable[];
constructor(private adminTerms: AdminTermsApiService, constructor(private adminTerms: AdminTermsApiService,
private toaster: ToasterService, private toaster: ToasterService,
private router: Router, private router: Router,
private activatedRoute: ActivatedRoute, private activatedRoute: ActivatedRoute,
public translate: TranslateService) { public translate: TranslateService) {
this.translate = translate; this.translate = translate;
} }
@ -34,7 +34,9 @@ export class AdminTermsComponent implements OnInit {
this.isLoading = false; this.isLoading = false;
}).catch(err => { }).catch(err => {
console.error(err); console.error(err);
this.translate.get('Failed to load policies').subscribe((res: string) => {this.toaster.pop("error", res); }); this.translate.get('Failed to load policies').subscribe((res: string) => {
this.toaster.pop("error", res);
});
}); });
} }

View File

@ -16,9 +16,9 @@ export class AdminWidgetEtherpadConfigComponent implements OnInit {
private originalWidget = <FE_EtherpadWidget>{}; private originalWidget = <FE_EtherpadWidget>{};
constructor(public modal: NgbActiveModal, constructor(public modal: NgbActiveModal,
private adminIntegrationsApi: AdminIntegrationsApiService, private adminIntegrationsApi: AdminIntegrationsApiService,
private toaster: ToasterService, private toaster: ToasterService,
public translate: TranslateService) { public translate: TranslateService) {
this.translate = translate; this.translate = translate;
} }
@ -31,12 +31,16 @@ export class AdminWidgetEtherpadConfigComponent implements OnInit {
this.isUpdating = true; this.isUpdating = true;
this.adminIntegrationsApi.setIntegrationOptions(this.widget.category, this.widget.type, this.widget.options).then(() => { this.adminIntegrationsApi.setIntegrationOptions(this.widget.category, this.widget.type, this.widget.options).then(() => {
this.originalWidget.options = this.widget.options; this.originalWidget.options = this.widget.options;
this.translate.get('Widget updated').subscribe((res: string) => {this.toaster.pop("success", res); }); this.translate.get('Widget updated').subscribe((res: string) => {
this.toaster.pop("success", res);
});
this.modal.close(); this.modal.close();
}).catch(err => { }).catch(err => {
this.isUpdating = false; this.isUpdating = false;
console.error(err); console.error(err);
this.translate.get('Error updating widget').subscribe((res: string) => {this.toaster.pop("error", res); }); this.translate.get('Error updating widget').subscribe((res: string) => {
this.toaster.pop("error", res);
});
}); });
} }
} }

View File

@ -16,10 +16,10 @@ export class AdminWidgetJitsiConfigComponent implements OnInit {
private originalWidget = <FE_JitsiWidget>{}; private originalWidget = <FE_JitsiWidget>{};
constructor(public modal: NgbActiveModal, constructor(public modal: NgbActiveModal,
private adminIntegrationsApi: AdminIntegrationsApiService, private adminIntegrationsApi: AdminIntegrationsApiService,
private toaster: ToasterService, private toaster: ToasterService,
public translate: TranslateService) { public translate: TranslateService) {
this.translate = translate; this.translate = translate;
} }
ngOnInit() { ngOnInit() {
@ -34,12 +34,16 @@ export class AdminWidgetJitsiConfigComponent implements OnInit {
this.isUpdating = true; this.isUpdating = true;
this.adminIntegrationsApi.setIntegrationOptions(this.widget.category, this.widget.type, this.widget.options).then(() => { this.adminIntegrationsApi.setIntegrationOptions(this.widget.category, this.widget.type, this.widget.options).then(() => {
this.originalWidget.options = this.widget.options; this.originalWidget.options = this.widget.options;
this.translate.get('Widget updated').subscribe((res: string) => {this.toaster.pop("success", res); }); this.translate.get('Widget updated').subscribe((res: string) => {
this.toaster.pop("success", res);
});
this.modal.close(); this.modal.close();
}).catch(err => { }).catch(err => {
this.isUpdating = false; this.isUpdating = false;
console.error(err); console.error(err);
this.translate.get('Error updating widget').subscribe((res: string) => {this.toaster.pop("error", res); }); this.translate.get('Error updating widget').subscribe((res: string) => {
this.toaster.pop("error", res);
});
}); });
} }

View File

@ -16,9 +16,9 @@ export class AdminWidgetWhiteboardConfigComponent implements OnInit {
private originalWidget: FE_WhiteBoardWidget; private originalWidget: FE_WhiteBoardWidget;
constructor(public modal: NgbActiveModal, constructor(public modal: NgbActiveModal,
private adminIntegrationsApi: AdminIntegrationsApiService, private adminIntegrationsApi: AdminIntegrationsApiService,
private toaster: ToasterService, private toaster: ToasterService,
public translate: TranslateService) { public translate: TranslateService) {
this.translate = translate; this.translate = translate;
} }

View File

@ -29,7 +29,9 @@ export class AdminWidgetsComponent {
this.widgets = widgets; this.widgets = widgets;
}).catch(err => { }).catch(err => {
console.error(err); console.error(err);
this.translate.get('Failed to load widgets').subscribe((res: string) => {this.toaster.pop("error", res); }); this.translate.get('Failed to load widgets').subscribe((res: string) => {
this.toaster.pop("error", res);
});
}); });
} }
@ -38,12 +40,16 @@ export class AdminWidgetsComponent {
this.isUpdating = true; this.isUpdating = true;
this.adminIntegrationsApi.toggleIntegration(widget.category, widget.type, widget.isEnabled).then(() => { this.adminIntegrationsApi.toggleIntegration(widget.category, widget.type, widget.isEnabled).then(() => {
this.isUpdating = false; this.isUpdating = false;
this.translate.get('Widget updated').subscribe((res: string) => {this.toaster.pop("success", res); }); this.translate.get('Widget updated').subscribe((res: string) => {
this.toaster.pop("success", res);
});
}).catch(err => { }).catch(err => {
console.error(err); console.error(err);
widget.isEnabled = !widget.isEnabled; // revert change widget.isEnabled = !widget.isEnabled; // revert change
this.isUpdating = false; this.isUpdating = false;
this.translate.get('Error updating widget').subscribe((res: string) => {this.toaster.pop("error", res); }); this.translate.get('Error updating widget').subscribe((res: string) => {
this.toaster.pop("error", res);
});
}); });
} }
@ -56,7 +62,9 @@ export class AdminWidgetsComponent {
if (!component) { if (!component) {
console.error("No known dialog component for " + widget.type); console.error("No known dialog component for " + widget.type);
this.translate.get('Error opening configuration page').subscribe((res: string) => {this.toaster.pop("error", res); }); this.translate.get('Error opening configuration page').subscribe((res: string) => {
this.toaster.pop("error", res);
});
return; return;
} }

View File

@ -4,19 +4,18 @@ import { TranslateService } from "@ngx-translate/core";
import { HttpClient } from "@angular/common/http"; import { HttpClient } from "@angular/common/http";
@Component({ @Component({
selector: "my-app", // <my-app></my-app> selector: "app-app", // <my-app></my-app>
templateUrl: "./app.component.html", templateUrl: "./app.component.html",
styleUrls: ["./app.component.scss"], styleUrls: ["./app.component.scss"],
}) })
export class AppComponent { export class AppComponent {
constructor(public translate: TranslateService, public http: HttpClient) { constructor(public translate: TranslateService, public http: HttpClient) {
translate.addLangs(['en', 'de']); translate.addLangs(["en", "de"]);
translate.setDefaultLang('de'); translate.setDefaultLang("de");
if (navigator.language === 'de') { if (navigator.language === "de") {
translate.use('de'); translate.use("de");
} else { } else {
translate.use('en'); translate.use("en");
} }
} }
} }

View File

@ -122,7 +122,7 @@ import { FontAwesomeModule } from '@fortawesome/angular-fontawesome';
// AoT requires an exported function for factories // AoT requires an exported function for factories
export function HttpLoaderFactory(http: HttpClient) { export function HttpLoaderFactory(http: HttpClient) {
return new TranslateHttpLoader(http); return new TranslateHttpLoader(http);
} }
@NgModule({ @NgModule({
@ -286,27 +286,27 @@ export function HttpLoaderFactory(http: HttpClient) {
] ]
}) })
export class AppModule { export class AppModule {
constructor(public appRef: ApplicationRef, injector: Injector) { constructor(public appRef: ApplicationRef, injector: Injector) {
ServiceLocator.injector = injector; ServiceLocator.injector = injector;
} }
hmrOnInit(store) { hmrOnInit(store) {
console.log("HMR store", store); console.log("HMR store", store);
} }
hmrOnDestroy(store) { hmrOnDestroy(store) {
let cmpLocation = this.appRef.components.map( const cmpLocation = this.appRef.components.map(
(cmp) => cmp.location.nativeElement (cmp) => cmp.location.nativeElement
); );
// recreate elements // recreate elements
store.disposeOldHosts = createNewHosts(cmpLocation); store.disposeOldHosts = createNewHosts(cmpLocation);
// remove styles // remove styles
removeNgStyles(); removeNgStyles();
} }
hmrAfterDestroy(store) { hmrAfterDestroy(store) {
// display new elements // display new elements
store.disposeOldHosts(); store.disposeOldHosts();
delete store.disposeOldHosts; delete store.disposeOldHosts;
} }
} }

View File

@ -52,19 +52,25 @@ export class BridgeComponent<T> implements OnInit, OnDestroy {
this.isLoading = false; this.isLoading = false;
}).catch(err => { }).catch(err => {
console.error(err); console.error(err);
this.translate.get("Failed to load configuration").subscribe((res: string) => {this.toaster.pop("error", res); }); this.translate.get("Failed to load configuration").subscribe((res: string) => {
this.toaster.pop("error", res);
});
}); });
} }
public save(): void { public save(): void {
this.isUpdating = true; this.isUpdating = true;
this.integrationsApi.setIntegrationConfiguration("bridge", this.integrationType, this.roomId, this.newConfig).then(() => { this.integrationsApi.setIntegrationConfiguration("bridge", this.integrationType, this.roomId, this.newConfig).then(() => {
this.translate.get("Configuration updated").subscribe((res: string) => {this.toaster.pop("success", res); }); this.translate.get("Configuration updated").subscribe((res: string) => {
this.toaster.pop("success", res);
});
this.bridge.config = this.newConfig; this.bridge.config = this.newConfig;
this.isUpdating = false; this.isUpdating = false;
}).catch(err => { }).catch(err => {
console.error(err); console.error(err);
this.translate.get("Error updating configuration").subscribe((res: string) => {this.toaster.pop("error", res); }); this.translate.get("Error updating configuration").subscribe((res: string) => {
this.toaster.pop("error", res);
});
this.isUpdating = false; this.isUpdating = false;
}); });
} }

View File

@ -2,15 +2,14 @@ import { Component, ContentChild, Input, TemplateRef } from "@angular/core";
import { BridgeComponent } from "../bridge.component"; import { BridgeComponent } from "../bridge.component";
@Component({ @Component({
selector: "my-bridge-config", selector: "app-bridge-config",
templateUrl: "config-screen.bridge.component.html", templateUrl: "config-screen.bridge.component.html",
styleUrls: ["config-screen.bridge.component.scss"], styleUrls: ["config-screen.bridge.component.scss"],
}) })
export class ConfigScreenBridgeComponent { export class ConfigScreenBridgeComponent {
@Input() bridgeComponent: BridgeComponent<any>; @Input() bridgeComponent: BridgeComponent<any>;
@ContentChild(TemplateRef, {static: false}) bridgeParamsTemplate: TemplateRef<any>; @ContentChild(TemplateRef, { static: false })
bridgeParamsTemplate: TemplateRef<any>;
constructor() { constructor() {}
} }
}

View File

@ -57,7 +57,9 @@ export class IrcBridgeConfigComponent extends BridgeComponent<IrcConfig> {
public loadOps() { public loadOps() {
if (!this.channel.trim()) { if (!this.channel.trim()) {
this.translate.get('Please enter a channel name').subscribe((res: string) => {this.toaster.pop("warning", res); }); this.translate.get('Please enter a channel name').subscribe((res: string) => {
this.toaster.pop("warning", res);
});
return; return;
} }
@ -70,7 +72,9 @@ export class IrcBridgeConfigComponent extends BridgeComponent<IrcConfig> {
}).catch(err => { }).catch(err => {
console.error(err); console.error(err);
this.loadingOps = false; this.loadingOps = false;
this.translate.get('Error loading channel operators').subscribe((res: string) => {this.toaster.pop("error", res); }); this.translate.get('Error loading channel operators').subscribe((res: string) => {
this.toaster.pop("error", res);
});
}); });
} }
@ -88,7 +92,9 @@ export class IrcBridgeConfigComponent extends BridgeComponent<IrcConfig> {
} catch (err) { } catch (err) {
console.error(err); console.error(err);
this.requestingBridge = false; this.requestingBridge = false;
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]); }); 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; return;
} }
@ -101,11 +107,15 @@ export class IrcBridgeConfigComponent extends BridgeComponent<IrcConfig> {
pending: true, pending: true,
}); });
this.resetForm(); this.resetForm();
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]); }); 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 => { }).catch(err => {
console.error(err); console.error(err);
this.requestingBridge = false; this.requestingBridge = false;
this.translate.get('Failed to request a link').subscribe((res: string) => {this.toaster.pop("error", res); }); this.translate.get('Failed to request a link').subscribe((res: string) => {
this.toaster.pop("error", res);
});
}); });
} }
@ -135,10 +145,14 @@ export class IrcBridgeConfigComponent extends BridgeComponent<IrcConfig> {
this.isUpdating = false; this.isUpdating = false;
const idx = this.bridge.config.links[channel.networkId].findIndex(c => c.channelName === channel.name); 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); if (idx !== -1) this.bridge.config.links[channel.networkId].splice(idx, 1);
this.translate.get('Link removed').subscribe((res: string) => {this.toaster.pop("success", res); }); this.translate.get('Link removed').subscribe((res: string) => {
this.toaster.pop("success", res);
});
}).catch(err => { }).catch(err => {
console.error(err); console.error(err);
this.translate.get('Failed to remove link').subscribe((res: string) => {this.toaster.pop("error", res); }); this.translate.get('Failed to remove link').subscribe((res: string) => {
this.toaster.pop("error", res);
});
}); });
} }
} }

View File

@ -60,7 +60,9 @@ export class SlackBridgeConfigComponent extends BridgeComponent<SlackConfig> imp
this.loadingTeams = false; this.loadingTeams = false;
}).catch(error2 => { }).catch(error2 => {
console.error(error2); console.error(error2);
this.translate.get('Error getting Slack authorization information').subscribe((res: string) => {this.toaster.pop("error", res); }); this.translate.get('Error getting Slack authorization information').subscribe((res: string) => {
this.toaster.pop("error", res);
});
}); });
this.timerId = setInterval(() => { this.timerId = setInterval(() => {
@ -69,7 +71,9 @@ export class SlackBridgeConfigComponent extends BridgeComponent<SlackConfig> imp
} }
} else { } else {
console.error(error); console.error(error);
this.translate.get('Error getting teams').subscribe((res: string) => {this.toaster.pop("error", res); }); this.translate.get('Error getting teams').subscribe((res: string) => {
this.toaster.pop("error", res);
});
} }
}); });
} }
@ -86,7 +90,9 @@ export class SlackBridgeConfigComponent extends BridgeComponent<SlackConfig> imp
this.isBusy = false; this.isBusy = false;
}).catch(error => { }).catch(error => {
console.error(error); console.error(error);
this.translate.get('Error getting channels for team').subscribe((res: string) => {this.toaster.pop("error", res); }); this.translate.get('Error getting channels for team').subscribe((res: string) => {
this.toaster.pop("error", res);
});
this.isBusy = false; this.isBusy = false;
}); });
} }
@ -100,7 +106,9 @@ export class SlackBridgeConfigComponent extends BridgeComponent<SlackConfig> imp
if (!e.response || !e.response.error || !e.response.error._error || if (!e.response || !e.response.error || !e.response.error._error ||
e.response.error._error.message.indexOf("already in the room") === -1) { e.response.error._error.message.indexOf("already in the room") === -1) {
this.isBusy = false; this.isBusy = false;
this.translate.get('Error inviting bridge').subscribe((res: string) => {this.toaster.pop("error", res); }); this.translate.get('Error inviting bridge').subscribe((res: string) => {
this.toaster.pop("error", res);
});
return; return;
} }
} }
@ -108,11 +116,15 @@ export class SlackBridgeConfigComponent extends BridgeComponent<SlackConfig> imp
this.slack.bridgeRoom(this.roomId, this.teamId, this.channelId).then(link => { this.slack.bridgeRoom(this.roomId, this.teamId, this.channelId).then(link => {
this.bridge.config.link = link; this.bridge.config.link = link;
this.isBusy = false; this.isBusy = false;
this.translate.get('Bridge requested').subscribe((res: string) => {this.toaster.pop("success", res); }); this.translate.get('Bridge requested').subscribe((res: string) => {
this.toaster.pop("success", res);
});
}).catch(error => { }).catch(error => {
this.isBusy = false; this.isBusy = false;
console.error(error); console.error(error);
this.translate.get('Error requesting bridge').subscribe((res: string) => {this.toaster.pop("error", res); }); this.translate.get('Error requesting bridge').subscribe((res: string) => {
this.toaster.pop("error", res);
});
}); });
} }
@ -121,11 +133,15 @@ export class SlackBridgeConfigComponent extends BridgeComponent<SlackConfig> imp
this.slack.unbridgeRoom(this.roomId).then(() => { this.slack.unbridgeRoom(this.roomId).then(() => {
this.bridge.config.link = null; this.bridge.config.link = null;
this.isBusy = false; this.isBusy = false;
this.translate.get('Bridge removed').subscribe((res: string) => {this.toaster.pop("success", res); }); this.translate.get('Bridge removed').subscribe((res: string) => {
this.toaster.pop("success", res);
});
}).catch(error => { }).catch(error => {
this.isBusy = false; this.isBusy = false;
console.error(error); console.error(error);
this.translate.get('Error removing bridge').subscribe((res: string) => {this.toaster.pop("error", res); }); this.translate.get('Error removing bridge').subscribe((res: string) => {
this.toaster.pop("error", res);
});
}); });
} }
} }

View File

@ -106,7 +106,9 @@ export class TelegramBridgeConfigComponent extends BridgeComponent<TelegramConfi
this.bridge.config.portalInfo = loadedPortalInfo; this.bridge.config.portalInfo = loadedPortalInfo;
this.bridge.config.linked = [loadedPortalInfo.chatId]; this.bridge.config.linked = [loadedPortalInfo.chatId];
this.isUpdating = false; this.isUpdating = false;
this.translate.get('Bridge updated').subscribe((res: string) => {this.toaster.pop("success", res); }); this.translate.get('Bridge updated').subscribe((res: string) => {
this.toaster.pop("success", res);
});
}).catch(error => { }).catch(error => {
this.isUpdating = false; this.isUpdating = false;
console.error(error); console.error(error);
@ -118,8 +120,10 @@ export class TelegramBridgeConfigComponent extends BridgeComponent<TelegramConfi
if (body["dim_errcode"] === "ROOM_ALREADY_BRIDGED") message = 'This room is already bridged to a Telegram chat'; 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"] === "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"] === "NOT_ENOUGH_PERMISSIONS") message = 'You do not have permission to bridge that chat';
} }
this.translate.get(message).subscribe((res: string) => {this.toaster.pop("error", res); }); this.translate.get(message).subscribe((res: string) => {
this.toaster.pop("error", res);
});
}); });
} }
@ -129,7 +133,9 @@ export class TelegramBridgeConfigComponent extends BridgeComponent<TelegramConfi
this.bridge.config.portalInfo = portalInfo; this.bridge.config.portalInfo = portalInfo;
this.bridge.config.linked = []; this.bridge.config.linked = [];
this.isUpdating = false; this.isUpdating = false;
this.translate.get('Bridge removed').subscribe((res: string) => {this.toaster.pop("success", res); }); this.translate.get('Bridge removed').subscribe((res: string) => {
this.toaster.pop("success", res);
});
}).catch(error => { }).catch(error => {
this.isUpdating = false; this.isUpdating = false;
console.error(error); console.error(error);
@ -139,7 +145,9 @@ export class TelegramBridgeConfigComponent extends BridgeComponent<TelegramConfi
if (body["dim_errcode"] === "BOT_NOT_IN_CHAT") message = 'The Telegram bot has not been invited to the 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'; if (body["dim_errcode"] === "NOT_ENOUGH_PERMISSIONS") message = 'You do not have permission to unbridge that chat';
} }
this.translate.get(message).subscribe((res: string) => {this.toaster.pop("error", res); }); this.translate.get(message).subscribe((res: string) => {
this.toaster.pop("error", res);
});
}); });
} }
} }

View File

@ -32,7 +32,9 @@ export class WebhooksBridgeConfigComponent extends BridgeComponent<WebhooksConfi
if (!e.response || !e.response.error || !e.response.error._error || if (!e.response || !e.response.error || !e.response.error._error ||
e.response.error._error.message.indexOf("already in the room") === -1) { e.response.error._error.message.indexOf("already in the room") === -1) {
this.isBusy = false; this.isBusy = false;
this.translate.get('Error inviting bridge').subscribe((res: string) => {this.toaster.pop("error", res); }); this.translate.get('Error inviting bridge').subscribe((res: string) => {
this.toaster.pop("error", res);
});
return; return;
} }
} }
@ -41,11 +43,15 @@ export class WebhooksBridgeConfigComponent extends BridgeComponent<WebhooksConfi
this.newConfig.webhooks.push(hook); this.newConfig.webhooks.push(hook);
this.isBusy = false; this.isBusy = false;
this.webhookName = ""; this.webhookName = "";
this.translate.get('Webhook created').subscribe((res: string) => {this.toaster.pop("success", res); }); this.translate.get('Webhook created').subscribe((res: string) => {
this.toaster.pop("success", res);
});
}).catch(err => { }).catch(err => {
console.error(err); console.error(err);
this.isBusy = false; this.isBusy = false;
this.translate.get('Error creating webhook').subscribe((res: string) => {this.toaster.pop("error", res); }); this.translate.get('Error creating webhook').subscribe((res: string) => {
this.toaster.pop("error", res);
});
}); });
} }
@ -55,11 +61,15 @@ export class WebhooksBridgeConfigComponent extends BridgeComponent<WebhooksConfi
const idx = this.newConfig.webhooks.indexOf(hook); const idx = this.newConfig.webhooks.indexOf(hook);
if (idx !== -1) this.newConfig.webhooks.splice(idx, 1); if (idx !== -1) this.newConfig.webhooks.splice(idx, 1);
this.isBusy = false; this.isBusy = false;
this.translate.get('Webhook deleted').subscribe((res: string) => {this.toaster.pop("success", res); }); this.translate.get('Webhook deleted').subscribe((res: string) => {
this.toaster.pop("success", res);
});
}).catch(err => { }).catch(err => {
console.error(err); console.error(err);
this.isBusy = false; this.isBusy = false;
this.translate.get('Error deleting webhook').subscribe((res: string) => {this.toaster.pop("error", res); }); this.translate.get('Error deleting webhook').subscribe((res: string) => {
this.toaster.pop("error", res);
});
}); });
} }
} }

View File

@ -53,20 +53,26 @@ export class ComplexBotComponent<T> implements OnInit, OnDestroy {
this.isLoading = false; this.isLoading = false;
}).catch(err => { }).catch(err => {
console.error(err); console.error(err);
this.translate.get("Failed to load configuration").subscribe((res: string) => {this.toaster.pop("error", res); }); this.translate.get("Failed to load configuration").subscribe((res: string) => {
this.toaster.pop("error", res);
});
}); });
} }
public save(): void { public save(): void {
this.isUpdating = true; this.isUpdating = true;
this.integrationsApi.setIntegrationConfiguration("complex-bot", this.integrationType, this.roomId, this.newConfig).then(() => { this.integrationsApi.setIntegrationConfiguration("complex-bot", this.integrationType, this.roomId, this.newConfig).then(() => {
this.translate.get("Configuration updated").subscribe((res: string) => {this.toaster.pop("success", res); }); this.translate.get("Configuration updated").subscribe((res: string) => {
this.toaster.pop("success", res);
});
this.bot.config = this.newConfig; this.bot.config = this.newConfig;
this.newConfig = JSON.parse(JSON.stringify(this.bot.config)); this.newConfig = JSON.parse(JSON.stringify(this.bot.config));
this.isUpdating = false; this.isUpdating = false;
}).catch(err => { }).catch(err => {
console.error(err); console.error(err);
this.translate.get("Error updating configuration").subscribe((res: string) => {this.toaster.pop("error", res); }); this.translate.get("Error updating configuration").subscribe((res: string) => {
this.toaster.pop("error", res);
});
this.isUpdating = false; this.isUpdating = false;
}); });
} }

View File

@ -2,15 +2,14 @@ import { ComplexBotComponent } from "../complex-bot.component";
import { Component, ContentChild, Input, TemplateRef } from "@angular/core"; import { Component, ContentChild, Input, TemplateRef } from "@angular/core";
@Component({ @Component({
selector: "my-complex-bot-config", selector: "app-complex-bot-config",
templateUrl: "config-screen.complex-bot.component.html", templateUrl: "config-screen.complex-bot.component.html",
styleUrls: ["config-screen.complex-bot.component.scss"], styleUrls: ["config-screen.complex-bot.component.scss"],
}) })
export class ConfigScreenComplexBotComponent { export class ConfigScreenComplexBotComponent {
@Input() botComponent: ComplexBotComponent<any>; @Input() botComponent: ComplexBotComponent<any>;
@ContentChild(TemplateRef, {static: false}) botParamsTemplate: TemplateRef<any>; @ContentChild(TemplateRef, { static: false })
botParamsTemplate: TemplateRef<any>;
constructor() { constructor() {}
} }
}

View File

@ -32,7 +32,9 @@ export class RssComplexBotConfigComponent extends ComplexBotComponent<RssConfig>
public addFeed(): void { public addFeed(): void {
if (!this.newFeedUrl.trim()) { if (!this.newFeedUrl.trim()) {
this.translate.get('Please enter a feed URL').subscribe((res: string) => {this.toaster.pop('warning', res); }); this.translate.get('Please enter a feed URL').subscribe((res: string) => {
this.toaster.pop('warning', res);
});
return; return;
} }

View File

@ -52,7 +52,9 @@ export class TravisCiComplexBotConfigComponent extends ComplexBotComponent<Travi
public addRepo(): void { public addRepo(): void {
if (!this.newRepoKey.trim()) { if (!this.newRepoKey.trim()) {
this.translate.get('Please enter a repository').subscribe((res: string) => {this.toaster.pop('warning', res); }); this.translate.get('Please enter a repository').subscribe((res: string) => {
this.toaster.pop('warning', res);
});
return; return;
} }

View File

@ -22,10 +22,10 @@ export class ConfigSimpleBotComponent implements OnInit {
private roomId: string; private roomId: string;
constructor(public modal: NgbActiveModal, constructor(public modal: NgbActiveModal,
private toaster: ToasterService, private toaster: ToasterService,
private scalar: ScalarClientApiService, private scalar: ScalarClientApiService,
private integrationsApi: IntegrationsApiService, private integrationsApi: IntegrationsApiService,
public translate: TranslateService) { public translate: TranslateService) {
this.translate = translate; this.translate = translate;
} }
@ -44,9 +44,13 @@ export class ConfigSimpleBotComponent implements OnInit {
promise.then(() => { promise.then(() => {
this.bot._isUpdating = false; this.bot._isUpdating = false;
if (this.bot._inRoom) { if (this.bot._inRoom) {
this.translate.get('was invited to the room').subscribe((res: string) => {this.toaster.pop("success", this.bot.displayName + res); }); this.translate.get('was invited to the room').subscribe((res: string) => {
this.toaster.pop("success", this.bot.displayName + res);
});
} else { } else {
this.translate.get('was removed from the room').subscribe((res: string) => {this.toaster.pop("success", this.bot.displayName + res); }); this.translate.get('was removed from the room').subscribe((res: string) => {
this.toaster.pop("success", this.bot.displayName + res);
});
} }
}).catch(err => { }).catch(err => {
this.bot._inRoom = !this.bot._inRoom; // revert the status change this.bot._inRoom = !this.bot._inRoom; // revert the status change
@ -57,7 +61,9 @@ export class ConfigSimpleBotComponent implements OnInit {
if (err.json) errorMessage = err.json().error; if (err.json) errorMessage = err.json().error;
if (err.response && err.response.error) errorMessage = err.response.error.message; if (err.response && err.response.error) errorMessage = err.response.error.message;
if (!errorMessage) errorMessage = ""; if (!errorMessage) errorMessage = "";
this.translate.get('Could not update integration status').subscribe((res: string) => {this.toaster.pop("error", res); }); this.translate.get('Could not update integration status').subscribe((res: string) => {
this.toaster.pop("error", res);
});
}); });
} }
} }

View File

@ -25,11 +25,11 @@ export class StickerpickerComponent implements OnInit {
public stickerBot: string; public stickerBot: string;
constructor(private stickerApi: StickerApiService, constructor(private stickerApi: StickerApiService,
private media: MediaService, private media: MediaService,
private scalarClient: ScalarClientApiService, private scalarClient: ScalarClientApiService,
private toaster: ToasterService, private toaster: ToasterService,
private window: Window, private window: Window,
public translate?: TranslateService) { public translate?: TranslateService) {
this.translate = translate; this.translate = translate;
this.isLoading = true; this.isLoading = true;
this.isUpdating = false; this.isUpdating = false;
@ -41,7 +41,9 @@ export class StickerpickerComponent implements OnInit {
this.isLoading = false; this.isLoading = false;
} catch (e) { } catch (e) {
console.error(e); console.error(e);
this.translate.get('Failed to load sticker packs').subscribe((res: string) => {this.toaster.pop("error", res); }); this.translate.get('Failed to load sticker packs').subscribe((res: string) => {
this.toaster.pop("error", res);
});
} }
this.stickerApi.getConfig().then(config => { this.stickerApi.getConfig().then(config => {
@ -58,12 +60,16 @@ export class StickerpickerComponent implements OnInit {
this.packs.splice(0, 0, pack); this.packs.splice(0, 0, pack);
this.packUrl = ""; this.packUrl = "";
this.isImporting = false; this.isImporting = false;
this.translate.get('Stickerpack added').subscribe((res: string) => {this.toaster.pop("success", res); }); this.translate.get('Stickerpack added').subscribe((res: string) => {
this.toaster.pop("success", res);
});
this.addWidget(); this.addWidget();
}).catch(err => { }).catch(err => {
console.error(err); console.error(err);
this.isImporting = false; this.isImporting = false;
this.translate.get('Error adding stickerpack').subscribe((res: string) => {this.toaster.pop("error", res); }); this.translate.get('Error adding stickerpack').subscribe((res: string) => {
this.toaster.pop("error", res);
});
}); });
} }
@ -76,13 +82,17 @@ export class StickerpickerComponent implements OnInit {
this.isUpdating = true; this.isUpdating = true;
this.stickerApi.togglePackSelection(pack.id, pack.isSelected).then(() => { this.stickerApi.togglePackSelection(pack.id, pack.isSelected).then(() => {
this.isUpdating = false; this.isUpdating = false;
this.translate.get('Stickers updated').subscribe((res: string) => {this.toaster.pop("success", res); }); this.translate.get('Stickers updated').subscribe((res: string) => {
this.toaster.pop("success", res);
});
if (this.packs.filter(p => p.isSelected).length > 0) this.addWidget(); if (this.packs.filter(p => p.isSelected).length > 0) this.addWidget();
}).catch(err => { }).catch(err => {
console.error(err); console.error(err);
pack.isSelected = !pack.isSelected; // revert change pack.isSelected = !pack.isSelected; // revert change
this.isUpdating = false; this.isUpdating = false;
this.translate.get('Error updating stickers').subscribe((res: string) => {this.toaster.pop("error", res); }); this.translate.get('Error updating stickers').subscribe((res: string) => {
this.toaster.pop("error", res);
});
}); });
} }

View File

@ -2,15 +2,14 @@ import { WidgetComponent } from "../widget.component";
import { Component, ContentChild, Input, TemplateRef } from "@angular/core"; import { Component, ContentChild, Input, TemplateRef } from "@angular/core";
@Component({ @Component({
selector: "my-widget-config", selector: "app-widget-config",
templateUrl: "config-screen.widget.component.html", templateUrl: "config-screen.widget.component.html",
styleUrls: ["config-screen.widget.component.scss"], styleUrls: ["config-screen.widget.component.scss"],
}) })
export class ConfigScreenWidgetComponent { export class ConfigScreenWidgetComponent {
@Input() widgetComponent: WidgetComponent; @Input() widgetComponent: WidgetComponent;
@ContentChild(TemplateRef, {static: false}) widgetParamsTemplate: TemplateRef<any>; @ContentChild(TemplateRef, { static: false })
widgetParamsTemplate: TemplateRef<any>;
constructor() { constructor() {}
} }
}

View File

@ -33,11 +33,11 @@ export class WidgetComponent implements OnInit {
private scalarApi = ServiceLocator.injector.get(ScalarClientApiService); private scalarApi = ServiceLocator.injector.get(ScalarClientApiService);
constructor(@Inject(String) private widgetTypes: string[], constructor(@Inject(String) private widgetTypes: string[],
@Inject(String) public defaultName: string, @Inject(String) public defaultName: string,
@Inject(String) private wrapperId = "generic", @Inject(String) private wrapperId = "generic",
public translate: TranslateService, public translate: TranslateService,
@Inject(String) private scalarWrapperId = null, @Inject(String) private scalarWrapperId = null,
@Inject(String) private scalarWrapperUrlParamName = "url") { @Inject(String) private scalarWrapperUrlParamName = "url") {
this.translate = translate; this.translate = translate;
this.isLoading = true; this.isLoading = true;
@ -49,7 +49,7 @@ export class WidgetComponent implements OnInit {
this.wrapperUrl = this.window.location.origin + "/widgets/" + this.wrapperId + "?url="; this.wrapperUrl = this.window.location.origin + "/widgets/" + this.wrapperId + "?url=";
if (!this.scalarWrapperId) this.scalarWrapperId = this.wrapperId; if (!this.scalarWrapperId) this.scalarWrapperId = this.wrapperId;
for (let widgetLink of SCALAR_WIDGET_LINKS) { for (const widgetLink of SCALAR_WIDGET_LINKS) {
const wrapperLink = widgetLink const wrapperLink = widgetLink
.replace("__TYPE__", this.scalarWrapperId) .replace("__TYPE__", this.scalarWrapperId)
.replace("__PNAME__", this.scalarWrapperUrlParamName); .replace("__PNAME__", this.scalarWrapperUrlParamName);
@ -60,7 +60,7 @@ export class WidgetComponent implements OnInit {
this.prepareNewWidget(); this.prepareNewWidget();
this.getWidgetsOfType(this.widgetTypes).then(widgets => { this.getWidgetsOfType(this.widgetTypes).then(widgets => {
this.widgets = widgets; this.widgets = widgets;
for (let widget of this.widgets) { for (const widget of this.widgets) {
this.unpackWidget(widget); this.unpackWidget(widget);
} }
@ -70,15 +70,15 @@ export class WidgetComponent implements OnInit {
// We reset after discovering to ensure that the widget component can correctly // We reset after discovering to ensure that the widget component can correctly
// set the state of the widget prior to us unpacking it (again) // set the state of the widget prior to us unpacking it (again)
for (let widget of this.widgets) { for (const widget of this.widgets) {
this.resetWidget(widget); this.resetWidget(widget);
} }
// See if we should request editing a particular widget // See if we should request editing a particular widget
if (SessionStorage.editIntegrationId && SessionStorage.editsRequested === 1) { if (SessionStorage.editIntegrationId && SessionStorage.editsRequested === 1) {
let editWidget: EditableWidget = null; let editWidget: EditableWidget = null;
let otherWidgets: EditableWidget[] = []; const otherWidgets: EditableWidget[] = [];
for (let widget of this.widgets) { for (const widget of this.widgets) {
if (widget.id === SessionStorage.editIntegrationId) { if (widget.id === SessionStorage.editIntegrationId) {
editWidget = widget; editWidget = widget;
} else otherWidgets.push(widget); } else otherWidgets.push(widget);
@ -186,7 +186,7 @@ export class WidgetComponent implements OnInit {
if (!this.wrapperUrl) return url; if (!this.wrapperUrl) return url;
const urls = [this.wrapperUrl].concat(this.scalarWrapperUrls); const urls = [this.wrapperUrl].concat(this.scalarWrapperUrls);
for (let scalarUrl of urls) { for (const scalarUrl of urls) {
if (url.startsWith(scalarUrl)) { if (url.startsWith(scalarUrl)) {
return decodeURIComponent(url.substring(scalarUrl.length)); return decodeURIComponent(url.substring(scalarUrl.length));
} }
@ -263,12 +263,16 @@ export class WidgetComponent implements OnInit {
try { try {
this.OnWidgetBeforeAdd(this.newWidget); this.OnWidgetBeforeAdd(this.newWidget);
} catch (error) { } catch (error) {
this.translate.get(error.message).subscribe((res: string) => {this.toaster.pop("warning", res); }); this.translate.get(error.message).subscribe((res: string) => {
this.toaster.pop("warning", res);
});
return; return;
} }
if (!this.newWidget.dimension.newUrl || this.newWidget.dimension.newUrl.trim().length === 0) { if (!this.newWidget.dimension.newUrl || this.newWidget.dimension.newUrl.trim().length === 0) {
this.translate.get("Please enter a URL for the widget").subscribe((res: string) => {this.toaster.pop("warning", res ); }); this.translate.get("Please enter a URL for the widget").subscribe((res: string) => {
this.toaster.pop("warning", res );
});
return; return;
} }
@ -281,7 +285,9 @@ export class WidgetComponent implements OnInit {
this.isUpdating = false; this.isUpdating = false;
this.OnWidgetAfterAdd(this.newWidget); this.OnWidgetAfterAdd(this.newWidget);
this.prepareNewWidget(); this.prepareNewWidget();
this.translate.get("Widget added!").subscribe((res: string) => {this.toaster.pop("success", res); }); this.translate.get("Widget added!").subscribe((res: string) => {
this.toaster.pop("success", res);
});
}) })
.catch(err => { .catch(err => {
this.isUpdating = false; this.isUpdating = false;
@ -305,7 +311,9 @@ export class WidgetComponent implements OnInit {
} }
if (!widget.dimension.newUrl || widget.dimension.newUrl.trim().length === 0) { if (!widget.dimension.newUrl || widget.dimension.newUrl.trim().length === 0) {
this.translate.get("Please enter a URL for the widget").subscribe((res: string) => {this.toaster.pop("warning", res); }); this.translate.get("Please enter a URL for the widget").subscribe((res: string) => {
this.toaster.pop("warning", res);
});
return; return;
} }
@ -316,7 +324,9 @@ export class WidgetComponent implements OnInit {
.then(() => { .then(() => {
this.isUpdating = false; this.isUpdating = false;
this.OnWidgetAfterEdit(widget); this.OnWidgetAfterEdit(widget);
this.translate.get("Widget updated!").subscribe((res: string) => {this.toaster.pop("success", res); }); this.translate.get("Widget updated!").subscribe((res: string) => {
this.toaster.pop("success", res);
});
}) })
.catch(err => { .catch(err => {
this.isUpdating = false; this.isUpdating = false;
@ -338,7 +348,9 @@ export class WidgetComponent implements OnInit {
.then(() => { .then(() => {
this.isUpdating = false; this.isUpdating = false;
this.OnWidgetAfterDelete(widget); this.OnWidgetAfterDelete(widget);
this.translate.get("Widget deleted!").subscribe((res: string) => {this.toaster.pop("success", res); }); this.translate.get("Widget deleted!").subscribe((res: string) => {
this.toaster.pop("success", res);
});
}) })
.catch(err => { .catch(err => {
this.isUpdating = false; this.isUpdating = false;

View File

@ -47,12 +47,16 @@ export class YoutubeWidgetConfigComponent extends WidgetComponent {
private setVideoUrl(widget: EditableWidget) { private setVideoUrl(widget: EditableWidget) {
if (!widget.dimension.newData.videoUrl || widget.dimension.newData.videoUrl.trim().length === 0) { if (!widget.dimension.newData.videoUrl || widget.dimension.newData.videoUrl.trim().length === 0) {
this.translate.get('Please enter a video URL').subscribe((res: string) => {throw new Error(res); }); this.translate.get('Please enter a video URL').subscribe((res: string) => {
throw new Error(res);
});
} }
const videoUrl = this.getRealVideoUrl(widget.dimension.newData.videoUrl); const videoUrl = this.getRealVideoUrl(widget.dimension.newData.videoUrl);
if (!videoUrl) { if (!videoUrl) {
this.translate.get('Please enter a YouTube, Vimeo, or DailyMotion video URL').subscribe((res: string) => {throw new Error(res); }); this.translate.get('Please enter a YouTube, Vimeo, or DailyMotion video URL').subscribe((res: string) => {
throw new Error(res);
});
} }
widget.dimension.newUrl = videoUrl; widget.dimension.newUrl = videoUrl;

View File

@ -2,22 +2,21 @@ import { Component, OnDestroy, OnInit } from "@angular/core";
import * as screenfull from "screenfull"; import * as screenfull from "screenfull";
@Component({ @Component({
selector: "my-fullscreen-button", selector: "app-fullscreen-button",
templateUrl: "fullscreen-button.component.html", templateUrl: "fullscreen-button.component.html",
styleUrls: ["fullscreen-button.component.scss"], styleUrls: ["fullscreen-button.component.scss"],
}) })
export class FullscreenButtonComponent implements OnDestroy, OnInit { export class FullscreenButtonComponent implements OnDestroy, OnInit {
public isFullscreen = false; public isFullscreen = false;
private listener = null; private listener = null;
constructor() { constructor() {
// Do stuff // Do stuff
} }
public ngOnInit(): void { public ngOnInit(): void {
// @ts-ignore // @ts-ignore
this.listener = screenfull.on("change", () => { this.listener = screenfull.on("change", () => {
// @ts-ignore // @ts-ignore
this.isFullscreen = screenfull.isFullscreen; this.isFullscreen = screenfull.isFullscreen;

View File

@ -2,7 +2,7 @@ import { Component, Input, OnInit } from "@angular/core";
import { ANIMATION_FADE_IN_NOT_OUT } from "../../app.animations"; import { ANIMATION_FADE_IN_NOT_OUT } from "../../app.animations";
@Component({ @Component({
selector: "my-ibox", selector: "app-ibox",
templateUrl: "./ibox.component.html", templateUrl: "./ibox.component.html",
styleUrls: ["./ibox.component.scss"], styleUrls: ["./ibox.component.scss"],
animations: [ANIMATION_FADE_IN_NOT_OUT], animations: [ANIMATION_FADE_IN_NOT_OUT],

View File

@ -1,9 +1,8 @@
import { Component } from "@angular/core"; import { Component } from "@angular/core";
@Component({ @Component({
selector: "my-spinner", selector: "app-spinner",
templateUrl: "./spinner.component.html", templateUrl: "./spinner.component.html",
styleUrls: ["./spinner.component.scss"], styleUrls: ["./spinner.component.scss"],
}) })
export class SpinnerComponent { export class SpinnerComponent {}
}

View File

@ -1,23 +1,22 @@
import { Component } from "@angular/core"; import { Component } from "@angular/core";
@Component({ @Component({
selector: "my-home", selector: "app-home",
templateUrl: "./home.component.html", templateUrl: "./home.component.html",
styleUrls: ["./home.component.scss"], styleUrls: ["./home.component.scss"],
}) })
export class HomeComponent { export class HomeComponent {
public hostname: string = window.location.origin; public hostname: string = window.location.origin;
public showPromoPage = this.hostname === "https://dimension.t2bot.io"; public showPromoPage = this.hostname === "https://dimension.t2bot.io";
public integrationsConfig = `` + public integrationsConfig =
`"integrations_ui_url": "${this.hostname}/element",\n` + `` +
`"integrations_rest_url": "${this.hostname}/api/v1/scalar",\n` + `"integrations_ui_url": "${this.hostname}/element",\n` +
`"integrations_widgets_urls": ["${this.hostname}/widgets"],\n` + `"integrations_rest_url": "${this.hostname}/api/v1/scalar",\n` +
`"integrations_jitsi_widget_url": "${this.hostname}/widgets/jitsi",\n`; `"integrations_widgets_urls": ["${this.hostname}/widgets"],\n` +
`"integrations_jitsi_widget_url": "${this.hostname}/widgets/jitsi",\n`;
constructor() { constructor() {
// Do stuff // Do stuff
} }
} }

View File

@ -1,27 +1,40 @@
import { Component, EventEmitter, Input, OnChanges, Output, SimpleChange, SimpleChanges } from "@angular/core"; import {
Component,
EventEmitter,
Input,
OnChanges,
Output,
SimpleChange,
SimpleChanges,
} from "@angular/core";
import { DomSanitizer, SafeResourceUrl } from "@angular/platform-browser"; import { DomSanitizer, SafeResourceUrl } from "@angular/platform-browser";
import { FE_Integration } from "../shared/models/integration"; import { FE_Integration } from "../shared/models/integration";
import { MediaService } from "../shared/services/media.service"; import { MediaService } from "../shared/services/media.service";
@Component({ @Component({
selector: "my-integration-bag", selector: "app-integration-bag",
templateUrl: "./integration-bag.component.html", templateUrl: "./integration-bag.component.html",
styleUrls: ["./integration-bag.component.scss"], styleUrls: ["./integration-bag.component.scss"],
}) })
export class IntegrationBagComponent implements OnChanges { export class IntegrationBagComponent implements OnChanges {
@Input() integrations: FE_Integration[]; @Input() integrations: FE_Integration[];
@Output() integrationClicked: EventEmitter<FE_Integration> = new EventEmitter<FE_Integration>(); @Output() integrationClicked: EventEmitter<FE_Integration> =
new EventEmitter<FE_Integration>();
constructor(private sanitizer: DomSanitizer, private media: MediaService) { constructor(private sanitizer: DomSanitizer, private media: MediaService) {}
}
public ngOnChanges(changes: SimpleChanges) { public ngOnChanges(changes: SimpleChanges) {
const change: SimpleChange = changes.integrations; const change: SimpleChange = changes.integrations;
(<FE_Integration[]>change.currentValue).map(async (i) => { (<FE_Integration[]>change.currentValue).map(async (i) => {
if (i.avatarUrl.startsWith("mxc://")) { if (i.avatarUrl.startsWith("mxc://")) {
i.avatarUrl = await this.media.getThumbnailUrl(i.avatarUrl, 128, 128, "scale", true); i.avatarUrl = await this.media.getThumbnailUrl(
i.avatarUrl,
128,
128,
"scale",
true
);
} }
}); });
} }

View File

@ -1,37 +1,52 @@
import { Component } from "@angular/core"; import { Component } from "@angular/core";
import { ActivatedRoute, NavigationEnd, PRIMARY_OUTLET, Router } from "@angular/router"; import {
ActivatedRoute,
NavigationEnd,
PRIMARY_OUTLET,
Router,
} from "@angular/router";
import { TranslateService } from "@ngx-translate/core"; import { TranslateService } from "@ngx-translate/core";
import { filter } from "rxjs/operators"; import { filter } from "rxjs/operators";
@Component({ @Component({
selector: "my-page-header", selector: "app-page-header",
templateUrl: "./page-header.component.html", templateUrl: "./page-header.component.html",
styleUrls: ["./page-header.component.scss"], styleUrls: ["./page-header.component.scss"],
}) })
export class PageHeaderComponent { export class PageHeaderComponent {
public pageName: string; public pageName: string;
constructor(private router: Router, private activatedRoute: ActivatedRoute, public translate: TranslateService) { constructor(
private router: Router,
private activatedRoute: ActivatedRoute,
public translate: TranslateService
) {
this.translate = translate; this.translate = translate;
this.router.events.pipe(filter(ev => ev instanceof NavigationEnd)).subscribe((ev) => { this.router.events
let currentRoute = this.activatedRoute.root; .pipe(filter((ev) => ev instanceof NavigationEnd))
let url = ""; .subscribe((ev) => {
const event = ev as NavigationEnd; let currentRoute = this.activatedRoute.root;
let url = "";
const event = ev as NavigationEnd;
while (currentRoute.children.length > 0) { while (currentRoute.children.length > 0) {
const children = currentRoute.children; const children = currentRoute.children;
children.forEach(route => { children.forEach((route) => {
if (route.snapshot.data['breadcrumb']) { if (route.snapshot.data["breadcrumb"]) {
this.translate.get(route.snapshot.data['breadcrumb']).subscribe((res: string) => {route.snapshot.data['breadcrumb'] = res}); this.translate
} .get(route.snapshot.data["breadcrumb"])
currentRoute = route; .subscribe((res: string) => {
url += "/" + route.snapshot.url.map(s => s.path).join("/"); route.snapshot.data["breadcrumb"] = res;
if (route.outlet !== PRIMARY_OUTLET) return; });
if (!route.routeConfig || !route.routeConfig.data) return; }
if (url === event.urlAfterRedirects.split("?")[0]) this.pageName = route.snapshot.data.name; currentRoute = route;
}); url += "/" + route.snapshot.url.map((s) => s.path).join("/");
} if (route.outlet !== PRIMARY_OUTLET) return;
}); if (!route.routeConfig || !route.routeConfig.data) return;
if (url === event.urlAfterRedirects.split("?")[0])
this.pageName = route.snapshot.data.name;
});
}
});
} }
} }

View File

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

View File

@ -2,14 +2,12 @@ import { Component } from "@angular/core";
import { SessionStorage } from "../shared/SessionStorage"; import { SessionStorage } from "../shared/SessionStorage";
@Component({ @Component({
selector: "my-riot", selector: "app-riot",
templateUrl: "./riot.component.html", templateUrl: "./riot.component.html",
styleUrls: ["./riot.component.scss"], styleUrls: ["./riot.component.scss"],
}) })
export class RiotComponent { export class RiotComponent {
constructor() {}
constructor() {
}
public isAdmin(): boolean { public isAdmin(): boolean {
return SessionStorage.isAdmin; return SessionStorage.isAdmin;

View File

@ -2,14 +2,12 @@ import { Component } from "@angular/core";
import { ScalarClientApiService } from "../../shared/services/scalar/scalar-client-api.service"; import { ScalarClientApiService } from "../../shared/services/scalar/scalar-client-api.service";
@Component({ @Component({
selector: "my-scalar-close", selector: "app-scalar-close",
templateUrl: "./scalar-close.component.html", templateUrl: "./scalar-close.component.html",
styleUrls: ["./scalar-close.component.scss"], styleUrls: ["./scalar-close.component.scss"],
}) })
export class ScalarCloseComponent { export class ScalarCloseComponent {
constructor(private scalar: ScalarClientApiService) {}
constructor(private scalar: ScalarClientApiService) {
}
public closeScalar() { public closeScalar() {
console.log("Closing scalar..."); console.log("Closing scalar...");

View File

@ -30,7 +30,9 @@ export class ScreenshotCapableDirective implements OnInit, OnDestroy {
private takeScreenshot(request: ScalarToWidgetRequest) { private takeScreenshot(request: ScalarToWidgetRequest) {
if (this.el.nativeElement.tagName === "IFRAME") { if (this.el.nativeElement.tagName === "IFRAME") {
console.error("Attempted to take a screenshot of an iframe"); console.error("Attempted to take a screenshot of an iframe");
this.translate.get('Failed to take screenshot: iframe not supported').subscribe((res: string) => {ScalarWidgetApi.replyError(request, new Error("Cannot take screenshot of iframe"), res); }); this.translate.get('Failed to take screenshot: iframe not supported').subscribe((res: string) => {
ScalarWidgetApi.replyError(request, new Error("Cannot take screenshot of iframe"), res);
});
} else { } else {
domtoimage.toBlob(this.el.nativeElement).then(b => { domtoimage.toBlob(this.el.nativeElement).then(b => {
if (!b) { if (!b) {
@ -40,7 +42,9 @@ export class ScreenshotCapableDirective implements OnInit, OnDestroy {
ScalarWidgetApi.replyScreenshot(request, b); ScalarWidgetApi.replyScreenshot(request, b);
}).catch(error => { }).catch(error => {
console.error(error); console.error(error);
this.translate.get('Failed to take screenshot').subscribe((res: string) => {ScalarWidgetApi.replyError(request, error, res); }); this.translate.get('Failed to take screenshot').subscribe((res: string) => {
ScalarWidgetApi.replyError(request, error, res);
});
}); });
} }
} }

View File

@ -84,9 +84,9 @@ export interface EditableWidget {
* @return {EditableWidget[]} The Dimension widgets * @return {EditableWidget[]} The Dimension widgets
*/ */
export function convertScalarWidgetsToDtos(scalarResponse: WidgetsResponse): EditableWidget[] { export function convertScalarWidgetsToDtos(scalarResponse: WidgetsResponse): EditableWidget[] {
let widgets = []; const widgets = [];
for (let event of scalarResponse.response) { for (const event of scalarResponse.response) {
widgets.push({ widgets.push({
id: event.state_key, id: event.state_key,
type: event.content.type, type: event.content.type,

View File

@ -18,7 +18,7 @@ export class ScalarClientApiService {
private static actionMap: { [key: string]: { resolve: (obj: any) => void, reject: (obj: any) => void } } = {}; private static actionMap: { [key: string]: { resolve: (obj: any) => void, reject: (obj: any) => void } } = {};
public static getAndRemoveActionHandler(requestKey: string): { resolve: (obj: any) => void, reject: (obj: any) => void } { public static getAndRemoveActionHandler(requestKey: string): { resolve: (obj: any) => void, reject: (obj: any) => void } {
let handler = ScalarClientApiService.actionMap[requestKey]; const handler = ScalarClientApiService.actionMap[requestKey];
ScalarClientApiService.actionMap[requestKey] = null; ScalarClientApiService.actionMap[requestKey] = null;
return handler; return handler;
} }
@ -121,7 +121,7 @@ export class ScalarClientApiService {
} }
private callAction(action, payload): Promise<any> { private callAction(action, payload): Promise<any> {
let requestKey = randomString({length: 20}); const requestKey = randomString({length: 20});
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
if (!window.opener) { if (!window.opener) {
// Mimic an error response from scalar // Mimic an error response from scalar
@ -134,7 +134,7 @@ export class ScalarClientApiService {
reject: reject reject: reject
}; };
let request = JSON.parse(JSON.stringify(payload)); const request = JSON.parse(JSON.stringify(payload));
request["request_id"] = requestKey; request["request_id"] = requestKey;
request["action"] = action; request["action"] = action;
@ -147,10 +147,10 @@ export class ScalarClientApiService {
window.addEventListener("message", event => { window.addEventListener("message", event => {
if (!event.data) return; if (!event.data) return;
let requestKey = event.data["request_id"]; const requestKey = event.data["request_id"];
if (!requestKey) return; if (!requestKey) return;
let action = ScalarClientApiService.getAndRemoveActionHandler(requestKey); const action = ScalarClientApiService.getAndRemoveActionHandler(requestKey);
if (!action) return; if (!action) return;
if (event.data.response && event.data.response.error) action.reject(event.data); if (event.data.response && event.data.response.error) action.reject(event.data);

View File

@ -23,9 +23,9 @@ export class ScalarWidgetApi {
} }
public static replyCapabilities(request: ScalarToWidgetRequest, public static replyCapabilities(request: ScalarToWidgetRequest,
capabilities: ( capabilities: (
"m.text" | "m.image" | "m.sticker" | "m.capability.screenshot" | "m.capability.request_data" | "m.text" | "m.image" | "m.sticker" | "m.capability.screenshot" | "m.capability.request_data" |
"m.capability.request_messages" | "m.capability.room_membership" | string)[] "m.capability.request_messages" | "m.capability.room_membership" | string)[]
): void { ): void {
ScalarWidgetApi.replyEvent(request, {capabilities: capabilities}); ScalarWidgetApi.replyEvent(request, {capabilities: capabilities});
} }
@ -97,7 +97,7 @@ export class ScalarWidgetApi {
return; return;
} }
let request = JSON.parse(JSON.stringify(payload)); const request = JSON.parse(JSON.stringify(payload));
request["api"] = "fromWidget"; request["api"] = "fromWidget";
request["widgetId"] = ScalarWidgetApi.widgetId; request["widgetId"] = ScalarWidgetApi.widgetId;
request["action"] = action; request["action"] = action;
@ -114,7 +114,7 @@ export class ScalarWidgetApi {
return; return;
} }
let requestClone = JSON.parse(JSON.stringify(request)); const requestClone = JSON.parse(JSON.stringify(request));
requestClone["response"] = payload; requestClone["response"] = payload;
console.log("[Dimension] Sending postMessage response: ", request); console.log("[Dimension] Sending postMessage response: ", request);

View File

@ -5,21 +5,25 @@ import { ScalarWidgetApi } from "../../shared/services/scalar/scalar-widget.api"
import { CapableWidget } from "../capable-widget"; import { CapableWidget } from "../capable-widget";
import { DomSanitizer, SafeUrl } from "@angular/platform-browser"; import { DomSanitizer, SafeUrl } from "@angular/platform-browser";
import { BigBlueButtonApiService } from "../../shared/services/integrations/bigbluebutton-api.service"; import { BigBlueButtonApiService } from "../../shared/services/integrations/bigbluebutton-api.service";
import { FE_BigBlueButtonCreateAndJoinMeeting, FE_BigBlueButtonJoin } from "../../shared/models/integration"; import {
FE_BigBlueButtonCreateAndJoinMeeting,
FE_BigBlueButtonJoin,
} from "../../shared/models/integration";
import { TranslateService } from "@ngx-translate/core"; import { TranslateService } from "@ngx-translate/core";
@Component({ @Component({
selector: "my-bigbluebutton-widget-wrapper", selector: "app-bigbluebutton-widget-wrapper",
templateUrl: "bigbluebutton.component.html", templateUrl: "bigbluebutton.component.html",
styleUrls: ["bigbluebutton.component.scss"], styleUrls: ["bigbluebutton.component.scss"],
}) })
export class BigBlueButtonWidgetWrapperComponent extends CapableWidget implements OnInit, OnDestroy { export class BigBlueButtonWidgetWrapperComponent
extends CapableWidget
implements OnInit, OnDestroy {
public canEmbed = true; public canEmbed = true;
/** /**
* User metadata passed to us by the client * User metadata passed to us by the client
*/ */
private conferenceUrl: string; private conferenceUrl: string;
private displayName: string; private displayName: string;
private userId: string; private userId: string;
@ -28,57 +32,59 @@ export class BigBlueButtonWidgetWrapperComponent extends CapableWidget implement
private meetingPassword: string; private meetingPassword: string;
/** /**
* *
* The name to join the BigBlueButton meeting with. Made up of metadata the client passes to us. * The name to join the BigBlueButton meeting with. Made up of metadata the client passes to us.
*/ */
private joinName: string; private joinName: string;
/** /**
* Whether we expect the meeting to be created on command. * Whether we expect the meeting to be created on command.
* *
* True if we'd like the meeting to be created, false if we have a greenlight URL leading to an existing meeting * True if we'd like the meeting to be created, false if we have a greenlight URL leading to an existing meeting
* and would like Dimension to translate that to a BigBlueButton meeting URL. * and would like Dimension to translate that to a BigBlueButton meeting URL.
*/ */
private createMeeting: boolean; private createMeeting: boolean;
/** /**
* The ID of the room, required if createMeeting is true. * The ID of the room, required if createMeeting is true.
*/ */
private roomId: string; private roomId: string;
/** /**
* The poll period in ms while waiting for a meeting to start * The poll period in ms while waiting for a meeting to start
*/ */
private pollIntervalMillis = 5000; private pollIntervalMillis = 5000;
/** /**
* Subscriber for messages from the client via the postMessage API * Subscriber for messages from the client via the postMessage API
*/ */
private bigBlueButtonApiSubscription: Subscription; private bigBlueButtonApiSubscription: Subscription;
/** /**
* A status message to display to the user in the widget, typically for loading messages * A status message to display to the user in the widget, typically for loading messages
*/ */
public statusMessage: string; public statusMessage: string;
/** /**
* Whether we are currently in a meeting * Whether we are currently in a meeting
*/ */
private inMeeting = false; private inMeeting = false;
/** /**
* The URL to embed into the iframe * The URL to embed into the iframe
*/ */
public embedUrl: SafeUrl = null; public embedUrl: SafeUrl = null;
constructor(activatedRoute: ActivatedRoute, constructor(
private bigBlueButtonApi: BigBlueButtonApiService, activatedRoute: ActivatedRoute,
private sanitizer: DomSanitizer, private bigBlueButtonApi: BigBlueButtonApiService,
public translate: TranslateService) { private sanitizer: DomSanitizer,
public translate: TranslateService
) {
super(); super();
this.supportsAlwaysOnScreen = true; this.supportsAlwaysOnScreen = true;
let params: any = activatedRoute.snapshot.queryParams; const params: any = activatedRoute.snapshot.queryParams;
this.roomId = params.roomId; this.roomId = params.roomId;
this.createMeeting = params.createMeeting; this.createMeeting = params.createMeeting;
@ -144,63 +150,85 @@ export class BigBlueButtonWidgetWrapperComponent extends CapableWidget implement
// Ask Dimension to create a meeting (or use an existing one) for this room and return the embeddable meeting URL // Ask Dimension to create a meeting (or use an existing one) for this room and return the embeddable meeting URL
private async joinThroughDimension() { private async joinThroughDimension() {
console.log("BigBlueButton: Joining meeting created by Dimension with meeting ID: " + this.meetingId); console.log(
"BigBlueButton: Joining meeting created by Dimension with meeting ID: " +
this.meetingId
);
this.bigBlueButtonApi.getJoinUrl(this.displayName, this.userId, this.avatarUrl, this.meetingId, this.meetingPassword).then((response) => { this.bigBlueButtonApi
console.log("The response"); .getJoinUrl(
console.log(response); this.displayName,
if ("errorCode" in response) { this.userId,
// This is an instance of ApiError this.avatarUrl,
if (response.errorCode === "UNKNOWN_MEETING_ID") { this.meetingId,
// This meeting ID is invalid. this.meetingPassword
// Inform the user that they should try and start a new meeting )
this.statusMessage = "This meeting has ended or otherwise does not exist.<br>Please start a new meeting."; .then((response) => {
return; console.log("The response");
console.log(response);
if ("errorCode" in response) {
// This is an instance of ApiError
if (response.errorCode === "UNKNOWN_MEETING_ID") {
// This meeting ID is invalid.
// Inform the user that they should try and start a new meeting
this.statusMessage =
"This meeting has ended or otherwise does not exist.<br>Please start a new meeting.";
return;
}
if (response.errorCode === "MEETING_HAS_ENDED") {
// It's likely that everyone has left the meeting, and it's been garbage collected.
// Inform the user that they should try and start a new meeting
this.statusMessage =
"This meeting has ended.<br>Please start a new meeting.";
return;
}
// Otherwise this is a generic error
this.statusMessage = "An error occurred while loading the meeting";
} }
if (response.errorCode === "MEETING_HAS_ENDED") { // Retrieve and embed the meeting URL
// It's likely that everyone has left the meeting, and it's been garbage collected. const joinUrl = (response as FE_BigBlueButtonCreateAndJoinMeeting).url;
// Inform the user that they should try and start a new meeting this.embedMeetingWithUrl(joinUrl);
this.statusMessage = "This meeting has ended.<br>Please start a new meeting."; });
return;
}
// Otherwise this is a generic error
this.statusMessage = "An error occurred while loading the meeting";
}
// Retrieve and embed the meeting URL
const joinUrl = (response as FE_BigBlueButtonCreateAndJoinMeeting).url;
this.embedMeetingWithUrl(joinUrl);
});
} }
// Hand Dimension a Greenlight URL and receive a translated, embeddable meeting URL in response // Hand Dimension a Greenlight URL and receive a translated, embeddable meeting URL in response
private joinThroughGreenlightUrl() { private joinThroughGreenlightUrl() {
console.log("BigBlueButton: joining via greenlight url:", this.conferenceUrl); console.log(
this.bigBlueButtonApi.joinMeetingWithGreenlightUrl(this.conferenceUrl, this.joinName).then((response) => { "BigBlueButton: joining via greenlight url:",
if ("errorCode" in response) { this.conferenceUrl
// This is an instance of ApiError );
if (response.errorCode === "WAITING_FOR_MEETING_START") { this.bigBlueButtonApi
// The meeting hasn't started yet .joinMeetingWithGreenlightUrl(this.conferenceUrl, this.joinName)
this.statusMessage = "Waiting for conference to start..."; .then((response) => {
if ("errorCode" in response) {
// This is an instance of ApiError
if (response.errorCode === "WAITING_FOR_MEETING_START") {
// The meeting hasn't started yet
this.statusMessage = "Waiting for conference to start...";
// Poll until it has // Poll until it has
setTimeout(this.joinConference.bind(this), this.pollIntervalMillis, false); setTimeout(
return; this.joinConference.bind(this),
this.pollIntervalMillis,
false
);
return;
}
// Otherwise this is a generic error
this.statusMessage = "An error occurred while loading the meeting";
} }
// Otherwise this is a generic error // Retrieve and embed the meeting URL
this.statusMessage = "An error occurred while loading the meeting"; const joinUrl = (response as FE_BigBlueButtonJoin).url;
} this.embedMeetingWithUrl(joinUrl);
});
// Retrieve and embed the meeting URL
const joinUrl = (response as FE_BigBlueButtonJoin).url;
this.embedMeetingWithUrl(joinUrl);
});
} }
private embedMeetingWithUrl(url: string) { private embedMeetingWithUrl(url: string) {
// Hide widget-related UI // Hide widget-related UI
this.statusMessage = null; this.statusMessage = null;
// Embed the return meeting URL, joining the meeting // Embed the return meeting URL, joining the meeting
@ -212,7 +240,8 @@ export class BigBlueButtonWidgetWrapperComponent extends CapableWidget implement
} }
public ngOnDestroy() { public ngOnDestroy() {
if (this.bigBlueButtonApiSubscription) this.bigBlueButtonApiSubscription.unsubscribe(); if (this.bigBlueButtonApiSubscription)
this.bigBlueButtonApiSubscription.unsubscribe();
} }
protected onCapabilitiesSent(): void { protected onCapabilitiesSent(): void {
@ -221,5 +250,4 @@ export class BigBlueButtonWidgetWrapperComponent extends CapableWidget implement
// Don't set alwaysOnScreen until we start a meeting // Don't set alwaysOnScreen until we start a meeting
ScalarWidgetApi.sendSetAlwaysOnScreen(false); ScalarWidgetApi.sendSetAlwaysOnScreen(false);
} }
} }

View File

@ -3,17 +3,17 @@ import { ActivatedRoute } from "@angular/router";
import { DomSanitizer, SafeUrl } from "@angular/platform-browser"; import { DomSanitizer, SafeUrl } from "@angular/platform-browser";
@Component({ @Component({
selector: "my-gcal-widget-wrapper", selector: "app-gcal-widget-wrapper",
templateUrl: "../fullpage-iframe/fullpage-iframe.component.html", templateUrl: "../fullpage-iframe/fullpage-iframe.component.html",
styleUrls: ["../fullpage-iframe/fullpage-iframe.component.scss"], styleUrls: ["../fullpage-iframe/fullpage-iframe.component.scss"],
}) })
export class GCalWidgetWrapperComponent { export class GCalWidgetWrapperComponent {
public embedUrl: SafeUrl = null; public embedUrl: SafeUrl = null;
constructor(activatedRoute: ActivatedRoute, sanitizer: DomSanitizer) { constructor(activatedRoute: ActivatedRoute, sanitizer: DomSanitizer) {
let params: any = activatedRoute.snapshot.queryParams; const params: any = activatedRoute.snapshot.queryParams;
const embedUrl = "https://calendar.google.com/calendar/embed?src=" + params.calendarId; const embedUrl =
"https://calendar.google.com/calendar/embed?src=" + params.calendarId;
this.embedUrl = sanitizer.bypassSecurityTrustResourceUrl(embedUrl); this.embedUrl = sanitizer.bypassSecurityTrustResourceUrl(embedUrl);
} }
} }

View File

@ -3,16 +3,15 @@ import { ActivatedRoute } from "@angular/router";
import { DomSanitizer, SafeUrl } from "@angular/platform-browser"; import { DomSanitizer, SafeUrl } from "@angular/platform-browser";
@Component({ @Component({
selector: "my-generic-fullscreen-widget-wrapper", selector: "app-generic-fullscreen-widget-wrapper",
templateUrl: "../fullpage-iframe/fullpage-iframe.component.html", templateUrl: "../fullpage-iframe/fullpage-iframe.component.html",
styleUrls: ["../fullpage-iframe/fullpage-iframe.component.scss"], styleUrls: ["../fullpage-iframe/fullpage-iframe.component.scss"],
}) })
export class GenericFullscreenWidgetWrapperComponent { export class GenericFullscreenWidgetWrapperComponent {
public embedUrl: SafeUrl = null; public embedUrl: SafeUrl = null;
constructor(activatedRoute: ActivatedRoute, sanitizer: DomSanitizer) { constructor(activatedRoute: ActivatedRoute, sanitizer: DomSanitizer) {
let params: any = activatedRoute.snapshot.queryParams; const params: any = activatedRoute.snapshot.queryParams;
// Note: we don't do an embeddable check (as we would in a generic wrapper) // Note: we don't do an embeddable check (as we would in a generic wrapper)
// because the Grafana dashboard might be private. // because the Grafana dashboard might be private.
this.embedUrl = sanitizer.bypassSecurityTrustResourceUrl(params.url); this.embedUrl = sanitizer.bypassSecurityTrustResourceUrl(params.url);

View File

@ -4,27 +4,33 @@ import { DomSanitizer, SafeUrl } from "@angular/platform-browser";
import { WidgetApiService } from "../../shared/services/integrations/widget-api.service"; import { WidgetApiService } from "../../shared/services/integrations/widget-api.service";
@Component({ @Component({
selector: "my-generic-widget-wrapper", selector: "app-generic-widget-wrapper",
templateUrl: "generic.component.html", templateUrl: "generic.component.html",
styleUrls: ["generic.component.scss"], styleUrls: ["generic.component.scss"],
}) })
export class GenericWidgetWrapperComponent { export class GenericWidgetWrapperComponent {
public isLoading = true; public isLoading = true;
public canEmbed = false; public canEmbed = false;
public embedUrl: SafeUrl = null; public embedUrl: SafeUrl = null;
constructor(widgetApi: WidgetApiService, activatedRoute: ActivatedRoute, sanitizer: DomSanitizer) { constructor(
let params: any = activatedRoute.snapshot.queryParams; widgetApi: WidgetApiService,
activatedRoute: ActivatedRoute,
sanitizer: DomSanitizer
) {
const params: any = activatedRoute.snapshot.queryParams;
widgetApi.isEmbeddable(params.url).then(result => { widgetApi
this.canEmbed = result.canEmbed; .isEmbeddable(params.url)
this.isLoading = false; .then((result) => {
this.embedUrl = sanitizer.bypassSecurityTrustResourceUrl(params.url); this.canEmbed = result.canEmbed;
}).catch(err => { this.isLoading = false;
console.error(err); this.embedUrl = sanitizer.bypassSecurityTrustResourceUrl(params.url);
this.canEmbed = false; })
this.isLoading = false; .catch((err) => {
}); console.error(err);
this.canEmbed = false;
this.isLoading = false;
});
} }
} }

View File

@ -7,15 +7,16 @@ import { Subscription } from "rxjs/Subscription";
import { ScalarWidgetApi } from "../../shared/services/scalar/scalar-widget.api"; import { ScalarWidgetApi } from "../../shared/services/scalar/scalar-widget.api";
import { CapableWidget } from "../capable-widget"; import { CapableWidget } from "../capable-widget";
declare var JitsiMeetExternalAPI: any; declare let JitsiMeetExternalAPI: any;
@Component({ @Component({
selector: "my-jitsi-widget-wrapper", selector: "app-jitsi-widget-wrapper",
templateUrl: "jitsi.component.html", templateUrl: "jitsi.component.html",
styleUrls: ["jitsi.component.scss"], styleUrls: ["jitsi.component.scss"],
}) })
export class JitsiWidgetWrapperComponent extends CapableWidget implements OnInit, OnDestroy { export class JitsiWidgetWrapperComponent
extends CapableWidget
implements OnInit, OnDestroy {
public isJoined = false; public isJoined = false;
public toggleVideo = false; public toggleVideo = false;
@ -28,18 +29,21 @@ export class JitsiWidgetWrapperComponent extends CapableWidget implements OnInit
private jitsiApiObj: any; private jitsiApiObj: any;
private jitsiApiSubscription: Subscription; private jitsiApiSubscription: Subscription;
constructor(activatedRoute: ActivatedRoute, private widgetApi: WidgetApiService) { constructor(
activatedRoute: ActivatedRoute,
private widgetApi: WidgetApiService
) {
super(); super();
this.supportsAlwaysOnScreen = true; this.supportsAlwaysOnScreen = true;
let params: any = activatedRoute.snapshot.queryParams; const params: any = activatedRoute.snapshot.queryParams;
this.domain = params.domain; this.domain = params.domain;
this.conferenceId = params.conferenceId || params.confId; this.conferenceId = params.conferenceId || params.confId;
this.displayName = params.displayName; this.displayName = params.displayName;
this.avatarUrl = params.avatarUrl; this.avatarUrl = params.avatarUrl;
this.userId = params.userId || params.email; // Element uses `email` when placing a conference call this.userId = params.userId || params.email; // Element uses `email` when placing a conference call
this.isAudioOnly = params.isAudioOnly === 'true'; this.isAudioOnly = params.isAudioOnly === "true";
this.toggleVideo = !this.isAudioOnly; this.toggleVideo = !this.isAudioOnly;
// Set the widget ID if we have it // Set the widget ID if we have it
@ -48,47 +52,51 @@ export class JitsiWidgetWrapperComponent extends CapableWidget implements OnInit
public ngOnInit() { public ngOnInit() {
super.ngOnInit(); super.ngOnInit();
this.widgetApi.getWidget("jitsi").then(integration => { this.widgetApi.getWidget("jitsi").then((integration) => {
const widget = <FE_JitsiWidget>integration; const widget = <FE_JitsiWidget>integration;
$.getScript(widget.options.scriptUrl); $.getScript(widget.options.scriptUrl);
if (!this.domain) { if (!this.domain) {
// Always fall back to jitsi.riot.im to maintain compatibility with widgets created by Element. // Always fall back to jitsi.riot.im to maintain compatibility with widgets created by Element.
this.domain = widget.options.useDomainAsDefault ? widget.options.jitsiDomain : "jitsi.riot.im"; this.domain = widget.options.useDomainAsDefault
? widget.options.jitsiDomain
: "jitsi.riot.im";
} }
}); });
this.jitsiApiSubscription = ScalarWidgetApi.requestReceived.subscribe(request => { this.jitsiApiSubscription = ScalarWidgetApi.requestReceived.subscribe(
if (!this.isJoined) { (request) => {
return; if (!this.isJoined) {
}
switch (request.action) {
case "audioToggle":
this.jitsiApiObj.executeCommand('toggleAudio');
break;
case "audioMute":
this.jitsiApiObj.isAudioMuted().then((muted) => {
// Toggle audio if Jitsi is not currently muted
if (!muted) {
this.jitsiApiObj.executeCommand('toggleAudio');
}
});
break;
case "audioUnmute":
this.jitsiApiObj.isAudioMuted().then((muted) => {
// Toggle audio if Jitsi is currently muted
if (muted) {
this.jitsiApiObj.executeCommand('toggleAudio');
}
});
break;
default:
// Unknown command sent
return; return;
} }
ScalarWidgetApi.replyAcknowledge(request); switch (request.action) {
}); case "audioToggle":
this.jitsiApiObj.executeCommand("toggleAudio");
break;
case "audioMute":
this.jitsiApiObj.isAudioMuted().then((muted) => {
// Toggle audio if Jitsi is not currently muted
if (!muted) {
this.jitsiApiObj.executeCommand("toggleAudio");
}
});
break;
case "audioUnmute":
this.jitsiApiObj.isAudioMuted().then((muted) => {
// Toggle audio if Jitsi is currently muted
if (muted) {
this.jitsiApiObj.executeCommand("toggleAudio");
}
});
break;
default:
// Unknown command sent
return;
}
ScalarWidgetApi.replyAcknowledge(request);
}
);
} }
public joinConference() { public joinConference() {
@ -107,12 +115,15 @@ export class JitsiWidgetWrapperComponent extends CapableWidget implements OnInit
SHOW_WATERMARK_FOR_GUESTS: false, SHOW_WATERMARK_FOR_GUESTS: false,
MAIN_TOOLBAR_BUTTONS: [], MAIN_TOOLBAR_BUTTONS: [],
VIDEO_LAYOUT_FIT: "height", VIDEO_LAYOUT_FIT: "height",
} },
}); });
if (this.displayName) this.jitsiApiObj.executeCommand("displayName", this.displayName); if (this.displayName)
if (this.avatarUrl) this.jitsiApiObj.executeCommand("avatarUrl", this.avatarUrl.toString()); this.jitsiApiObj.executeCommand("displayName", this.displayName);
if (this.avatarUrl)
this.jitsiApiObj.executeCommand("avatarUrl", this.avatarUrl.toString());
if (this.userId) this.jitsiApiObj.executeCommand("email", this.userId); if (this.userId) this.jitsiApiObj.executeCommand("email", this.userId);
if (this.isAudioOnly === this.toggleVideo) this.jitsiApiObj.executeCommand("toggleVideo"); if (this.isAudioOnly === this.toggleVideo)
this.jitsiApiObj.executeCommand("toggleVideo");
this.jitsiApiObj.on("readyToClose", () => { this.jitsiApiObj.on("readyToClose", () => {
this.isJoined = false; this.isJoined = false;
@ -132,5 +143,4 @@ export class JitsiWidgetWrapperComponent extends CapableWidget implements OnInit
super.onCapabilitiesSent(); super.onCapabilitiesSent();
ScalarWidgetApi.sendSetAlwaysOnScreen(false); ScalarWidgetApi.sendSetAlwaysOnScreen(false);
} }
} }

View File

@ -6,15 +6,16 @@ import { ScalarServerApiService } from "../../shared/services/scalar/scalar-serv
import { TranslateService } from "@ngx-translate/core"; import { TranslateService } from "@ngx-translate/core";
@Component({ @Component({
selector: "my-reauth-example-widget-wrapper", selector: "app-reauth-example-widget-wrapper",
templateUrl: "manager-test.component.html", templateUrl: "manager-test.component.html",
styleUrls: ["manager-test.component.scss"], styleUrls: ["manager-test.component.scss"],
}) })
export class ManagerTestWidgetWrapperComponent extends CapableWidget implements OnInit, OnDestroy { export class ManagerTestWidgetWrapperComponent
extends CapableWidget
public readonly STATE_NEUTRAL = 'neutral'; implements OnInit, OnDestroy {
public readonly STATE_OK = 'ok'; public readonly STATE_NEUTRAL = "neutral";
public readonly STATE_ERROR = 'error'; public readonly STATE_OK = "ok";
public readonly STATE_ERROR = "error";
public isBusy = true; public isBusy = true;
public isSupported = true; public isSupported = true;
@ -23,22 +24,30 @@ export class ManagerTestWidgetWrapperComponent extends CapableWidget implements
public homeserverState = this.STATE_NEUTRAL; public homeserverState = this.STATE_NEUTRAL;
public message: string; public message: string;
constructor(activatedRoute: ActivatedRoute, constructor(
private scalarApi: ScalarServerApiService, activatedRoute: ActivatedRoute,
private changeDetector: ChangeDetectorRef, private scalarApi: ScalarServerApiService,
public translate: TranslateService) { private changeDetector: ChangeDetectorRef,
public translate: TranslateService
) {
super(); super();
this.translate = translate; this.translate = translate;
this.translate.get('Click the button to test your connection. This may cause your client to ask if it is okay to share your identity with the widget - this is required to test your connection to your homeserver.').subscribe((res: string) => {this.message = res}); this.translate
.get(
"Click the button to test your connection. This may cause your client to ask if it is okay to share your identity with the widget - this is required to test your connection to your homeserver."
)
.subscribe((res: string) => {
this.message = res;
});
const params: any = activatedRoute.snapshot.queryParams; const params: any = activatedRoute.snapshot.queryParams;
ScalarWidgetApi.widgetId = params.widgetId; ScalarWidgetApi.widgetId = params.widgetId;
} }
protected onSupportedVersionsFound(): void { protected onSupportedVersionsFound(): void {
super.onSupportedVersionsFound(); super.onSupportedVersionsFound();
this.isSupported = this.doesSupportAtLeastVersion(WIDGET_API_VERSION_OPENID); this.isSupported = this.doesSupportAtLeastVersion(
WIDGET_API_VERSION_OPENID
);
this.isBusy = false; this.isBusy = false;
if (!this.isSupported) { if (!this.isSupported) {
this.selfState = this.STATE_ERROR; this.selfState = this.STATE_ERROR;
@ -50,41 +59,73 @@ export class ManagerTestWidgetWrapperComponent extends CapableWidget implements
this.selfState = this.STATE_NEUTRAL; this.selfState = this.STATE_NEUTRAL;
this.managerState = this.STATE_NEUTRAL; this.managerState = this.STATE_NEUTRAL;
this.homeserverState = this.STATE_NEUTRAL; this.homeserverState = this.STATE_NEUTRAL;
this.translate.get('Please accept the prompt to verify your identity.').subscribe((res: string) => {this.message = res}); this.translate
.get("Please accept the prompt to verify your identity.")
.subscribe((res: string) => {
this.message = res;
});
this.isBusy = true; this.isBusy = true;
const response = await this.getOpenIdInfo(); const response = await this.getOpenIdInfo();
if (response.blocked) { if (response.blocked) {
this.isBusy = false; this.isBusy = false;
this.selfState = this.STATE_ERROR; this.selfState = this.STATE_ERROR;
this.translate.get('You have blocked this widget from verifying your identity.').subscribe((res: string) => {this.message = res}); this.translate
.get("You have blocked this widget from verifying your identity.")
.subscribe((res: string) => {
this.message = res;
});
return; return;
} }
this.selfState = this.STATE_OK; this.selfState = this.STATE_OK;
this.translate.get('Checking connectivity to integration manager...').subscribe((res: string) => {this.message = res}); this.translate
.get("Checking connectivity to integration manager...")
.subscribe((res: string) => {
this.message = res;
});
try { try {
await this.scalarApi.ping(); await this.scalarApi.ping();
this.managerState = this.STATE_OK; this.managerState = this.STATE_OK;
this.translate.get('Checking connectivity to homeserver...').subscribe((res: string) => {this.message = res}); this.translate
.get("Checking connectivity to homeserver...")
.subscribe((res: string) => {
this.message = res;
});
} catch (e) { } catch (e) {
console.error(e); console.error(e);
this.isBusy = false; this.isBusy = false;
this.managerState = this.STATE_ERROR; this.managerState = this.STATE_ERROR;
this.translate.get('Error checking if the integration manager is alive. This usually means that the manager which served this widget has gone offline.').subscribe((res: string) => {this.message = res}); this.translate
.get(
"Error checking if the integration manager is alive. This usually means that the manager which served this widget has gone offline."
)
.subscribe((res: string) => {
this.message = res;
});
return; return;
} }
try { try {
await this.scalarApi.register(response.openId); await this.scalarApi.register(response.openId);
this.homeserverState = this.STATE_OK; this.homeserverState = this.STATE_OK;
this.translate.get('You\'re all set! Click the button below to re-run the test.').subscribe((res: string) => {this.message = res}); this.translate
.get("You're all set! Click the button below to re-run the test.")
.subscribe((res: string) => {
this.message = res;
});
this.isBusy = false; this.isBusy = false;
} catch (e) { } catch (e) {
this.isBusy = false; this.isBusy = false;
this.homeserverState = this.STATE_ERROR; this.homeserverState = this.STATE_ERROR;
this.translate.get('Error contacting homeserver. This usually means your federation setup is incorrect, or your homeserver is offline. Consult your homeserver\'s documentation for how to set up federation.').subscribe((res: string) => {this.message = res}); this.translate
.get(
"Error contacting homeserver. This usually means your federation setup is incorrect, or your homeserver is offline. Consult your homeserver's documentation for how to set up federation."
)
.subscribe((res: string) => {
this.message = res;
});
} }
} }
} }

View File

@ -8,12 +8,13 @@ import { FE_ScalarOpenIdRequestBody } from "../../shared/models/scalar-server-re
import { TranslateService } from "@ngx-translate/core"; import { TranslateService } from "@ngx-translate/core";
@Component({ @Component({
selector: "my-reauth-example-widget-wrapper", selector: "app-reauth-example-widget-wrapper",
templateUrl: "reauth-example.component.html", templateUrl: "reauth-example.component.html",
styleUrls: ["reauth-example.component.scss"], styleUrls: ["reauth-example.component.scss"],
}) })
export class ReauthExampleWidgetWrapperComponent extends CapableWidget implements OnInit, OnDestroy { export class ReauthExampleWidgetWrapperComponent
extends CapableWidget
implements OnInit, OnDestroy {
public busy = true; // busy until we load supported versions public busy = true; // busy until we load supported versions
public hasOpenId = false; public hasOpenId = false;
public userId: string; public userId: string;
@ -21,13 +22,19 @@ export class ReauthExampleWidgetWrapperComponent extends CapableWidget implement
public error = false; public error = false;
public stateMessage: string; public stateMessage: string;
constructor(activatedRoute: ActivatedRoute, constructor(
private scalarApi: ScalarServerApiService, activatedRoute: ActivatedRoute,
private changeDetector: ChangeDetectorRef, private scalarApi: ScalarServerApiService,
public translate: TranslateService) { private changeDetector: ChangeDetectorRef,
public translate: TranslateService
) {
super(); super();
this.translate = translate; this.translate = translate;
this.translate.get('Checking client version...').subscribe((res: string) => {this.stateMessage = res}); this.translate
.get("Checking client version...")
.subscribe((res: string) => {
this.stateMessage = res;
});
const params: any = activatedRoute.snapshot.queryParams; const params: any = activatedRoute.snapshot.queryParams;
ScalarWidgetApi.widgetId = params.widgetId; ScalarWidgetApi.widgetId = params.widgetId;
@ -44,7 +51,11 @@ export class ReauthExampleWidgetWrapperComponent extends CapableWidget implement
this.error = true; this.error = true;
this.hasOpenId = false; this.hasOpenId = false;
this.blocked = false; this.blocked = false;
this.translate.get('Your client is too old to use this widget, sorry').subscribe((res: string) => {this.stateMessage = res}); this.translate
.get("Your client is too old to use this widget, sorry")
.subscribe((res: string) => {
this.stateMessage = res;
});
} else { } else {
this.busy = false; this.busy = false;
this.error = false; this.error = false;
@ -60,7 +71,11 @@ export class ReauthExampleWidgetWrapperComponent extends CapableWidget implement
this.error = false; this.error = false;
this.blocked = false; this.blocked = false;
this.hasOpenId = false; this.hasOpenId = false;
this.translate.get('Please accept the prompt to verify your identity').subscribe((res: string) => {this.stateMessage = res}); this.translate
.get("Please accept the prompt to verify your identity")
.subscribe((res: string) => {
this.stateMessage = res;
});
const response = await this.getOpenIdInfo(); const response = await this.getOpenIdInfo();
if (response.blocked) { if (response.blocked) {

View File

@ -4,19 +4,17 @@ import * as spotifyUri from "spotify-uri";
import { DomSanitizer, SafeUrl } from "@angular/platform-browser"; import { DomSanitizer, SafeUrl } from "@angular/platform-browser";
@Component({ @Component({
selector: "my-spotify-widget-wrapper", selector: "app-spotify-widget-wrapper",
templateUrl: "../fullpage-iframe/fullpage-iframe.component.html", templateUrl: "../fullpage-iframe/fullpage-iframe.component.html",
styleUrls: ["../fullpage-iframe/fullpage-iframe.component.scss"], styleUrls: ["../fullpage-iframe/fullpage-iframe.component.scss"],
}) })
export class SpotifyWidgetWrapperComponent { export class SpotifyWidgetWrapperComponent {
public embedUrl: SafeUrl = null; public embedUrl: SafeUrl = null;
constructor(activatedRoute: ActivatedRoute, sanitizer: DomSanitizer) { constructor(activatedRoute: ActivatedRoute, sanitizer: DomSanitizer) {
let params: any = activatedRoute.snapshot.queryParams; const params: any = activatedRoute.snapshot.queryParams;
const spotifyUrl = spotifyUri.parse(params.uri); const spotifyUrl = spotifyUri.parse(params.uri);
const spotifyEmbedUrl = spotifyUri.formatEmbedURL(spotifyUrl); const spotifyEmbedUrl = spotifyUri.formatEmbedURL(spotifyUrl);
this.embedUrl = sanitizer.bypassSecurityTrustResourceUrl(spotifyEmbedUrl); this.embedUrl = sanitizer.bypassSecurityTrustResourceUrl(spotifyEmbedUrl);
} }
} }

View File

@ -3,50 +3,53 @@ import {
state, state,
style, style,
transition, transition,
trigger trigger,
} from '@angular/animations'; } from "@angular/animations";
import { AfterViewInit, ChangeDetectorRef, Component, OnDestroy, OnInit } from "@angular/core"; import {
AfterViewInit,
ChangeDetectorRef,
Component,
OnDestroy,
OnInit,
} from "@angular/core";
import { ActivatedRoute } from "@angular/router"; import { ActivatedRoute } from "@angular/router";
import { CapableWidget, WIDGET_API_VERSION_OPENID } from "../capable-widget"; import { CapableWidget, WIDGET_API_VERSION_OPENID } from "../capable-widget";
import { fromEvent } from 'rxjs'; import { fromEvent } from "rxjs";
import { import {
distinctUntilChanged, distinctUntilChanged,
filter, filter,
map, map,
pairwise, pairwise,
share, share,
throttleTime throttleTime,
} from 'rxjs/operators'; } from "rxjs/operators";
import { Subscription } from "rxjs/Subscription"; import { Subscription } from "rxjs/Subscription";
import { ScalarWidgetApi } from "../../shared/services/scalar/scalar-widget.api"; import { ScalarWidgetApi } from "../../shared/services/scalar/scalar-widget.api";
import { StickerApiService } from "../../shared/services/integrations/sticker-api.service"; import { StickerApiService } from "../../shared/services/integrations/sticker-api.service";
import { SessionStorage } from "../../shared/SessionStorage"; import { SessionStorage } from "../../shared/SessionStorage";
import { ScalarServerApiService } from "../../shared/services/scalar/scalar-server-api.service"; import { ScalarServerApiService } from "../../shared/services/scalar/scalar-server-api.service";
import { FE_Sticker, FE_UserStickerPack } from "../../shared/models/integration"; import {
FE_Sticker,
FE_UserStickerPack,
} from "../../shared/models/integration";
import { MediaService } from "../../shared/services/media.service"; import { MediaService } from "../../shared/services/media.service";
import { WIDGET_STICKER_PICKER } from "../../shared/models/widget"; import { WIDGET_STICKER_PICKER } from "../../shared/models/widget";
@Component({ @Component({
selector: "my-generic-widget-wrapper", selector: "app-generic-widget-wrapper",
templateUrl: "sticker-picker.component.html", templateUrl: "sticker-picker.component.html",
styleUrls: ["sticker-picker.component.scss"], styleUrls: ["sticker-picker.component.scss"],
animations: [ animations: [
trigger('hideList', [ trigger("hideList", [
state( state("hidden", style({ opacity: 0, transform: "translateY(100%)" })),
'hidden', state("visible", style({ opacity: 1, transform: "translateY(0)" })),
style({ opacity: 0, transform: 'translateY(100%)' }) transition("* => *", animate("200ms ease-in")),
), ]),
state( ],
'visible',
style({ opacity: 1, transform: 'translateY(0)' })
),
transition('* => *', animate('200ms ease-in'))
])
]
}) })
export class StickerPickerWidgetWrapperComponent
export class StickerPickerWidgetWrapperComponent extends CapableWidget implements OnInit, OnDestroy, AfterViewInit { extends CapableWidget
implements OnInit, OnDestroy, AfterViewInit {
public isLoading = true; public isLoading = true;
public isListVisible = true; public isListVisible = true;
public authError = false; public authError = false;
@ -54,15 +57,17 @@ export class StickerPickerWidgetWrapperComponent extends CapableWidget implement
private stickerWidgetApiSubscription: Subscription; private stickerWidgetApiSubscription: Subscription;
constructor(activatedRoute: ActivatedRoute, constructor(
private media: MediaService, activatedRoute: ActivatedRoute,
private scalarApi: ScalarServerApiService, private media: MediaService,
private stickerApi: StickerApiService, private scalarApi: ScalarServerApiService,
private changeDetector: ChangeDetectorRef) { private stickerApi: StickerApiService,
private changeDetector: ChangeDetectorRef
) {
super(); super();
this.supportsStickers = true; this.supportsStickers = true;
let params: any = activatedRoute.snapshot.queryParams; const params: any = activatedRoute.snapshot.queryParams;
let token = params.scalar_token; let token = params.scalar_token;
if (!token) token = localStorage.getItem("dim-scalar-token"); if (!token) token = localStorage.getItem("dim-scalar-token");
@ -85,50 +90,53 @@ export class StickerPickerWidgetWrapperComponent extends CapableWidget implement
public ngOnInit() { public ngOnInit() {
super.ngOnInit(); super.ngOnInit();
this.stickerWidgetApiSubscription = ScalarWidgetApi.requestReceived.subscribe(request => { this.stickerWidgetApiSubscription =
if (request.action === "visibility") { ScalarWidgetApi.requestReceived.subscribe((request) => {
if ((<any>request).visible) this.loadStickers(); if (request.action === "visibility") {
ScalarWidgetApi.replyAcknowledge(request); if ((<any>request).visible) this.loadStickers();
} ScalarWidgetApi.replyAcknowledge(request);
}); }
});
this.loadStickers(); this.loadStickers();
} }
public ngOnDestroy() { public ngOnDestroy() {
super.ngOnDestroy(); super.ngOnDestroy();
if (this.stickerWidgetApiSubscription) this.stickerWidgetApiSubscription.unsubscribe(); if (this.stickerWidgetApiSubscription)
this.stickerWidgetApiSubscription.unsubscribe();
} }
public ngAfterViewInit() { public ngAfterViewInit() {
const scroll$ = fromEvent(window, 'scroll').pipe( const scroll$ = fromEvent(window, "scroll").pipe(
throttleTime(10), throttleTime(10),
map(() => window.pageYOffset), map(() => window.pageYOffset),
pairwise(), pairwise(),
map(([y1, y2]): string => (y2 < y1 ? 'up' : 'down')), map(([y1, y2]): string => (y2 < y1 ? "up" : "down")),
distinctUntilChanged(), distinctUntilChanged(),
share() share()
); );
const scrollUp$ = scroll$.pipe( const scrollUp$ = scroll$.pipe(filter((direction) => direction === "up"));
filter(direction => direction === 'up')
);
const scrollDown = scroll$.pipe( const scrollDown = scroll$.pipe(
filter(direction => direction === 'down') filter((direction) => direction === "down")
); );
scrollUp$.subscribe(() => (this.isListVisible = true)); scrollUp$.subscribe(() => (this.isListVisible = true));
scrollDown.subscribe(() => (this.isListVisible = false)); scrollDown.subscribe(() => (this.isListVisible = false));
} }
protected onSupportedVersionsFound(): void { protected onSupportedVersionsFound(): void {
super.onSupportedVersionsFound(); super.onSupportedVersionsFound();
if (this.authError && this.doesSupportAtLeastVersion(WIDGET_API_VERSION_OPENID)) { if (
this.authError &&
this.doesSupportAtLeastVersion(WIDGET_API_VERSION_OPENID)
) {
this.isLoading = true; this.isLoading = true;
this.changeDetector.detectChanges(); this.changeDetector.detectChanges();
this.getOpenIdInfo().then(async response => { this.getOpenIdInfo().then(async (response) => {
if (response.blocked) { if (response.blocked) {
this.isLoading = false; this.isLoading = false;
this.authError = true; this.authError = true;
@ -137,8 +145,13 @@ export class StickerPickerWidgetWrapperComponent extends CapableWidget implement
} }
try { try {
const registerResponse = await this.scalarApi.register(response.openId); const registerResponse = await this.scalarApi.register(
localStorage.setItem("dim-scalar-token", registerResponse.scalar_token); response.openId
);
localStorage.setItem(
"dim-scalar-token",
registerResponse.scalar_token
);
SessionStorage.scalarToken = registerResponse.scalar_token; SessionStorage.scalarToken = registerResponse.scalar_token;
this.authError = !SessionStorage.scalarToken; this.authError = !SessionStorage.scalarToken;
this.isLoading = false; this.isLoading = false;
@ -154,7 +167,12 @@ export class StickerPickerWidgetWrapperComponent extends CapableWidget implement
} }
} }
public getThumbnailUrl(mxc: string, width: number, height: number, method: "crop" | "scale" = "scale"): string { public getThumbnailUrl(
mxc: string,
width: number,
height: number,
method: "crop" | "scale" = "scale"
): string {
return this.media.getThumbnailUrl(mxc, width, height, method, true); return this.media.getThumbnailUrl(mxc, width, height, method, true);
} }
@ -165,7 +183,9 @@ export class StickerPickerWidgetWrapperComponent extends CapableWidget implement
try { try {
const info = await this.scalarApi.getAccount(); const info = await this.scalarApi.getAccount();
SessionStorage.userId = info.user_id; SessionStorage.userId = info.user_id;
console.log("Dimension scalar_token belongs to " + SessionStorage.userId); console.log(
"Dimension scalar_token belongs to " + SessionStorage.userId
);
} catch (e) { } catch (e) {
console.error(e); console.error(e);
this.authError = true; this.authError = true;
@ -177,8 +197,14 @@ export class StickerPickerWidgetWrapperComponent extends CapableWidget implement
console.log("Attempting to load available stickers..."); console.log("Attempting to load available stickers...");
try { try {
const packs = await this.stickerApi.getPacks(); const packs = await this.stickerApi.getPacks();
this.packs = packs.filter(p => p.isSelected); this.packs = packs.filter((p) => p.isSelected);
console.log("User has " + this.packs.length + "/" + packs.length + " sticker packs selected"); console.log(
"User has " +
this.packs.length +
"/" +
packs.length +
" sticker packs selected"
);
this.isLoading = false; this.isLoading = false;
this.changeDetector.markForCheck(); this.changeDetector.markForCheck();
} catch (e) { } catch (e) {
@ -187,13 +213,14 @@ export class StickerPickerWidgetWrapperComponent extends CapableWidget implement
} }
public scrollHorizontal(event: WheelEvent): void { public scrollHorizontal(event: WheelEvent): void {
document.getElementsByClassName('sticker-pack-list')[0].scrollLeft += event.deltaY; document.getElementsByClassName("sticker-pack-list")[0].scrollLeft +=
event.deltaY;
event.preventDefault(); event.preventDefault();
} }
public scrollToPack(id: string) { public scrollToPack(id: string) {
const el = document.getElementById(id); const el = document.getElementById(id);
el.scrollIntoView({behavior: 'smooth'}); el.scrollIntoView({ behavior: "smooth" });
} }
public sendSticker(sticker: FE_Sticker, pack: FE_UserStickerPack) { public sendSticker(sticker: FE_Sticker, pack: FE_UserStickerPack) {
@ -201,6 +228,9 @@ export class StickerPickerWidgetWrapperComponent extends CapableWidget implement
} }
public openIntegrationManager() { public openIntegrationManager() {
ScalarWidgetApi.openIntegrationManager(WIDGET_STICKER_PICKER[0], ScalarWidgetApi.widgetId); ScalarWidgetApi.openIntegrationManager(
WIDGET_STICKER_PICKER[0],
ScalarWidgetApi.widgetId
);
} }
} }

View File

@ -6,32 +6,38 @@ import { ToasterService } from "angular2-toaster";
import { TranslateService } from "@ngx-translate/core"; import { TranslateService } from "@ngx-translate/core";
@Component({ @Component({
selector: "my-terms-widget-wrapper", selector: "app-terms-widget-wrapper",
templateUrl: "terms.component.html", templateUrl: "terms.component.html",
styleUrls: ["terms.component.scss"], styleUrls: ["terms.component.scss"],
}) })
export class TermsWidgetWrapperComponent implements OnInit { export class TermsWidgetWrapperComponent implements OnInit {
public isLoading = true; public isLoading = true;
public html: SafeHtml; public html: SafeHtml;
constructor(private activatedRoute: ActivatedRoute, constructor(
private sanitizer: DomSanitizer, private activatedRoute: ActivatedRoute,
private toaster: ToasterService, private sanitizer: DomSanitizer,
private widgetApi: WidgetApiService, private toaster: ToasterService,
public translate: TranslateService) { private widgetApi: WidgetApiService,
public translate: TranslateService
) {
this.translate = translate; this.translate = translate;
} }
public ngOnInit(): void { public ngOnInit(): void {
const params: any = this.activatedRoute.snapshot.params; const params: any = this.activatedRoute.snapshot.params;
this.widgetApi.getTerms(params.shortcode, params.lang, params.version).then(terms => { this.widgetApi
this.html = this.sanitizer.bypassSecurityTrustHtml(terms.text); .getTerms(params.shortcode, params.lang, params.version)
this.isLoading = false; .then((terms) => {
}).catch(err => { this.html = this.sanitizer.bypassSecurityTrustHtml(terms.text);
console.error(err); this.isLoading = false;
this.translate.get('Error loading policy').subscribe((res: string) => {this.toaster.pop("error", res); }); })
}); .catch((err) => {
console.error(err);
this.translate.get("Error loading policy").subscribe((res: string) => {
this.toaster.pop("error", res);
});
});
} }
} }

View File

@ -2,20 +2,19 @@ import { Component, OnInit } from "@angular/core";
import { ActivatedRoute } from "@angular/router"; import { ActivatedRoute } from "@angular/router";
import * as $ from "jquery"; import * as $ from "jquery";
declare var TradingView: any; declare let TradingView: any;
@Component({ @Component({
selector: "my-tradingview-widget-wrapper", selector: "app-tradingview-widget-wrapper",
templateUrl: "tradingview.component.html", templateUrl: "tradingview.component.html",
styleUrls: ["tradingview.component.scss"], styleUrls: ["tradingview.component.scss"],
}) })
export class TradingViewWidgetWrapperComponent implements OnInit { export class TradingViewWidgetWrapperComponent implements OnInit {
private symbol: string; private symbol: string;
private interval: string; private interval: string;
constructor(activatedRoute: ActivatedRoute) { constructor(activatedRoute: ActivatedRoute) {
let params: any = activatedRoute.snapshot.queryParams; const params: any = activatedRoute.snapshot.queryParams;
this.symbol = params.pair; this.symbol = params.pair;
this.interval = params.interval; this.interval = params.interval;
@ -24,18 +23,18 @@ export class TradingViewWidgetWrapperComponent implements OnInit {
public ngOnInit() { public ngOnInit() {
$.getScript("https://s3.tradingview.com/tv.js", () => { $.getScript("https://s3.tradingview.com/tv.js", () => {
const widget = new TradingView.widget({ const widget = new TradingView.widget({
"autosize": true, autosize: true,
"symbol": this.symbol, symbol: this.symbol,
"interval": this.interval, interval: this.interval,
"timezone": "Etc/UTC", timezone: "Etc/UTC",
"theme": "Light", theme: "Light",
"style": "1", style: "1",
"locale": "en", locale: "en",
"toolbar_bg": "#f1f3f6", toolbar_bg: "#f1f3f6",
"enable_publishing": false, enable_publishing: false,
"hide_top_toolbar": true, hide_top_toolbar: true,
"hide_legend": true, hide_legend: true,
"container_id": "tradingviewContainer", container_id: "tradingviewContainer",
}); });
console.log("Created widget: " + widget); console.log("Created widget: " + widget);
}); });

View File

@ -3,17 +3,15 @@ import { ActivatedRoute } from "@angular/router";
import { DomSanitizer, SafeUrl } from "@angular/platform-browser"; import { DomSanitizer, SafeUrl } from "@angular/platform-browser";
@Component({ @Component({
selector: "my-video-widget-wrapper", selector: "app-video-widget-wrapper",
templateUrl: "../fullpage-iframe/fullpage-iframe.component.html", templateUrl: "../fullpage-iframe/fullpage-iframe.component.html",
styleUrls: ["../fullpage-iframe/fullpage-iframe.component.scss"], styleUrls: ["../fullpage-iframe/fullpage-iframe.component.scss"],
}) })
export class VideoWidgetWrapperComponent { export class VideoWidgetWrapperComponent {
public embedUrl: SafeUrl = null; public embedUrl: SafeUrl = null;
constructor(activatedRoute: ActivatedRoute, sanitizer: DomSanitizer) { constructor(activatedRoute: ActivatedRoute, sanitizer: DomSanitizer) {
let params: any = activatedRoute.snapshot.queryParams; const params: any = activatedRoute.snapshot.queryParams;
this.embedUrl = sanitizer.bypassSecurityTrustResourceUrl(params.url); this.embedUrl = sanitizer.bypassSecurityTrustResourceUrl(params.url);
} }
} }

View File

@ -1,4 +1,3 @@
export const environment = { export const environment = {
production: true production: true
}; };

View File

@ -4,14 +4,13 @@
export const environment = { export const environment = {
production: false production: false
}; };
/* /*
* For easier debugging in development mode, you can import the following file * For easier debugging in development mode, you can import the following file
* to ignore zone related error stack frames such as `zone.run`, `zoneDelegate.invokeTask`. * to ignore zone related error stack frames such as `zone.run`, `zoneDelegate.invokeTask`.
* *
* This import should be commented out in production mode because it will have a negative impact * This import should be commented out in production mode because it will have a negative impact
* on performance if an error is thrown. * on performance if an error is thrown.
*/ */
// import 'zone.js/plugins/zone-error'; // Included with Angular CLI. // import 'zone.js/plugins/zone-error'; // Included with Angular CLI.