diff --git a/src/db/migrations/20171218203245-AddWidgets.ts b/src/db/migrations/20171218203245-AddWidgets.ts
index 5cbddbb..9d60881 100644
--- a/src/db/migrations/20171218203245-AddWidgets.ts
+++ b/src/db/migrations/20171218203245-AddWidgets.ts
@@ -78,4 +78,4 @@ export default {
down: (queryInterface: QueryInterface) => {
return queryInterface.dropTable("dimension_widgets");
}
-}
\ No newline at end of file
+}
diff --git a/src/db/migrations/20201204142645-AddWhiteboardWidget.ts b/src/db/migrations/20201204142645-AddWhiteboardWidget.ts
new file mode 100644
index 0000000..68192c4
--- /dev/null
+++ b/src/db/migrations/20201204142645-AddWhiteboardWidget.ts
@@ -0,0 +1,24 @@
+import { QueryInterface } from "sequelize";
+
+export default {
+ up: (queryInterface: QueryInterface) => {
+ return Promise.resolve()
+ .then(() => queryInterface.bulkInsert("dimension_widgets", [
+ {
+ type: "whiteboard",
+ name: "Whiteboard",
+ avatarUrl: "/img/avatars/whiteboard.png",
+ isEnabled: true,
+ isPublic: true,
+ description: "A whiteboard app embedded in the room.",
+ optionsJson: '{"defaultUrl":"https://cloud13.de/testwhiteboard/?whiteboardid=$roomId_$boardName"}',
+ }
+ ]));
+ },
+ down: (queryInterface: QueryInterface) => {
+ return Promise.resolve()
+ .then(() => queryInterface.bulkDelete("dimension_widgets", {
+ type: "whiteboard",
+ }));
+ }
+}
diff --git a/src/integrations/Widget.ts b/src/integrations/Widget.ts
index e29da8c..c348834 100644
--- a/src/integrations/Widget.ts
+++ b/src/integrations/Widget.ts
@@ -5,6 +5,10 @@ export interface EtherpadWidgetOptions {
defaultUrl: string;
}
+export interface WhiteboardWidgetOptions {
+ defaultUrl: string;
+}
+
export interface JitsiWidgetOptions {
jitsiDomain: string;
scriptUrl: string;
diff --git a/web/app/admin/widgets/whiteboard/whiteboard.component.html b/web/app/admin/widgets/whiteboard/whiteboard.component.html
new file mode 100644
index 0000000..68fc80c
--- /dev/null
+++ b/web/app/admin/widgets/whiteboard/whiteboard.component.html
@@ -0,0 +1,22 @@
+
+
+
+
+
+
+
diff --git a/web/app/admin/widgets/whiteboard/whiteboard.component.scss b/web/app/admin/widgets/whiteboard/whiteboard.component.scss
new file mode 100644
index 0000000..e69de29
diff --git a/web/app/admin/widgets/whiteboard/whiteboard.component.ts b/web/app/admin/widgets/whiteboard/whiteboard.component.ts
new file mode 100644
index 0000000..6b9c01b
--- /dev/null
+++ b/web/app/admin/widgets/whiteboard/whiteboard.component.ts
@@ -0,0 +1,35 @@
+import { Component } from "@angular/core";
+import { FE_WhiteBoardWidget } from "../../../shared/models/integration";
+import { ToasterService } from "angular2-toaster";
+import { DialogRef, ModalComponent } from "ngx-modialog";
+import { WidgetConfigDialogContext } from "../widgets.component";
+import { AdminIntegrationsApiService } from "../../../shared/services/admin/admin-integrations-api.service";
+
+@Component({
+ templateUrl: "./whiteboard.component.html",
+ styleUrls: ["./whiteboard.component.scss", "../config-dialog.scss"],
+})
+export class AdminWidgetWhiteboardConfigComponent implements ModalComponent {
+
+ public isUpdating = false;
+ public widget: FE_WhiteBoardWidget;
+ private originalWidget: FE_WhiteBoardWidget;
+
+ constructor(public dialog: DialogRef, private adminIntegrationsApi: AdminIntegrationsApiService, private toaster: ToasterService) {
+ this.originalWidget = dialog.context.widget;
+ this.widget = JSON.parse(JSON.stringify(this.originalWidget));
+ }
+
+ public save() {
+ this.isUpdating = true;
+ this.adminIntegrationsApi.setIntegrationOptions(this.widget.category, this.widget.type, this.widget.options).then(() => {
+ this.originalWidget.options = this.widget.options;
+ this.toaster.pop("success", "Widget updated");
+ this.dialog.close();
+ }).catch(err => {
+ this.isUpdating = false;
+ console.error(err);
+ this.toaster.pop("error", "Error updating widget");
+ });
+ }
+}
diff --git a/web/app/admin/widgets/widgets.component.ts b/web/app/admin/widgets/widgets.component.ts
index 5debd8e..6aab37c 100644
--- a/web/app/admin/widgets/widgets.component.ts
+++ b/web/app/admin/widgets/widgets.component.ts
@@ -6,6 +6,7 @@ import { Modal, overlayConfigFactory } from "ngx-modialog";
import { BSModalContext } from "ngx-modialog/plugins/bootstrap";
import { AdminWidgetJitsiConfigComponent } from "./jitsi/jitsi.component";
import { AdminIntegrationsApiService } from "../../shared/services/admin/admin-integrations-api.service";
+import { AdminWidgetWhiteboardConfigComponent } from "./whiteboard/whiteboard.component";
export class WidgetConfigDialogContext extends BSModalContext {
public widget: FE_Widget;
@@ -50,6 +51,7 @@ export class AdminWidgetsComponent {
if (widget.type === "etherpad") component = AdminWidgetEtherpadConfigComponent;
if (widget.type === "jitsi") component = AdminWidgetJitsiConfigComponent;
+ if (widget.type === "whiteboard") component = AdminWidgetWhiteboardConfigComponent;
if (!component) {
console.error("No known dialog component for " + widget.type);
@@ -67,6 +69,6 @@ export class AdminWidgetsComponent {
public hasConfiguration(widget: FE_Widget) {
// Currently only Jitsi and Etherpad have additional configuration
- return widget.type === "jitsi" || widget.type === "etherpad";
+ return widget.type === "jitsi" || widget.type === "etherpad" || widget.type === "whiteboard";
}
}
diff --git a/web/app/app.module.ts b/web/app/app.module.ts
index 9d9dbf7..c1889ae 100644
--- a/web/app/app.module.ts
+++ b/web/app/app.module.ts
@@ -121,6 +121,8 @@ import { TermsWidgetWrapperComponent } from "./widget-wrappers/terms/terms.compo
import { BigBlueButtonConfigComponent } from "./configs/widget/bigbluebutton/bigbluebutton.widget.component";
import { BigBlueButtonWidgetWrapperComponent } from "./widget-wrappers/bigbluebutton/bigbluebutton.component";
import { BigBlueButtonApiService } from "./shared/services/integrations/bigbluebutton-api.service";
+import { WhiteboardWidgetComponent } from "./configs/widget/whiteboard/whiteboard.widget.component";
+import { AdminWidgetWhiteboardConfigComponent } from "./admin/widgets/whiteboard/whiteboard.component";
@NgModule({
imports: [
@@ -220,6 +222,8 @@ import { BigBlueButtonApiService } from "./shared/services/integrations/bigblueb
AdminNewEditTermsComponent,
AdminTermsNewEditPublishDialogComponent,
TermsWidgetWrapperComponent,
+ WhiteboardWidgetComponent,
+ AdminWidgetWhiteboardConfigComponent
// Vendor
],
@@ -277,6 +281,7 @@ import { BigBlueButtonApiService } from "./shared/services/integrations/bigblueb
AdminSlackBridgeManageSelfhostedComponent,
AdminLogoutConfirmationDialogComponent,
AdminTermsNewEditPublishDialogComponent,
+ AdminWidgetWhiteboardConfigComponent
]
})
export class AppModule {
diff --git a/web/app/app.routing.ts b/web/app/app.routing.ts
index 8bbd11c..eb778e0 100644
--- a/web/app/app.routing.ts
+++ b/web/app/app.routing.ts
@@ -49,6 +49,7 @@ import { ManagerTestWidgetWrapperComponent } from "./widget-wrappers/manager-tes
import { AdminTermsComponent } from "./admin/terms/terms.component";
import { AdminNewEditTermsComponent } from "./admin/terms/new-edit/new-edit.component";
import { TermsWidgetWrapperComponent } from "./widget-wrappers/terms/terms.component";
+import { WhiteboardWidgetComponent } from "./configs/widget/whiteboard/whiteboard.widget.component";
const routes: Routes = [
{path: "", component: HomeComponent},
@@ -232,6 +233,11 @@ const routes: Routes = [
component: SpotifyWidgetConfigComponent,
data: {breadcrumb: "Spotify Widgets", name: "Spotify Widgets"},
},
+ {
+ path: "whiteboard",
+ component: WhiteboardWidgetComponent,
+ data: {breadcrumb: "Whiteboard Widgets", name: "Whiteboard Widgets"},
+ },
],
},
{
diff --git a/web/app/configs/widget/whiteboard/whiteboard.widget.component.html b/web/app/configs/widget/whiteboard/whiteboard.widget.component.html
new file mode 100644
index 0000000..49e80b1
--- /dev/null
+++ b/web/app/configs/widget/whiteboard/whiteboard.widget.component.html
@@ -0,0 +1,18 @@
+
+
+
+
+
+
diff --git a/web/app/configs/widget/whiteboard/whiteboard.widget.component.scss b/web/app/configs/widget/whiteboard/whiteboard.widget.component.scss
new file mode 100644
index 0000000..e69de29
diff --git a/web/app/configs/widget/whiteboard/whiteboard.widget.component.ts b/web/app/configs/widget/whiteboard/whiteboard.widget.component.ts
new file mode 100644
index 0000000..e10cd98
--- /dev/null
+++ b/web/app/configs/widget/whiteboard/whiteboard.widget.component.ts
@@ -0,0 +1,46 @@
+import { WidgetComponent } from "../widget.component";
+import { Component } from "@angular/core";
+import { EditableWidget, WIDGET_WHITEBOARD } from "../../../shared/models/widget";
+import * as url from "url";
+import { SessionStorage } from "../../../shared/SessionStorage";
+import { NameService } from "../../../shared/services/name.service";
+import { FE_WhiteBoardWidget } from "../../../shared/models/integration";
+
+@Component({
+ templateUrl: "whiteboard.widget.component.html",
+ styleUrls: ["whiteboard.widget.component.scss"],
+})
+export class WhiteboardWidgetComponent extends WidgetComponent {
+ private whiteBoardWidget: FE_WhiteBoardWidget = SessionStorage.editIntegration;
+
+ constructor(private nameService: NameService) {
+ super(WIDGET_WHITEBOARD, "Whiteboard", "generic", "whiteboard", "boardName");
+ }
+ protected OnWidgetsDiscovered(widgets: EditableWidget[]): void {
+ console.log(widgets);
+ for (const widget of widgets) {
+ if (!widget.dimension.newUrl.startsWith("http://") && !widget.dimension.newUrl.startsWith("https://")) {
+ const parsedUrl = url.parse(widget.url, true);
+ const boardName = parsedUrl.query["boardName"];
+
+ // Set the new URL so that it unpacks correctly
+ widget.url = `https://dev-whiteboard.nordeck.net/?whiteboardid=${boardName}`;
+ }
+ }
+ }
+
+ protected OnNewWidgetPrepared(widget: EditableWidget): void {
+ const name = this.nameService.getHumanReadableName();
+
+ let template = "https://dev-whiteboard.nordeck.net/?whiteboardid=$roomId_$boardName";
+ if (this.whiteBoardWidget.options && this.whiteBoardWidget.options.defaultUrl) {
+ template = this.whiteBoardWidget.options.defaultUrl;
+ }
+
+ template = template.replace("$roomId", encodeURIComponent(SessionStorage.roomId));
+ template = template.replace("$boardName", encodeURIComponent(name));
+
+ widget.dimension.newUrl = template;
+ widget.dimension.newName = name;
+ }
+}
diff --git a/web/app/home/home.component.html b/web/app/home/home.component.html
index 72a58f1..da34646 100644
--- a/web/app/home/home.component.html
+++ b/web/app/home/home.component.html
@@ -77,6 +77,10 @@
Custom Widget
+
+
![](/img/avatars/whiteboard.png)
+
Whiteboard
+
diff --git a/web/app/shared/models/integration.ts b/web/app/shared/models/integration.ts
index 6d8a444..519cb32 100644
--- a/web/app/shared/models/integration.ts
+++ b/web/app/shared/models/integration.ts
@@ -99,6 +99,12 @@ export interface FE_BigBlueButtonWidget extends FE_Widget {
};
}
+export interface FE_WhiteBoardWidget extends FE_Widget {
+ options: {
+ defaultUrl: string;
+ };
+}
+
export interface FE_IntegrationRequirement {
condition: "publicRoom" | "canSendEventTypes" | "userInRoom";
argument: any;
diff --git a/web/app/shared/models/widget.ts b/web/app/shared/models/widget.ts
index 795189b..4026d4a 100644
--- a/web/app/shared/models/widget.ts
+++ b/web/app/shared/models/widget.ts
@@ -12,6 +12,7 @@ export const WIDGET_TWITCH = ["twitch", "dimension-twitch"]; // TODO: m.* namesp
export const WIDGET_STICKER_PICKER = ["m.stickerpicker"];
export const WIDGET_TRADINGVIEW = ["tradingview", "dimension-tradingview"]; // TODO: Use m.tradingview (https://github.com/turt2live/matrix-dimension/issues/261)
export const WIDGET_SPOTIFY = ["m.spotify", "spotify", "dimension-spotify"];
+export const WIDGET_WHITEBOARD = ["whiteboard", "phoenix-whiteboard"];
export interface EditableWidget {
/**
diff --git a/web/app/shared/registry/integrations.registry.ts b/web/app/shared/registry/integrations.registry.ts
index 673836b..4c834bf 100644
--- a/web/app/shared/registry/integrations.registry.ts
+++ b/web/app/shared/registry/integrations.registry.ts
@@ -11,7 +11,8 @@ import {
WIDGET_STICKER_PICKER,
WIDGET_TRADINGVIEW,
WIDGET_TWITCH,
- WIDGET_YOUTUBE
+ WIDGET_YOUTUBE,
+ WIDGET_WHITEBOARD
} from "../models/widget";
import { FE_Integration } from "../models/integration";
@@ -69,6 +70,9 @@ export class IntegrationsRegistry {
"stickerpicker": {
types: WIDGET_STICKER_PICKER,
},
+ "whiteboard": {
+ type: WIDGET_WHITEBOARD,
+ }
},
};
diff --git a/web/public/img/avatars/whiteboard.png b/web/public/img/avatars/whiteboard.png
new file mode 100644
index 0000000..526d155
Binary files /dev/null and b/web/public/img/avatars/whiteboard.png differ