[plugin-server-commands] - added server-command caption save and add a captionLocale
This commit is contained in:
parent
4063ee811b
commit
8db3a6be80
@ -82,7 +82,7 @@ trait UpdateTranscriptPubMsgHdlr {
|
||||
for {
|
||||
u <- Users2x.findWithIntId(liveMeeting.users2x, msg.header.userId)
|
||||
} yield {
|
||||
CaptionDAO.insertOrUpdateAudioCaption(msg.body.transcriptId, meetingId, msg.header.userId, transcript, u.speechLocale)
|
||||
CaptionDAO.insertOrUpdateCaption(msg.body.transcriptId, meetingId, msg.header.userId, transcript, u.speechLocale)
|
||||
}
|
||||
|
||||
broadcastEvent(
|
||||
|
@ -6,7 +6,7 @@ import org.bigbluebutton.common2.msgs._
|
||||
import org.bigbluebutton.core.bus.MessageBus
|
||||
import org.bigbluebutton.core.running.LiveMeeting
|
||||
import org.bigbluebutton.core.apps.{ PermissionCheck, RightsManagementTrait }
|
||||
import org.bigbluebutton.core.db.{ CaptionLocaleDAO, CaptionTypes }
|
||||
import org.bigbluebutton.core.db.{ CaptionDAO, CaptionLocaleDAO, CaptionTypes }
|
||||
|
||||
class CaptionApp2x(implicit val context: ActorContext) extends RightsManagementTrait {
|
||||
val log = Logging(context.system, getClass)
|
||||
@ -51,7 +51,23 @@ class CaptionApp2x(implicit val context: ActorContext) extends RightsManagementT
|
||||
}
|
||||
}
|
||||
}
|
||||
def handle(msg: CaptionSubmitTranscriptPubMsg, liveMeeting: LiveMeeting, bus: MessageBus): Unit = {
|
||||
val meetingId = liveMeeting.props.meetingProp.intId
|
||||
def broadcastSuccessEvent(transcriptId: String, transcript: String, locale: String): Unit = {
|
||||
val routing = Routing.addMsgToClientRouting(MessageTypes.BROADCAST_TO_MEETING, liveMeeting.props.meetingProp.intId, msg.header.userId)
|
||||
val envelope = BbbCoreEnvelope(CaptionSubmitTranscriptSuccessEvtMsg.NAME, routing)
|
||||
val header = BbbClientMsgHeader(CaptionSubmitTranscriptSuccessEvtMsg.NAME, liveMeeting.props.meetingProp.intId, msg.header.userId)
|
||||
|
||||
val body = CaptionSubmitTranscriptSuccessEvtMsgBody(transcriptId, transcript, locale, msg.body.captionType)
|
||||
val event = CaptionSubmitTranscriptSuccessEvtMsg(header, body)
|
||||
val msgEvent = BbbCommonEnvCoreMsg(envelope, event)
|
||||
bus.outGW.send(msgEvent)
|
||||
}
|
||||
CaptionDAO.insertOrUpdateCaption(msg.body.transcriptId, meetingId, msg.header.userId,
|
||||
msg.body.transcript, msg.body.locale, msg.body.captionType)
|
||||
|
||||
broadcastSuccessEvent(msg.body.transcriptId, msg.body.transcript, msg.body.locale)
|
||||
}
|
||||
def handle(msg: SendCaptionHistoryReqMsg, liveMeeting: LiveMeeting, bus: MessageBus): Unit = {
|
||||
def broadcastEvent(msg: SendCaptionHistoryReqMsg, history: Map[String, TranscriptVO]): Unit = {
|
||||
val routing = Routing.addMsgToClientRouting(MessageTypes.DIRECT, liveMeeting.props.meetingProp.intId, msg.header.userId)
|
||||
|
@ -32,13 +32,14 @@ object CaptionTypes {
|
||||
|
||||
object CaptionDAO {
|
||||
|
||||
def insertOrUpdateAudioCaption(captionId: String, meetingId: String, userId: String, transcript: String, locale: String) = {
|
||||
def insertOrUpdateCaption(captionId: String, meetingId: String, userId: String, transcript: String,
|
||||
locale: String, captionType: String = CaptionTypes.AUDIO_TRANSCRIPTION) = {
|
||||
DatabaseConnection.db.run(
|
||||
TableQuery[CaptionTableDef].insertOrUpdate(
|
||||
CaptionDbModel(
|
||||
captionId = captionId,
|
||||
meetingId = meetingId,
|
||||
captionType = CaptionTypes.AUDIO_TRANSCRIPTION,
|
||||
captionType = captionType,
|
||||
userId = userId,
|
||||
locale = locale,
|
||||
captionText = transcript,
|
||||
|
@ -347,6 +347,8 @@ class ReceivedJsonMsgHandlerActor(
|
||||
routeGenericMsg[AddCaptionLocalePubMsg](envelope, jsonNode)
|
||||
case SendCaptionHistoryReqMsg.NAME =>
|
||||
routeGenericMsg[SendCaptionHistoryReqMsg](envelope, jsonNode)
|
||||
case CaptionSubmitTranscriptPubMsg.NAME =>
|
||||
routeGenericMsg[CaptionSubmitTranscriptPubMsg](envelope, jsonNode)
|
||||
|
||||
// Chat
|
||||
case GetChatHistoryReqMsg.NAME =>
|
||||
|
@ -654,6 +654,7 @@ class MeetingActor(
|
||||
case m: EditCaptionHistoryPubMsg => captionApp2x.handle(m, liveMeeting, msgBus)
|
||||
case m: AddCaptionLocalePubMsg => captionApp2x.handle(m, liveMeeting, msgBus)
|
||||
case m: SendCaptionHistoryReqMsg => captionApp2x.handle(m, liveMeeting, msgBus)
|
||||
case m: CaptionSubmitTranscriptPubMsg => captionApp2x.handle(m, liveMeeting, msgBus)
|
||||
|
||||
// Guests
|
||||
case m: GetGuestsWaitingApprovalReqMsg => handleGetGuestsWaitingApprovalReqMsg(m)
|
||||
|
@ -9,6 +9,22 @@ object AddCaptionLocalePubMsg { val NAME = "AddCaptionLocalePubMsg" }
|
||||
case class AddCaptionLocalePubMsg(header: BbbClientMsgHeader, body: AddCaptionLocalePubMsgBody) extends StandardMsg
|
||||
case class AddCaptionLocalePubMsgBody(locale: String)
|
||||
|
||||
object CaptionSubmitTranscriptPubMsg { val NAME = "CaptionSubmitTranscriptPubMsg" }
|
||||
case class CaptionSubmitTranscriptPubMsg(header: BbbClientMsgHeader, body: CaptionSubmitTranscriptPubMsgBody) extends StandardMsg
|
||||
case class CaptionSubmitTranscriptPubMsgBody(
|
||||
transcriptId: String,
|
||||
transcript: String,
|
||||
locale: String,
|
||||
captionType: String,
|
||||
)
|
||||
object CaptionSubmitTranscriptSuccessEvtMsg { val NAME = "CaptionSubmitTranscriptSuccessEvtMsg" }
|
||||
case class CaptionSubmitTranscriptSuccessEvtMsg(header: BbbClientMsgHeader, body: CaptionSubmitTranscriptSuccessEvtMsgBody) extends StandardMsg
|
||||
case class CaptionSubmitTranscriptSuccessEvtMsgBody(
|
||||
transcriptId: String,
|
||||
transcript: String,
|
||||
locale: String,
|
||||
captionType: String,
|
||||
)
|
||||
object SendCaptionHistoryReqMsg { val NAME = "SendCaptionHistoryReqMsg" }
|
||||
case class SendCaptionHistoryReqMsg(header: BbbClientMsgHeader, body: SendCaptionHistoryReqMsgBody) extends StandardMsg
|
||||
case class SendCaptionHistoryReqMsgBody()
|
||||
|
36
bbb-graphql-actions/src/actions/captionSubmitTranscript.ts
Normal file
36
bbb-graphql-actions/src/actions/captionSubmitTranscript.ts
Normal file
@ -0,0 +1,36 @@
|
||||
|
||||
import { throwErrorIfInvalidInput } from '../imports/validation';
|
||||
import { RedisMessage } from '../types';
|
||||
|
||||
export default function buildRedisMessage(sessionVariables: Record<string, unknown>, input: Record<string, unknown>): RedisMessage {
|
||||
const eventName = `CaptionSubmitTranscriptPubMsg`;
|
||||
|
||||
throwErrorIfInvalidInput(input,
|
||||
[
|
||||
{name: 'transcriptId', type: 'string', required: true},
|
||||
{name: 'transcript', type: 'string', required: true},
|
||||
{name: 'locale', type: 'string', required: true},
|
||||
{name: 'captionType', type: 'string', required: true},
|
||||
]
|
||||
)
|
||||
|
||||
const routing = {
|
||||
meetingId: sessionVariables['x-hasura-meetingid'] as String,
|
||||
userId: sessionVariables['x-hasura-userid'] as String
|
||||
};
|
||||
|
||||
const header = {
|
||||
name: eventName,
|
||||
meetingId: routing.meetingId,
|
||||
userId: routing.userId
|
||||
};
|
||||
|
||||
const body = {
|
||||
transcriptId: input.transcriptId,
|
||||
transcript: input.transcript,
|
||||
locale: input.locale,
|
||||
captionType: input.captionType,
|
||||
};
|
||||
|
||||
return { eventName, routing, header, body };
|
||||
}
|
@ -11,7 +11,7 @@ export default function buildRedisMessage(sessionVariables: Record<string, unkno
|
||||
]
|
||||
)
|
||||
|
||||
const eventName = `PluginDataChannelDeleteMessageMsg`;
|
||||
const eventName = `PluginDataChannelDeleteEntryMsg`;
|
||||
|
||||
const routing = {
|
||||
meetingId: sessionVariables['x-hasura-meetingid'] as String,
|
||||
|
@ -77,6 +77,14 @@ type Mutation {
|
||||
): Boolean
|
||||
}
|
||||
|
||||
type Mutation {
|
||||
captionSubmitTranscript(
|
||||
transcriptId: String!
|
||||
transcript: String!
|
||||
locale: String!
|
||||
): Boolean
|
||||
}
|
||||
|
||||
type Mutation {
|
||||
chatCreateWithUser(
|
||||
userId: String!
|
||||
|
@ -71,6 +71,12 @@ actions:
|
||||
handler: '{{HASURA_BBB_GRAPHQL_ACTIONS_ADAPTER_URL}}'
|
||||
permissions:
|
||||
- role: bbb_client
|
||||
- name: captionSubmitTranscript
|
||||
definition:
|
||||
kind: synchronous
|
||||
handler: '{{HASURA_BBB_GRAPHQL_ACTIONS_ADAPTER_URL}}'
|
||||
permissions:
|
||||
- role: bbb_client
|
||||
- name: chatCreateWithUser
|
||||
definition:
|
||||
kind: synchronous
|
||||
|
@ -16,6 +16,7 @@ const GenericContentItem: React.FC<GenericContentItemProps> = (props) => {
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
height: '100%',
|
||||
overflow: 'hidden',
|
||||
}}
|
||||
ref={elementRef}
|
||||
|
@ -2,43 +2,40 @@ import React from 'react';
|
||||
import Styled from './styles';
|
||||
import { GenericSidekickContentProps } from '../types';
|
||||
import GenericContentItem from '../generic-content-item/component';
|
||||
import { layoutDispatch } from '/imports/ui/components/layout/context';
|
||||
import { PANELS, ACTIONS } from '/imports/ui/components/layout/enums';
|
||||
|
||||
const GenericSidekickContent: React.FC<GenericSidekickContentProps> = ({
|
||||
renderFunction,
|
||||
layoutContextDispatch,
|
||||
genericContentId,
|
||||
genericContentLabel,
|
||||
}) => {
|
||||
const layoutContextDispatch = layoutDispatch();
|
||||
return (
|
||||
<Styled.Container
|
||||
data-test={genericContentId}
|
||||
>
|
||||
<Styled.Header
|
||||
leftButtonProps={{
|
||||
onClick: () => {
|
||||
layoutContextDispatch({
|
||||
type: ACTIONS.SET_SIDEBAR_CONTENT_IS_OPEN,
|
||||
value: false,
|
||||
});
|
||||
layoutContextDispatch({
|
||||
type: ACTIONS.SET_SIDEBAR_CONTENT_PANEL,
|
||||
value: PANELS.NONE,
|
||||
});
|
||||
},
|
||||
'data-test': `hide_${genericContentId}`,
|
||||
'aria-label': genericContentLabel,
|
||||
label: genericContentLabel,
|
||||
}}
|
||||
customRightButton={null}
|
||||
/>
|
||||
<GenericContentItem
|
||||
key={genericContentId}
|
||||
renderFunction={renderFunction}
|
||||
/>
|
||||
</Styled.Container>
|
||||
);
|
||||
};
|
||||
}) => (
|
||||
<Styled.Container
|
||||
data-test={genericContentId}
|
||||
>
|
||||
<Styled.Header
|
||||
leftButtonProps={{
|
||||
onClick: () => {
|
||||
layoutContextDispatch({
|
||||
type: ACTIONS.SET_SIDEBAR_CONTENT_IS_OPEN,
|
||||
value: false,
|
||||
});
|
||||
layoutContextDispatch({
|
||||
type: ACTIONS.SET_SIDEBAR_CONTENT_PANEL,
|
||||
value: PANELS.NONE,
|
||||
});
|
||||
},
|
||||
'data-test': `hide_${genericContentId}`,
|
||||
'aria-label': genericContentLabel,
|
||||
label: genericContentLabel,
|
||||
}}
|
||||
customRightButton={null}
|
||||
/>
|
||||
<GenericContentItem
|
||||
key={genericContentId}
|
||||
renderFunction={renderFunction}
|
||||
/>
|
||||
</Styled.Container>
|
||||
);
|
||||
|
||||
export default GenericSidekickContent;
|
||||
|
@ -2,30 +2,42 @@ import React, { useContext } from 'react';
|
||||
import * as PluginSdk from 'bigbluebutton-html-plugin-sdk';
|
||||
import { GenericContentType } from 'bigbluebutton-html-plugin-sdk/dist/cjs/extensible-areas/generic-content-item/enums';
|
||||
import { PluginsContext } from '/imports/ui/components/components-data/plugin-context/context';
|
||||
import { PANELS } from '/imports/ui/components/layout/enums';
|
||||
import { PANELS, ACTIONS } from '/imports/ui/components/layout/enums';
|
||||
import GenericSidekickContent from './component';
|
||||
import { GenericContentSidekickContainerProps } from '../types';
|
||||
import logger from '/imports/startup/client/logger';
|
||||
import { layoutDispatch } from '../../layout/context';
|
||||
|
||||
const GenericContentSidekickContainer: React.FC<GenericContentSidekickContainerProps> = (
|
||||
props: GenericContentSidekickContainerProps,
|
||||
) => {
|
||||
const { genericSidekickContentId } = props;
|
||||
const genericSidekickContentIdIsolated = genericSidekickContentId.replace(PANELS.GENERIC_CONTENT_SIDEKICK, '');
|
||||
const layoutContextDispatch = layoutDispatch();
|
||||
|
||||
const {
|
||||
pluginsExtensibleAreasAggregatedState,
|
||||
} = useContext(PluginsContext);
|
||||
let genericSidekickContentExtensibleArea = [] as PluginSdk.GenericContentSidekickArea[];
|
||||
let genericContentSidekickAreaExtensibleArea = [] as PluginSdk.GenericContentSidekickArea[];
|
||||
|
||||
if (pluginsExtensibleAreasAggregatedState.genericContentItems) {
|
||||
const genericMainContent = pluginsExtensibleAreasAggregatedState.genericContentItems
|
||||
const genericContentSidekickArea = pluginsExtensibleAreasAggregatedState.genericContentItems
|
||||
.filter((g) => g.type === GenericContentType.SIDEKICK_AREA) as PluginSdk.GenericContentSidekickArea[];
|
||||
genericSidekickContentExtensibleArea = [...genericMainContent];
|
||||
genericContentSidekickAreaExtensibleArea = [...genericContentSidekickArea];
|
||||
}
|
||||
|
||||
if (genericSidekickContentExtensibleArea.length === 0) return null;
|
||||
const pickedGenericSidekickContent = genericSidekickContentExtensibleArea
|
||||
if (genericContentSidekickAreaExtensibleArea.length === 0) {
|
||||
layoutContextDispatch({
|
||||
type: ACTIONS.SET_SIDEBAR_CONTENT_IS_OPEN,
|
||||
value: false,
|
||||
});
|
||||
layoutContextDispatch({
|
||||
type: ACTIONS.SET_SIDEBAR_CONTENT_PANEL,
|
||||
value: PANELS.NONE,
|
||||
});
|
||||
return null;
|
||||
}
|
||||
const pickedGenericSidekickContent = genericContentSidekickAreaExtensibleArea
|
||||
.filter((gsc) => gsc.id === genericSidekickContentIdIsolated)[0];
|
||||
|
||||
if (!pickedGenericSidekickContent) {
|
||||
@ -40,6 +52,7 @@ const GenericContentSidekickContainer: React.FC<GenericContentSidekickContainerP
|
||||
|
||||
return (
|
||||
<GenericSidekickContent
|
||||
layoutContextDispatch={layoutContextDispatch}
|
||||
genericContentId={pickedGenericSidekickContent.id}
|
||||
renderFunction={pickedGenericSidekickContent.contentFunction}
|
||||
genericContentLabel={pickedGenericSidekickContent.name}
|
||||
|
@ -17,6 +17,7 @@ export interface GenericContentSidekickContainerProps {
|
||||
}
|
||||
|
||||
export interface GenericSidekickContentProps {
|
||||
layoutContextDispatch: (...args: unknown[]) => void;
|
||||
genericContentId: string;
|
||||
renderFunction: (element: HTMLElement) => void;
|
||||
genericContentLabel: string;
|
||||
|
@ -97,7 +97,7 @@ const DataChannelItemManagerWriter: React.ElementType<DataChannelItemManagerWrit
|
||||
variables: {
|
||||
pluginName: hookArguments?.pluginName,
|
||||
channelName: hookArguments?.channelName,
|
||||
messageId: eventDetails.data,
|
||||
entryId: eventDetails.data,
|
||||
subChannelName,
|
||||
},
|
||||
});
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { gql } from '@apollo/client';
|
||||
|
||||
const PLUGIN_DATA_CHANNEL_NEW_ITEMS = gql`
|
||||
subscription FetchPluginDataChannelEntryMsg($pluginName: String!,
|
||||
subscription FetchPluginDataChannelEntry($pluginName: String!,
|
||||
$channelName: String! , $createdAt: timestamptz!, $subChannelName: String!){
|
||||
pluginDataChannelEntry_stream(
|
||||
cursor: {initial_value: {createdAt: $createdAt}}, batch_size: 100,
|
||||
@ -24,7 +24,7 @@ const PLUGIN_DATA_CHANNEL_NEW_ITEMS = gql`
|
||||
`;
|
||||
|
||||
const PLUGIN_DATA_CHANNEL_All_ITEMS = gql`
|
||||
subscription FetchPluginDataChannelEntryMsg($pluginName: String!,
|
||||
subscription FetchPluginDataChannelEntry($pluginName: String!,
|
||||
$channelName: String!, $subChannelName: String!
|
||||
){
|
||||
pluginDataChannelEntry(
|
||||
@ -48,7 +48,7 @@ const PLUGIN_DATA_CHANNEL_All_ITEMS = gql`
|
||||
`;
|
||||
|
||||
const PLUGIN_DATA_CHANNEL_LATEST_ITEM = gql`
|
||||
subscription FetchPluginDataChannelEntryMsg($pluginName: String!,
|
||||
subscription FetchPluginDataChannelEntry($pluginName: String!,
|
||||
$channelName: String!, $subChannelName: String!
|
||||
){
|
||||
pluginDataChannelEntry(
|
||||
|
@ -15,6 +15,7 @@ import ExtensibleAreaStateManager from './extensible-areas/manager';
|
||||
import PluginDataChannelManager from './data-channel/manager';
|
||||
import PluginUiCommandsHandler from './ui-commands/handler';
|
||||
import PluginDomElementManipulationManager from './dom-element-manipulation/manager';
|
||||
import PluginServerCommandsHandler from './server-commands/handler';
|
||||
|
||||
const PluginsEngineManager = () => {
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
@ -53,6 +54,7 @@ const PluginsEngineManager = () => {
|
||||
}}
|
||||
/>
|
||||
<PluginDataConsumptionManager />
|
||||
<PluginServerCommandsHandler />
|
||||
<PluginUiCommandsHandler />
|
||||
<PluginDomElementManipulationManager />
|
||||
{
|
||||
|
@ -0,0 +1,30 @@
|
||||
import { useEffect } from 'react';
|
||||
import { useMutation } from '@apollo/client';
|
||||
import {
|
||||
CaptionCommandsEnum,
|
||||
} from 'bigbluebutton-html-plugin-sdk/dist/cjs/server-commands/caption/enum';
|
||||
import CAPTION_ADD_LOCALE from './mutations';
|
||||
|
||||
const PluginAddLocaleCaptionServerCommandsManager = () => {
|
||||
const [captionAddLocale] = useMutation(CAPTION_ADD_LOCALE);
|
||||
const handleCaptionAddLocale = ((
|
||||
event: CustomEvent<string>,
|
||||
) => {
|
||||
captionAddLocale({
|
||||
variables: {
|
||||
locale: event.detail,
|
||||
},
|
||||
});
|
||||
}) as EventListener;
|
||||
|
||||
useEffect(() => {
|
||||
window.addEventListener(CaptionCommandsEnum.ADD_LOCALE, handleCaptionAddLocale);
|
||||
|
||||
return () => {
|
||||
window.removeEventListener(CaptionCommandsEnum.ADD_LOCALE, handleCaptionAddLocale);
|
||||
};
|
||||
}, []);
|
||||
return null;
|
||||
};
|
||||
|
||||
export default PluginAddLocaleCaptionServerCommandsManager;
|
@ -8,6 +8,4 @@ export const CAPTION_ADD_LOCALE = gql`
|
||||
}
|
||||
`;
|
||||
|
||||
export default {
|
||||
CAPTION_ADD_LOCALE,
|
||||
};
|
||||
export default CAPTION_ADD_LOCALE;
|
@ -0,0 +1,35 @@
|
||||
import { useEffect } from 'react';
|
||||
import { CaptionSaveCommandArguments } from 'bigbluebutton-html-plugin-sdk/dist/cjs/server-commands/caption/types';
|
||||
import { useMutation } from '@apollo/client';
|
||||
import * as uuidLib from 'uuid';
|
||||
import {
|
||||
CaptionCommandsEnum,
|
||||
} from 'bigbluebutton-html-plugin-sdk/dist/cjs/server-commands/caption/enum';
|
||||
import SUBMIT_TRANSCRIPT from './mutations';
|
||||
|
||||
const PluginSaveCaptionServerCommandsManager = () => {
|
||||
const [submitTranscript] = useMutation(SUBMIT_TRANSCRIPT);
|
||||
const handleSubmitCaption = ((
|
||||
event: CustomEvent<CaptionSaveCommandArguments>,
|
||||
) => {
|
||||
submitTranscript({
|
||||
variables: {
|
||||
transcriptId: uuidLib.v4(),
|
||||
transcript: event.detail.text,
|
||||
locale: event.detail.locale,
|
||||
captionType: event.detail.captionType,
|
||||
},
|
||||
});
|
||||
}) as EventListener;
|
||||
|
||||
useEffect(() => {
|
||||
window.addEventListener(CaptionCommandsEnum.SAVE, handleSubmitCaption);
|
||||
|
||||
return () => {
|
||||
window.removeEventListener(CaptionCommandsEnum.SAVE, handleSubmitCaption);
|
||||
};
|
||||
}, []);
|
||||
return null;
|
||||
};
|
||||
|
||||
export default PluginSaveCaptionServerCommandsManager;
|
@ -0,0 +1,19 @@
|
||||
import { gql } from '@apollo/client';
|
||||
|
||||
const SUBMIT_TRANSCRIPT = gql`
|
||||
mutation (
|
||||
$transcriptId: String!
|
||||
$transcript: String!
|
||||
$locale: String!
|
||||
$captionType: String!
|
||||
) {
|
||||
captionSubmitTranscript(
|
||||
transcriptId: $transcriptId,
|
||||
transcript: $transcript,
|
||||
locale: $locale,
|
||||
captionType: $captionType
|
||||
)
|
||||
}
|
||||
`;
|
||||
|
||||
export default SUBMIT_TRANSCRIPT;
|
@ -0,0 +1,12 @@
|
||||
import * as React from 'react';
|
||||
import PluginSaveCaptionServerCommandsManager from './caption/save/manager';
|
||||
import PluginAddLocaleCaptionServerCommandsManager from './caption/add-locale/manager';
|
||||
|
||||
const PluginServerCommandsHandler = () => (
|
||||
<>
|
||||
<PluginSaveCaptionServerCommandsManager />
|
||||
<PluginAddLocaleCaptionServerCommandsManager />
|
||||
</>
|
||||
);
|
||||
|
||||
export default PluginServerCommandsHandler;
|
@ -1,59 +0,0 @@
|
||||
import React, { useContext } from 'react';
|
||||
import { GenericContentType } from 'bigbluebutton-html-plugin-sdk/dist/cjs/extensible-areas/generic-content-item/enums';
|
||||
import Icon from '/imports/ui/components/common/icon/component';
|
||||
import Styled from './styles';
|
||||
import { ACTIONS, PANELS } from '/imports/ui/components/layout/enums';
|
||||
import { PluginsContext } from '/imports/ui/components/components-data/plugin-context/context';
|
||||
|
||||
const GenericSidekickContentNavButton = ({ sidebarContentPanel, layoutContextDispatch }) => {
|
||||
const { pluginsExtensibleAreasAggregatedState } = useContext(PluginsContext);
|
||||
let genericSidekickContentExtensibleArea = [];
|
||||
|
||||
if (pluginsExtensibleAreasAggregatedState.genericContentItems) {
|
||||
const genericMainContent = pluginsExtensibleAreasAggregatedState.genericContentItems
|
||||
.filter((g) => g.type === GenericContentType.SIDEKICK_AREA);
|
||||
genericSidekickContentExtensibleArea = [...genericMainContent];
|
||||
}
|
||||
|
||||
const genericSidekickContentId = (id) => PANELS.GENERIC_CONTENT_SIDEKICK + id;
|
||||
|
||||
if (genericSidekickContentExtensibleArea.length === 0) return null;
|
||||
const genericSidekickContentNavButtons = genericSidekickContentExtensibleArea.map((gsc) => (
|
||||
<Styled.Section>
|
||||
<Styled.Container>
|
||||
<Styled.SmallTitle>
|
||||
{gsc.section}
|
||||
</Styled.SmallTitle>
|
||||
</Styled.Container>
|
||||
<Styled.ScrollableList>
|
||||
<Styled.List>
|
||||
<Styled.ListItem
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
active={sidebarContentPanel === genericSidekickContentId(gsc.id)}
|
||||
onClick={() => {
|
||||
layoutContextDispatch({
|
||||
type: ACTIONS.SET_SIDEBAR_CONTENT_IS_OPEN,
|
||||
value: sidebarContentPanel !== genericSidekickContentId(gsc.id),
|
||||
});
|
||||
layoutContextDispatch({
|
||||
type: ACTIONS.SET_SIDEBAR_CONTENT_PANEL,
|
||||
value: sidebarContentPanel === genericSidekickContentId(gsc.id)
|
||||
? PANELS.NONE
|
||||
: genericSidekickContentId(gsc.id),
|
||||
});
|
||||
}}
|
||||
>
|
||||
<Icon iconName={gsc.buttonIcon} />
|
||||
<span>
|
||||
{gsc.name}
|
||||
</span>
|
||||
</Styled.ListItem>
|
||||
</Styled.List>
|
||||
</Styled.ScrollableList>
|
||||
</Styled.Section>
|
||||
));
|
||||
return <>{genericSidekickContentNavButtons}</>;
|
||||
};
|
||||
|
||||
export default GenericSidekickContentNavButton;
|
@ -0,0 +1,72 @@
|
||||
import React, { useContext } from 'react';
|
||||
import { GenericContentType } from 'bigbluebutton-html-plugin-sdk/dist/cjs/extensible-areas/generic-content-item/enums';
|
||||
import * as PluginSdk from 'bigbluebutton-html-plugin-sdk';
|
||||
import Styled from './styles';
|
||||
import { PANELS } from '/imports/ui/components/layout/enums';
|
||||
import { PluginsContext } from '/imports/ui/components/components-data/plugin-context/context';
|
||||
import GenericContentSidekickAreaMenuItem from './menu-item/component';
|
||||
|
||||
interface GenericComponentSidekickMenuProps {
|
||||
sidebarContentPanel: string;
|
||||
layoutContextDispatch: (...args: unknown[]) => void;
|
||||
}
|
||||
|
||||
interface MappedMenuItems {
|
||||
[key: string]: PluginSdk.GenericContentSidekickArea[]
|
||||
}
|
||||
|
||||
const GenericSidekickContentNavButton = ({
|
||||
sidebarContentPanel, layoutContextDispatch,
|
||||
}: GenericComponentSidekickMenuProps) => {
|
||||
const { pluginsExtensibleAreasAggregatedState } = useContext(PluginsContext);
|
||||
let genericSidekickContentExtensibleArea = [] as PluginSdk.GenericContentSidekickArea[];
|
||||
|
||||
if (pluginsExtensibleAreasAggregatedState.genericContentItems) {
|
||||
const genericMainContent = pluginsExtensibleAreasAggregatedState.genericContentItems
|
||||
.filter((g) => g.type === GenericContentType.SIDEKICK_AREA) as PluginSdk.GenericContentSidekickArea[];
|
||||
genericSidekickContentExtensibleArea = [...genericMainContent];
|
||||
}
|
||||
|
||||
const genericContentSidekickId = (id: string) => PANELS.GENERIC_CONTENT_SIDEKICK + id;
|
||||
|
||||
const groupBySidekickMenuSection: MappedMenuItems = {};
|
||||
|
||||
genericSidekickContentExtensibleArea.forEach((item) => {
|
||||
const { section } = item;
|
||||
let alreadySetArray = groupBySidekickMenuSection[section];
|
||||
if (alreadySetArray) {
|
||||
alreadySetArray.push(item);
|
||||
} else {
|
||||
alreadySetArray = [item];
|
||||
}
|
||||
groupBySidekickMenuSection[section] = alreadySetArray;
|
||||
});
|
||||
|
||||
if (Object.keys(groupBySidekickMenuSection).length !== 0) {
|
||||
return Object.keys(groupBySidekickMenuSection).map((section) => (
|
||||
<Styled.Section
|
||||
key={genericContentSidekickId(section)}
|
||||
>
|
||||
<Styled.Container>
|
||||
<Styled.SmallTitle>
|
||||
{section}
|
||||
</Styled.SmallTitle>
|
||||
</Styled.Container>
|
||||
{groupBySidekickMenuSection[section].map((genericContentSidekickAreaObject) => (
|
||||
<GenericContentSidekickAreaMenuItem
|
||||
key={genericContentSidekickId(genericContentSidekickAreaObject.id)}
|
||||
sidebarContentPanel={sidebarContentPanel}
|
||||
genericSidekickContentId={genericContentSidekickId(genericContentSidekickAreaObject.id)}
|
||||
genericContentSidekickAreaObject={genericContentSidekickAreaObject}
|
||||
layoutContextDispatch={layoutContextDispatch}
|
||||
/>
|
||||
))}
|
||||
</Styled.Section>
|
||||
));
|
||||
} else {
|
||||
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
export default GenericSidekickContentNavButton;
|
@ -0,0 +1,63 @@
|
||||
import * as React from 'react';
|
||||
import { useEffect } from 'react';
|
||||
import * as PluginSdk from 'bigbluebutton-html-plugin-sdk';
|
||||
import Icon from '/imports/ui/components/common/icon/component';
|
||||
import { ACTIONS, PANELS } from '/imports/ui/components/layout/enums';
|
||||
import Styled from '../styles';
|
||||
|
||||
interface GenericContentSidekickAreaMenuItemProps{
|
||||
sidebarContentPanel: string;
|
||||
genericSidekickContentId: string;
|
||||
genericContentSidekickAreaObject: PluginSdk.GenericContentSidekickArea;
|
||||
layoutContextDispatch: (...args: unknown[]) => void;
|
||||
}
|
||||
|
||||
const GenericContentSidekickAreaMenuItem = ({
|
||||
sidebarContentPanel,
|
||||
genericSidekickContentId,
|
||||
genericContentSidekickAreaObject,
|
||||
layoutContextDispatch,
|
||||
}: GenericContentSidekickAreaMenuItemProps) => {
|
||||
useEffect(() => {
|
||||
if (genericContentSidekickAreaObject.open) {
|
||||
layoutContextDispatch({
|
||||
type: ACTIONS.SET_SIDEBAR_CONTENT_IS_OPEN,
|
||||
value: true,
|
||||
});
|
||||
layoutContextDispatch({
|
||||
type: ACTIONS.SET_SIDEBAR_CONTENT_PANEL,
|
||||
value: genericSidekickContentId,
|
||||
});
|
||||
}
|
||||
}, []);
|
||||
return (
|
||||
<Styled.ScrollableList>
|
||||
<Styled.List>
|
||||
<Styled.ListItem
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
active={sidebarContentPanel === genericSidekickContentId}
|
||||
onClick={() => {
|
||||
layoutContextDispatch({
|
||||
type: ACTIONS.SET_SIDEBAR_CONTENT_IS_OPEN,
|
||||
value: sidebarContentPanel !== genericSidekickContentId,
|
||||
});
|
||||
layoutContextDispatch({
|
||||
type: ACTIONS.SET_SIDEBAR_CONTENT_PANEL,
|
||||
value: sidebarContentPanel === genericSidekickContentId
|
||||
? PANELS.NONE
|
||||
: genericSidekickContentId,
|
||||
});
|
||||
}}
|
||||
>
|
||||
<Icon iconName={genericContentSidekickAreaObject.buttonIcon} />
|
||||
<span>
|
||||
{genericContentSidekickAreaObject.name}
|
||||
</span>
|
||||
</Styled.ListItem>
|
||||
</Styled.List>
|
||||
</Styled.ScrollableList>
|
||||
);
|
||||
};
|
||||
|
||||
export default GenericContentSidekickAreaMenuItem;
|
@ -3,7 +3,11 @@ import styled from 'styled-components';
|
||||
import Styled from '/imports/ui/components/user-list/styles';
|
||||
import StyledContent from '/imports/ui/components/user-list/user-list-content/styles';
|
||||
|
||||
const ListItem = styled(StyledContent.ListItem)`
|
||||
interface ListItemProps {
|
||||
active: boolean;
|
||||
}
|
||||
|
||||
const ListItem = styled(StyledContent.ListItem)<ListItemProps>`
|
||||
i{ left: 4px; }
|
||||
`;
|
||||
|
Loading…
Reference in New Issue
Block a user