mirror of
https://github.com/turt2live/matrix-dimension.git
synced 2024-10-01 01:05:53 -04:00
Merge remote-tracking branch 'nordeck/nic/feat/configurable-whiteboard-widget'
This commit is contained in:
commit
0e90e73414
@ -78,4 +78,4 @@ export default {
|
|||||||
down: (queryInterface: QueryInterface) => {
|
down: (queryInterface: QueryInterface) => {
|
||||||
return queryInterface.dropTable("dimension_widgets");
|
return queryInterface.dropTable("dimension_widgets");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
24
src/db/migrations/20201204142645-AddWhiteboardWidget.ts
Normal file
24
src/db/migrations/20201204142645-AddWhiteboardWidget.ts
Normal file
@ -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",
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
@ -5,6 +5,10 @@ export interface EtherpadWidgetOptions {
|
|||||||
defaultUrl: string;
|
defaultUrl: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface WhiteboardWidgetOptions {
|
||||||
|
defaultUrl: string;
|
||||||
|
}
|
||||||
|
|
||||||
export interface JitsiWidgetOptions {
|
export interface JitsiWidgetOptions {
|
||||||
jitsiDomain: string;
|
jitsiDomain: string;
|
||||||
scriptUrl: string;
|
scriptUrl: string;
|
||||||
|
22
web/app/admin/widgets/whiteboard/whiteboard.component.html
Normal file
22
web/app/admin/widgets/whiteboard/whiteboard.component.html
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
<div class="dialog">
|
||||||
|
<div class="dialog-header">
|
||||||
|
<h4>Whiteboard Widget Configuration</h4>
|
||||||
|
</div>
|
||||||
|
<div class="dialog-content">
|
||||||
|
<label class="label-block">
|
||||||
|
Default Board URL Template
|
||||||
|
<span class="text-muted ">$boardName and $roomId will be replaced during creation to help create a unique pad URL.</span>
|
||||||
|
<input type="text" class="form-control"
|
||||||
|
placeholder="https://cloud13.de/testwhiteboard/?whiteboardid=$roomId_$boardName"
|
||||||
|
[(ngModel)]="widget.options.defaultUrl" [disabled]="isUpdating"/>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<div class="dialog-footer">
|
||||||
|
<button type="button" (click)="save()" title="save" class="btn btn-primary btn-sm">
|
||||||
|
<i class="far fa-save"></i> Save
|
||||||
|
</button>
|
||||||
|
<button type="button" (click)="dialog.close()" title="close" class="btn btn-secondary btn-sm">
|
||||||
|
<i class="far fa-times-circle"></i> Cancel
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
35
web/app/admin/widgets/whiteboard/whiteboard.component.ts
Normal file
35
web/app/admin/widgets/whiteboard/whiteboard.component.ts
Normal file
@ -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<WidgetConfigDialogContext> {
|
||||||
|
|
||||||
|
public isUpdating = false;
|
||||||
|
public widget: FE_WhiteBoardWidget;
|
||||||
|
private originalWidget: FE_WhiteBoardWidget;
|
||||||
|
|
||||||
|
constructor(public dialog: DialogRef<WidgetConfigDialogContext>, private adminIntegrationsApi: AdminIntegrationsApiService, private toaster: ToasterService) {
|
||||||
|
this.originalWidget = dialog.context.widget;
|
||||||
|
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");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -6,6 +6,7 @@ import { Modal, overlayConfigFactory } from "ngx-modialog";
|
|||||||
import { BSModalContext } from "ngx-modialog/plugins/bootstrap";
|
import { BSModalContext } from "ngx-modialog/plugins/bootstrap";
|
||||||
import { AdminWidgetJitsiConfigComponent } from "./jitsi/jitsi.component";
|
import { AdminWidgetJitsiConfigComponent } from "./jitsi/jitsi.component";
|
||||||
import { AdminIntegrationsApiService } from "../../shared/services/admin/admin-integrations-api.service";
|
import { AdminIntegrationsApiService } from "../../shared/services/admin/admin-integrations-api.service";
|
||||||
|
import { AdminWidgetWhiteboardConfigComponent } from "./whiteboard/whiteboard.component";
|
||||||
|
|
||||||
export class WidgetConfigDialogContext extends BSModalContext {
|
export class WidgetConfigDialogContext extends BSModalContext {
|
||||||
public widget: FE_Widget;
|
public widget: FE_Widget;
|
||||||
@ -50,6 +51,7 @@ export class AdminWidgetsComponent {
|
|||||||
|
|
||||||
if (widget.type === "etherpad") component = AdminWidgetEtherpadConfigComponent;
|
if (widget.type === "etherpad") component = AdminWidgetEtherpadConfigComponent;
|
||||||
if (widget.type === "jitsi") component = AdminWidgetJitsiConfigComponent;
|
if (widget.type === "jitsi") component = AdminWidgetJitsiConfigComponent;
|
||||||
|
if (widget.type === "whiteboard") component = AdminWidgetWhiteboardConfigComponent;
|
||||||
|
|
||||||
if (!component) {
|
if (!component) {
|
||||||
console.error("No known dialog component for " + widget.type);
|
console.error("No known dialog component for " + widget.type);
|
||||||
@ -67,6 +69,6 @@ export class AdminWidgetsComponent {
|
|||||||
|
|
||||||
public hasConfiguration(widget: FE_Widget) {
|
public hasConfiguration(widget: FE_Widget) {
|
||||||
// Currently only Jitsi and Etherpad have additional configuration
|
// 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";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -121,6 +121,8 @@ import { TermsWidgetWrapperComponent } from "./widget-wrappers/terms/terms.compo
|
|||||||
import { BigBlueButtonConfigComponent } from "./configs/widget/bigbluebutton/bigbluebutton.widget.component";
|
import { BigBlueButtonConfigComponent } from "./configs/widget/bigbluebutton/bigbluebutton.widget.component";
|
||||||
import { BigBlueButtonWidgetWrapperComponent } from "./widget-wrappers/bigbluebutton/bigbluebutton.component";
|
import { BigBlueButtonWidgetWrapperComponent } from "./widget-wrappers/bigbluebutton/bigbluebutton.component";
|
||||||
import { BigBlueButtonApiService } from "./shared/services/integrations/bigbluebutton-api.service";
|
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({
|
@NgModule({
|
||||||
imports: [
|
imports: [
|
||||||
@ -220,6 +222,8 @@ import { BigBlueButtonApiService } from "./shared/services/integrations/bigblueb
|
|||||||
AdminNewEditTermsComponent,
|
AdminNewEditTermsComponent,
|
||||||
AdminTermsNewEditPublishDialogComponent,
|
AdminTermsNewEditPublishDialogComponent,
|
||||||
TermsWidgetWrapperComponent,
|
TermsWidgetWrapperComponent,
|
||||||
|
WhiteboardWidgetComponent,
|
||||||
|
AdminWidgetWhiteboardConfigComponent
|
||||||
|
|
||||||
// Vendor
|
// Vendor
|
||||||
],
|
],
|
||||||
@ -277,6 +281,7 @@ import { BigBlueButtonApiService } from "./shared/services/integrations/bigblueb
|
|||||||
AdminSlackBridgeManageSelfhostedComponent,
|
AdminSlackBridgeManageSelfhostedComponent,
|
||||||
AdminLogoutConfirmationDialogComponent,
|
AdminLogoutConfirmationDialogComponent,
|
||||||
AdminTermsNewEditPublishDialogComponent,
|
AdminTermsNewEditPublishDialogComponent,
|
||||||
|
AdminWidgetWhiteboardConfigComponent
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
export class AppModule {
|
export class AppModule {
|
||||||
|
@ -49,6 +49,7 @@ import { ManagerTestWidgetWrapperComponent } from "./widget-wrappers/manager-tes
|
|||||||
import { AdminTermsComponent } from "./admin/terms/terms.component";
|
import { AdminTermsComponent } from "./admin/terms/terms.component";
|
||||||
import { AdminNewEditTermsComponent } from "./admin/terms/new-edit/new-edit.component";
|
import { AdminNewEditTermsComponent } from "./admin/terms/new-edit/new-edit.component";
|
||||||
import { TermsWidgetWrapperComponent } from "./widget-wrappers/terms/terms.component";
|
import { TermsWidgetWrapperComponent } from "./widget-wrappers/terms/terms.component";
|
||||||
|
import { WhiteboardWidgetComponent } from "./configs/widget/whiteboard/whiteboard.widget.component";
|
||||||
|
|
||||||
const routes: Routes = [
|
const routes: Routes = [
|
||||||
{path: "", component: HomeComponent},
|
{path: "", component: HomeComponent},
|
||||||
@ -232,6 +233,11 @@ const routes: Routes = [
|
|||||||
component: SpotifyWidgetConfigComponent,
|
component: SpotifyWidgetConfigComponent,
|
||||||
data: {breadcrumb: "Spotify Widgets", name: "Spotify Widgets"},
|
data: {breadcrumb: "Spotify Widgets", name: "Spotify Widgets"},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: "whiteboard",
|
||||||
|
component: WhiteboardWidgetComponent,
|
||||||
|
data: {breadcrumb: "Whiteboard Widgets", name: "Whiteboard Widgets"},
|
||||||
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -0,0 +1,18 @@
|
|||||||
|
<my-widget-config [widgetComponent]="this">
|
||||||
|
<ng-template #widgetParamsTemplate let-widget="widget">
|
||||||
|
<label class="label-block">
|
||||||
|
Whiteboard Name
|
||||||
|
<input type="text" class="form-control"
|
||||||
|
placeholder="{{ defaultName }}"
|
||||||
|
[(ngModel)]="widget.dimension.newName" name="widget-name-{{widget.id}}"
|
||||||
|
[disabled]="isUpdating"/>
|
||||||
|
</label>
|
||||||
|
<label class="label-block">
|
||||||
|
Whiteboard URL
|
||||||
|
<input type="text" class="form-control"
|
||||||
|
placeholder=""
|
||||||
|
[(ngModel)]="widget.dimension.newUrl" name="widget-url-{{widget.id}}"
|
||||||
|
[disabled]="isUpdating"/>
|
||||||
|
</label>
|
||||||
|
</ng-template>
|
||||||
|
</my-widget-config>
|
@ -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 = <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;
|
||||||
|
}
|
||||||
|
}
|
@ -77,6 +77,10 @@
|
|||||||
<img src="/img/avatars/customwidget.png">
|
<img src="/img/avatars/customwidget.png">
|
||||||
<span>Custom Widget</span>
|
<span>Custom Widget</span>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="integration">
|
||||||
|
<img src="/img/avatars/whiteboard.png">
|
||||||
|
<span>Whiteboard</span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -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 {
|
export interface FE_IntegrationRequirement {
|
||||||
condition: "publicRoom" | "canSendEventTypes" | "userInRoom";
|
condition: "publicRoom" | "canSendEventTypes" | "userInRoom";
|
||||||
argument: any;
|
argument: any;
|
||||||
|
@ -12,6 +12,7 @@ export const WIDGET_TWITCH = ["twitch", "dimension-twitch"]; // TODO: m.* namesp
|
|||||||
export const WIDGET_STICKER_PICKER = ["m.stickerpicker"];
|
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_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_SPOTIFY = ["m.spotify", "spotify", "dimension-spotify"];
|
||||||
|
export const WIDGET_WHITEBOARD = ["whiteboard", "phoenix-whiteboard"];
|
||||||
|
|
||||||
export interface EditableWidget {
|
export interface EditableWidget {
|
||||||
/**
|
/**
|
||||||
|
@ -11,7 +11,8 @@ import {
|
|||||||
WIDGET_STICKER_PICKER,
|
WIDGET_STICKER_PICKER,
|
||||||
WIDGET_TRADINGVIEW,
|
WIDGET_TRADINGVIEW,
|
||||||
WIDGET_TWITCH,
|
WIDGET_TWITCH,
|
||||||
WIDGET_YOUTUBE
|
WIDGET_YOUTUBE,
|
||||||
|
WIDGET_WHITEBOARD
|
||||||
} from "../models/widget";
|
} from "../models/widget";
|
||||||
import { FE_Integration } from "../models/integration";
|
import { FE_Integration } from "../models/integration";
|
||||||
|
|
||||||
@ -69,6 +70,9 @@ export class IntegrationsRegistry {
|
|||||||
"stickerpicker": {
|
"stickerpicker": {
|
||||||
types: WIDGET_STICKER_PICKER,
|
types: WIDGET_STICKER_PICKER,
|
||||||
},
|
},
|
||||||
|
"whiteboard": {
|
||||||
|
type: WIDGET_WHITEBOARD,
|
||||||
|
}
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
BIN
web/public/img/avatars/whiteboard.png
Normal file
BIN
web/public/img/avatars/whiteboard.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.8 KiB |
Loading…
Reference in New Issue
Block a user