Zum Hauptinhalt springen

Textnachrichten

Textnachrichten ermöglichen einen simplen Chat - dies ist eher ein PoC und die Basis für weitere, unterrichtsrelevante Interaktionsmöglichkeiten.

<DynamicDocumentRoots id="732a4df4-26b0-4809-a71b-70d20ccd21a8" />
http://localhost:3000

Technischer Hintergrund

Die DocumentRoot wird verwendet, um in MDX-Dokumenten bspw. Antworten User-Basiert abzuspeichern - es ist das Elternelement für alle Antworten und jede User:in kann dann ein eigenes Document hinzufügen. Über die DocumentRoot werden auch die Berechtigungen festgelegt.

Für interaktive Anwendung (wie einen (Gruppen)-Chat), die nicht ganze Klassen betreffen, braucht es dynamisch generierte DocumentRoots. Um diese dynamischen DocumentRoots wiederzufinden, wird ein Dokument DynamicDocumentRoots erzeugt und in diesem die DocumentRoots abgespeichert. Das mentale Modell dazu: Es werden Räume erzeugt, die von einer DocumentRoot verwaltet werden, die Raum-Logik entspricht dann jedoch direkt der DocumentRoot-Logik. Dadurch funktionieren sowohl "Live-Änderungen" wie auch die Berechtigungen.

Jeder Raum hat einen Namen und eine Raum-Typ (bspw. für den Chat ist dies text_messages).

Ein mögliches Beispiel für die Struktur der Daten des DynamicDocumentRoots:

{
"documentRoots": [
{
"id": "dbc4e980-51d9-4036-b8f5-c26d07fa6dd9",
"name": "FooBar",
"type": "text_messages"
},
{
"id": "c35f8a75-a0a7-4a82-8e7f-da53e8e4f9b4",
"name": "🧁🍰🎂",
"type": "text_messages"
}
]
}
id
Die eindeutige ID des dynamischen DocumentRoot
name
Der Namen des Raums. Dieser wird bspw. im Chat angezeigt.
type
Der Typ des Raums. Dieser bestimmt, welche Komponenten und welche Logik für den Raum verwendet wird.
Aktuelle Einschränkungen

Bei der Erstellung eines dynamic_document_roots werden die Berechtigungen auf access=RO_DocumentRoot und sharedAccess=RW_DocumentRoot gesetzt - was vernünftige Standards sind. Allerdings kann dadurch nicht direkt ein Dokument erzeugt und hinzugefügt werden, da auch für ADmins die Berechtigungen nur RO sind.

Lösung

Eine Admin-Gruppe muss in der API bspw. als ENV-Variable hinterlegt werden und diese Gruppe wird standardmässig zu jeder DocumentRoot mit RW_GroupPermission hinzugefügt.

Installation

Code
  • src/plugins/plugin-dynamic-routes
  • src/models/DynamicDocumentRoots.ts
  • src/models/DynamicDocumentRoot.ts
  • src/components/Rooms
  • src/components/documents/DynamicDocumentRoots
Models
src/api/document.ts
export enum DocumentType {
/* ... */
TextMessage = 'text_message',
DynamicDocumentRoot = 'dynamic_document_root',
DynamicDocumentRoots = 'dynamic_document_roots'
}

export interface TextMessageData {
text: string;
}

export interface DynamicDocumentRootData {
/** such a document is never created - it's only the document root that is needed */
}

export enum RoomType {
Messages = 'text_messages'
}
export interface DynamicDocumentRoot {
id: string;
name: string;
type: RoomType;
}

export interface DynamicDocumentRootsData {
documentRoots: DynamicDocumentRoot[];
}
export interface TypeDataMapping {
/* ... */
[DocumentType.TextMessage]: TextMessageData;
[DocumentType.DynamicDocumentRoot]: DynamicDocumentRootData;
[DocumentType.DynamicDocumentRoots]: DynamicDocumentRootsData;
}

export interface TypeModelMapping {
/* ... */
[DocumentType.TextMessage]: TextMessage;
[DocumentType.DynamicDocumentRoot]: DynamicDocumentRootModel;
[DocumentType.DynamicDocumentRoots]: DynamicDocumentRoots;
}

export type DocumentTypes =
/* ... */
| TextMessage
| DynamicDocumentRootModel
| DynamicDocumentRoots
Stores
src/stores/DocumentStore.ts
export function CreateDocumentModel(data: DocumentProps<DocumentType>, store: DocumentStore): DocumentTypes {
switch (data.type) {
/* ... */
case DocumentType.TextMessage:
return new TextMessage(data as DocumentProps<DocumentType.TextMessage>, store);
case DocumentType.DynamicDocumentRoot:
return new DynamicDocumentRootModel(
data as DocumentProps<DocumentType.DynamicDocumentRoot>,
store
);
case DocumentType.DynamicDocumentRoots:
return new DynamicDocumentRoots(data as DocumentProps<DocumentType.DynamicDocumentRoots>, store);
}
}
src/stores/SocketDataStore.ts
/**
* Records that should be created when a IoEvent.NEW_RECORD event is received.
*/
const RecordsToCreate = new Set<DocumentType>([DocumentType.DynamicDocumentRoots, DocumentType.TextMessage /* ... */]);
/* ... */
docusaurus.config.ts

Die Landing-Page für die Räume /rooms/<documentRootId>/<dynamicDocumentRootId> muss im Docusaurus Router registriert werden.

import dynamicRouterPlugin, { Config as DynamicRouteConfig} from './src/plugins/plugin-dynamic-routes';

const config: Config = {
plugins: [
[
dynamicRouterPlugin,
{
routes: [
{
path: '/rooms/',
component: '@tdev-components/Rooms',
}
]
} satisfies DynamicRouteConfig
],
]
}