From f563ca6f8802baa569a74668ce7fe68768d1c613 Mon Sep 17 00:00:00 2001 From: freddysundowner Date: Tue, 21 Nov 2023 11:40:10 +0300 Subject: [PATCH 1/2] added video sharing component and its controls --- .../videoMeetingControllerComp.tsx | 99 +++-- .../meetingComp/videoMeetingStreamComp.tsx | 9 +- .../meetingComp/videoSharingStreamComp.tsx | 345 ++++++++++++++++++ client/packages/lowcoder/src/comps/index.tsx | 16 +- .../lowcoder/src/comps/uiCompRegistry.ts | 1 + .../packages/lowcoder/src/i18n/locales/en.ts | 12 +- .../src/pages/editor/editorConstants.tsx | 1 + 7 files changed, 451 insertions(+), 32 deletions(-) create mode 100644 client/packages/lowcoder/src/comps/comps/meetingComp/videoSharingStreamComp.tsx diff --git a/client/packages/lowcoder/src/comps/comps/meetingComp/videoMeetingControllerComp.tsx b/client/packages/lowcoder/src/comps/comps/meetingComp/videoMeetingControllerComp.tsx index fe4bcdb16..be45aede9 100644 --- a/client/packages/lowcoder/src/comps/comps/meetingComp/videoMeetingControllerComp.tsx +++ b/client/packages/lowcoder/src/comps/comps/meetingComp/videoMeetingControllerComp.tsx @@ -41,7 +41,7 @@ import { useUserViewMode } from "util/hooks"; import { isNumeric } from "util/stringUtils"; import { NameConfig, withExposingConfigs } from "../../generators/withExposing"; -import { v4 as uuidv4 } from 'uuid'; +import { v4 as uuidv4 } from "uuid"; // import axios from "axios"; @@ -147,6 +147,7 @@ const shareScreen = async (sharing: boolean) => { try { if (sharing === false) { await client.unpublish(screenShareStream); + screenShareStream.close(); await client.publish(videoTrack); videoTrack.play(userId + ""); } else { @@ -165,11 +166,16 @@ const shareScreen = async (sharing: boolean) => { } }; const leaveChannel = async () => { + //stops local sharing video + screenShareStream.close(); + + //stops local video streaming and puts off the camera if (videoTrack) { await client.unpublish(videoTrack); await turnOnCamera(false); } + //mutes and stops locla audio stream if (audioTrack) { await turnOnMicrophone(false); } @@ -183,12 +189,12 @@ const publishVideo = async ( rtmToken: string, rtcToken: string ) => { - // initializing the Agora Meeting Client - await turnOnCamera(true); - await client.join(appId, channel, rtcToken, userId); - await client.publish(videoTrack); - // initializing the Agora RTM Client - await rtmInit(appId, userId, rtmToken, channel); + // initializing the Agora Meeting Client + await turnOnCamera(true); + await client.join(appId, channel, rtcToken, userId); + await client.publish(videoTrack); + // initializing the Agora RTM Client + await rtmInit(appId, userId, rtmToken, channel); }; const sendMessageRtm = (message: any) => { @@ -231,8 +237,14 @@ export const meetingControllerChildren = { participants: stateComp([]), usersScreenShared: stateComp([]), localUser: jsonObjectExposingStateControl(""), - localUserID : withDefault(stringStateControl(trans("meeting.localUserID")), uuidv4() + ""), - meetingName: withDefault(stringStateControl(trans("meeting.meetingName")), uuidv4() + ""), + localUserID: withDefault( + stringStateControl(trans("meeting.localUserID")), + uuidv4() + "" + ), + meetingName: withDefault( + stringStateControl(trans("meeting.meetingName")), + uuidv4() + "" + ), rtmToken: stringStateControl(trans("meeting.rtmToken")), rtcToken: stringStateControl(trans("meeting.rtcToken")), messages: stateComp([]), @@ -265,7 +277,8 @@ let MTComp = (function () { }); const [rtmMessages, setRtmMessages] = useState([]); const [localUserSpeaking, setLocalUserSpeaking] = useState(false); - const [localUserVideo, setLocalUserVideo] = useState(); + const [localUserVideo, setLocalUserVideo] = + useState(); const [userJoined, setUserJoined] = useState(); const [userLeft, setUserLeft] = useState(); @@ -323,6 +336,8 @@ let MTComp = (function () { } }, [userLeft]); + console.log("sharing", props.sharing); + useEffect(() => { if (updateVolume.userid) { let prevUsers: [] = props.participants as []; @@ -342,6 +357,28 @@ let MTComp = (function () { } }, [updateVolume]); + useEffect(() => { + let prevUsers: [] = props.participants as []; + const updatedItems = prevUsers.map((userInfo: any) => { + if (userInfo.user === localUserVideo?.uid) { + return { ...userInfo, streamingSharing: props.sharing.value }; + } + return userInfo; + }); + dispatch( + changeChildAction("participants", getData(updatedItems).data, false) + ); + + let localObject = { + user: userId + "", + audiostatus: props.audioControl.value, + streamingVideo: props.videoControl.value, + streamingSharing: props.sharing.value, + speaking: localUserSpeaking, + }; + props.localUser.onChange(localObject); + }, [props.sharing.value]); + useEffect(() => { let prevUsers: [] = props.participants as []; const updatedItems = prevUsers.map((userInfo: any) => { @@ -383,37 +420,52 @@ let MTComp = (function () { if (prevMessages.length >= 500) { prevMessages.pop(); // Remove the oldest message } - return [...prevMessages, {"peermessage" : JSON.parse(message.text + ""), "from" : peerId}]; + return [ + ...prevMessages, + { peermessage: JSON.parse(message.text + ""), from: peerId }, + ]; }); }); - + rtmChannelResponse.on("ChannelMessage", function (message, memberId) { setRtmMessages((prevMessages: any[]) => { // Check if the messages array exceeds the maximum limit if (prevMessages.length >= 500) { prevMessages.pop(); // Remove the oldest message } - return [...prevMessages, {"channelmessage" : JSON.parse(message.text + ""), "from" : memberId}]; + return [ + ...prevMessages, + { + channelmessage: JSON.parse(message.text + ""), + from: memberId, + }, + ]; }); - - dispatch(changeChildAction("messages", getData(rtmMessages).data, false)); + + dispatch( + changeChildAction("messages", getData(rtmMessages).data, false) + ); }); } }, [rtmChannelResponse]); - useEffect(() => { if (client) { + //Enable Agora to send audio bytes client.enableAudioVolumeIndicator(); + //user activity listeners client.on("user-joined", (user: IAgoraRTCRemoteUser) => { setUserJoined(user); }); client.on("user-left", (user: IAgoraRTCRemoteUser, reason: any) => { setUserLeft(user); }); + + //listen to user speaking, client.on("volume-indicator", (volumeInfos: any) => { if (volumeInfos.length === 0) return; volumeInfos.map((volumeInfo: any) => { + //when the volume is above 30, user is probably speaking const speaking = volumeInfo.level >= 30; if ( volumeInfo.uid === userId && @@ -534,8 +586,8 @@ let MTComp = (function () { })}
- {children.appId.propertyView({ - label: trans("meeting.appid") + {children.appId.propertyView({ + label: trans("meeting.appid"), })} {children.meetingName.propertyView({ label: trans("meeting.meetingName"), @@ -646,7 +698,10 @@ MTComp = withMethodExposing(MTComp, [ }, execute: async (comp, values) => { if (comp.children.meetingActive.getView().value) return; - userId = comp.children.localUserID.getView().value === "" ? uuidv4() : comp.children.localUserID.getView().value; + userId = + comp.children.localUserID.getView().value === "" + ? uuidv4() + : comp.children.localUserID.getView().value; comp.children.localUser.change({ user: userId + "", audiostatus: false, @@ -669,7 +724,9 @@ MTComp = withMethodExposing(MTComp, [ comp.children.videoControl.change(true); await publishVideo( comp.children.appId.getView(), - comp.children.meetingName.getView().value === "" ? uuidv4() : comp.children.meetingName.getView().value, + comp.children.meetingName.getView().value === "" + ? uuidv4() + : comp.children.meetingName.getView().value, comp.children.rtmToken.getView().value, comp.children.rtcToken.getView().value ); @@ -790,7 +847,7 @@ export const VideoMeetingControllerComp = withExposingConfigs(MTComp, [ new NameConfig("meetingActive", trans("meeting.meetingActive")), new NameConfig("meetingName", trans("meeting.meetingName")), new NameConfig("localUserID", trans("meeting.localUserID")), - new NameConfig("messages", trans("meeting.messages")), + new NameConfig("messages", trans("meeting.messages")), new NameConfig("rtmToken", trans("meeting.rtmToken")), new NameConfig("rtcToken", trans("meeting.rtcToken")), ]); diff --git a/client/packages/lowcoder/src/comps/comps/meetingComp/videoMeetingStreamComp.tsx b/client/packages/lowcoder/src/comps/comps/meetingComp/videoMeetingStreamComp.tsx index 5fbc372b7..fe868117a 100644 --- a/client/packages/lowcoder/src/comps/comps/meetingComp/videoMeetingStreamComp.tsx +++ b/client/packages/lowcoder/src/comps/comps/meetingComp/videoMeetingStreamComp.tsx @@ -137,7 +137,6 @@ const typeOptions = [ export const meetingStreamChildren = { autoHeight: withDefault(AutoHeightControl, "fixed"), - shareScreen: withDefault(BoolShareVideoControl, false), profilePadding: withDefault(StringControl, "0px"), profileBorderRadius: withDefault(StringControl, "0px"), videoAspectRatio: withDefault(StringControl, "1 / 1"), @@ -236,6 +235,9 @@ let VideoCompBuilder = (function (props) { } }, [props.userId.value]); + console.log(props.userId); + + return ( {(editorState) => ( @@ -264,7 +266,7 @@ let VideoCompBuilder = (function (props) { borderRadius: props.style.radius, width: "auto", }} - id={props.shareScreen ? "share-screen" : userId} + id={userId} > ) : ( <> @@ -300,9 +302,6 @@ let VideoCompBuilder = (function (props) {
{children.userId.propertyView({ label: trans("meeting.videoId") })} {children.autoHeight.getPropertyView()} - {children.shareScreen.propertyView({ - label: trans("meeting.shareScreen"), - })} {children.profileImageUrl.propertyView({ label: trans("meeting.profileImageUrl"), placeholder: "https://via.placeholder.com/120", diff --git a/client/packages/lowcoder/src/comps/comps/meetingComp/videoSharingStreamComp.tsx b/client/packages/lowcoder/src/comps/comps/meetingComp/videoSharingStreamComp.tsx new file mode 100644 index 000000000..424d04853 --- /dev/null +++ b/client/packages/lowcoder/src/comps/comps/meetingComp/videoSharingStreamComp.tsx @@ -0,0 +1,345 @@ +import { BoolCodeControl } from "comps/controls/codeControl"; +import { dropdownControl } from "comps/controls/dropdownControl"; +// import { IconControl } from "comps/controls/iconControl"; +import { CompNameContext, EditorContext, EditorState } from "comps/editorState"; +import { withDefault } from "comps/generators"; +import { UICompBuilder } from "comps/generators/uiCompBuilder"; +import ReactResizeDetector from "react-resize-detector"; +// import _ from "lodash"; +import { + CommonBlueLabel, + controlItem, + Dropdown, + Section, + sectionNames, +} from "lowcoder-design"; +import { trans } from "i18n"; + +import styled, { css } from "styled-components"; +import { + CommonNameConfig, + NameConfig, + withExposingConfigs, +} from "../../generators/withExposing"; +import { IForm } from "../formComp/formDataConstants"; +import { SimpleNameComp } from "../simpleNameComp"; +import { ButtonStyleControl } from "./videobuttonCompConstants"; +import { RefControl } from "comps/controls/refControl"; +import { useEffect, useRef, useState } from "react"; + +import { AutoHeightControl } from "comps/controls/autoHeightControl"; +import { client } from "./videoMeetingControllerComp"; + +import { IAgoraRTCRemoteUser } from "agora-rtc-sdk-ng"; + +import { + MeetingEventHandlerControl, + StringControl, + StringStateControl, + hiddenPropertyView, + stringExposingStateControl, +} from "@lowcoder-ee/index.sdk"; +import { BoolShareVideoControl } from "./meetingControlerUtils"; + +const FormLabel = styled(CommonBlueLabel)` + font-size: 13px; + margin-right: 4px; +`; + +function getFormOptions(editorState: EditorState) { + return editorState + .uiCompInfoList() + .filter((info) => info.type === "form") + .map((info) => ({ + label: info.name, + value: info.name, + })); +} + +const VideoContainer = styled.video` + height: 100%; + width: 100%; + display: flex; + align-items: center; + justify-content: space-around; +`; + +function getForm(editorState: EditorState, formName: string) { + const comp = editorState?.getUICompByName(formName); + if (comp && comp.children.compType.getView() === "form") { + return comp.children.comp as unknown as IForm; + } +} + +function getFormEventHandlerPropertyView( + editorState: EditorState, + formName: string +) { + const form = getForm(editorState, formName); + if (!form) { + return undefined; + } + + return ( + + {form.onEventPropertyView( + <> + + editorState.setSelectedCompNames( + new Set([formName]), + "rightPanel" + ) + } + > + {formName} + + {trans("button.formButtonEvent")} + + )} + + ); +} + +class SelectFormControl extends SimpleNameComp { + override getPropertyView() { + const label = trans("button.formToSubmit"); + return controlItem( + { filterText: label }, + + {(editorState) => ( + <> + this.dispatchChangeValueAction(value)} + allowClear={true} + /> + {getFormEventHandlerPropertyView(editorState, this.value)} + + )} + + ); + } +} + +const typeOptions = [ + { + label: trans("button.default"), + value: "", + }, + { + label: trans("button.submit"), + value: "submit", + }, +] as const; + +export const meetingStreamChildren = { + autoHeight: withDefault(AutoHeightControl, "fixed"), + profilePadding: withDefault(StringControl, "0px"), + profileBorderRadius: withDefault(StringControl, "0px"), + videoAspectRatio: withDefault(StringControl, "1 / 1"), + type: dropdownControl(typeOptions, ""), + onEvent: MeetingEventHandlerControl, + disabled: BoolCodeControl, + loading: BoolCodeControl, + form: SelectFormControl, + // prefixIcon: IconControl, + // suffixIcon: IconControl, + style: ButtonStyleControl, + viewRef: RefControl, + userId: stringExposingStateControl(""), + profileImageUrl: withDefault( + StringStateControl, + "https://api.dicebear.com/7.x/fun-emoji/svg?seed=Peanut&radius=50&backgroundColor=transparent&randomizeIds=true&eyes=wink,sleepClose" + ), + noVideoText: stringExposingStateControl("No Video"), +}; + +let SharingCompBuilder = (function (props) { + return new UICompBuilder(meetingStreamChildren, (props) => { + const videoRef = useRef(null); + const conRef = useRef(null); + const [userId, setUserId] = useState(); + const [userName, setUsername] = useState(""); + const [showVideoSharing, setVideoSharing] = useState(true); + + useEffect(() => { + if (props.userId.value !== "") { + let userData = JSON.parse(props.userId?.value); + client.on( + "user-published", + async (user: IAgoraRTCRemoteUser, mediaType: "video" | "audio") => { + if (mediaType === "video") { + const remoteTrack = await client.subscribe(user, mediaType); + let userId = user.uid + ""; + if ( + user.hasVideo && + user.uid + "" !== userData.user && + userData.user !== "" + ) { + props.onEvent("videoOn"); + } + const element = document.getElementById(userId); + + if (element) { + remoteTrack.play(userId); + } + } + if (mediaType === "audio") { + const remoteTrack = await client.subscribe(user, mediaType); + if ( + user.hasAudio && + user.uid + "" !== userData.user && + userData.user !== "" + ) { + userData.audiostatus = user.hasVideo; + + props.onEvent("audioUnmuted"); + } + remoteTrack.play(); + } + } + ); + client.on( + "user-unpublished", + (user: IAgoraRTCRemoteUser, mediaType: "video" | "audio") => { + console.log("user-unpublished"); + + if (mediaType === "audio") { + if ( + !user.hasAudio && + user.uid + "" !== userData.user && + userData.user !== "" + ) { + userData.audiostatus = user.hasVideo; + props.onEvent("audioMuted"); + } + } + if (mediaType === "video") { + if (videoRef.current && videoRef.current?.id === user.uid + "") { + videoRef.current.srcObject = null; + } + if ( + !user.hasVideo && + user.uid + "" !== userData.user && + userData.user !== "" + ) { + props.onEvent("videoOff"); + } + } + } + ); + + setUserId(userData.user); + setUsername(userData.userName); + setVideoSharing(userData.streamingSharing); + } + }, [props.userId.value]); + + return ( + + {(editorState) => ( + +
+ {userId ? ( + props.onEvent("videoClicked")} + ref={videoRef} + style={{ + display: `${showVideoSharing ? "flex" : "none"}`, + aspectRatio: props.videoAspectRatio, + borderRadius: props.style.radius, + width: "auto", + }} + id="share-screen" + > + ) : ( + <> + )} +
+ +

{userName ?? ""}

+
+
+
+ )} +
+ ); + }) + .setPropertyViewFn((children) => ( + <> +
+ {children.userId.propertyView({ label: trans("meeting.videoId") })} + {children.autoHeight.getPropertyView()} + {children.profileImageUrl.propertyView({ + label: trans("meeting.profileImageUrl"), + placeholder: "https://via.placeholder.com/120", + })} +
+ +
+ {children.onEvent.getPropertyView()} +
+
+ {hiddenPropertyView(children)} +
+
+ {children.profilePadding.propertyView({ + label: "Profile Image Padding", + })} + {children.profileBorderRadius.propertyView({ + label: "Profile Image Border Radius", + })} + {children.videoAspectRatio.propertyView({ + label: "Video Aspect Ratio", + })} + {children.style.getPropertyView()} +
+ + )) + .build(); +})(); + +SharingCompBuilder = class extends SharingCompBuilder { + override autoHeight(): boolean { + return this.children.autoHeight.getView(); + } +}; + +export const VideoSharingStreamComp = withExposingConfigs(SharingCompBuilder, [ + new NameConfig("loading", trans("button.loadingDesc")), + new NameConfig("profileImageUrl", trans("meeting.profileImageUrl")), + + ...CommonNameConfig, +]); diff --git a/client/packages/lowcoder/src/comps/index.tsx b/client/packages/lowcoder/src/comps/index.tsx index 8aa9386b7..a14e4e682 100644 --- a/client/packages/lowcoder/src/comps/index.tsx +++ b/client/packages/lowcoder/src/comps/index.tsx @@ -142,6 +142,7 @@ import { ResponsiveLayoutComp } from "./comps/responsiveLayout"; import { VideoMeetingStreamComp } from "./comps/meetingComp/videoMeetingStreamComp"; import { ControlButton } from "./comps/meetingComp/controlButton"; import { VideoMeetingControllerComp } from "./comps/meetingComp/videoMeetingControllerComp"; +import { VideoSharingStreamComp } from "./comps/meetingComp/videoSharingStreamComp"; type Registry = { [key in UICompType]?: UICompManifest; @@ -560,7 +561,17 @@ const uiCompMap: Registry = { }, defaultDataFn: defaultContainerData, }, - + //ADDED BY FRED + sharingcomponent: { + name: trans("meeting.sharingCompName"), + enName: "Sharing", + description: trans("meeting.sharingCompName"), + categories: ["meeting"], + icon: VideoCompIcon, + keywords: trans("meeting.meetingCompKeywords"), + comp: VideoSharingStreamComp, + withoutLoading: true, + }, videocomponent: { name: trans("meeting.videoCompName"), enName: "Video", @@ -581,6 +592,7 @@ const uiCompMap: Registry = { comp: ControlButton, withoutLoading: true, }, + //END tabbedContainer: { name: trans("uiComp.tabbedContainerCompName"), enName: "Tabbed Container", @@ -931,7 +943,7 @@ const uiCompMap: Registry = { layoutInfo: { w: 13, h: 55, - } + }, }, mention: { name: trans("uiComp.mentionCompName"), diff --git a/client/packages/lowcoder/src/comps/uiCompRegistry.ts b/client/packages/lowcoder/src/comps/uiCompRegistry.ts index c48be999e..54d0f5d2c 100644 --- a/client/packages/lowcoder/src/comps/uiCompRegistry.ts +++ b/client/packages/lowcoder/src/comps/uiCompRegistry.ts @@ -58,6 +58,7 @@ export type UICompType = | "chart" | "meeting" | "videocomponent" + | "sharingcomponent" | "controlButton" | "imageEditor" | "calendar" diff --git a/client/packages/lowcoder/src/i18n/locales/en.ts b/client/packages/lowcoder/src/i18n/locales/en.ts index c061179ef..dd94e3b2b 100644 --- a/client/packages/lowcoder/src/i18n/locales/en.ts +++ b/client/packages/lowcoder/src/i18n/locales/en.ts @@ -860,6 +860,7 @@ export const en = { audioCompDesc: "Audio component", audioCompKeywords: "", videoCompName: "Video", + sharingCompName: "Sharing", videoCompDesc: "Video component", videoCompKeywords: "", drawerCompName: "Drawer", @@ -1464,8 +1465,8 @@ export const en = { meetingName: "Meeting Name", localUserID: "Host User Id", userName: "Host User Name", - rtmToken : "Agora RTM Token", - rtcToken : "Agora RTC Token", + rtmToken: "Agora RTM Token", + rtcToken: "Agora RTC Token", videoCompText: "No video Text", profileImageUrl: "Profile Image Url", right: "Right", @@ -1482,18 +1483,21 @@ export const en = { actionBtnDesc: "Action Button", broadCast: "BroadCast Messages", title: "Meeting Title", + //ADDED BY FRED meetingCompName: "Meeting Controller", + sharingCompName: "Video Share", videoCompName: "Video Stream", videoSharingCompName: "Screen Sharing", meetingControlCompName: "Controls Buttons", meetingCompDesc: "Meeting component", meetingCompControls: "Meeting control", meetingCompKeywords: "", + //END iconSize: "Icon Size", userId: "userId", roomId: "roomId", - meetingActive : "Ongoing Meeting", - messages : "Broadcasted Messages", + meetingActive: "Ongoing Meeting", + messages: "Broadcasted Messages", }, settings: { title: "Settings", diff --git a/client/packages/lowcoder/src/pages/editor/editorConstants.tsx b/client/packages/lowcoder/src/pages/editor/editorConstants.tsx index 8baf2944d..2820e14c9 100644 --- a/client/packages/lowcoder/src/pages/editor/editorConstants.tsx +++ b/client/packages/lowcoder/src/pages/editor/editorConstants.tsx @@ -88,6 +88,7 @@ export const CompStateIcon: { meeting: , mermaid: , videocomponent: , + sharingcomponent: , controlButton: , tabbedContainer: , modal: , From b83ae94fc43241c38ef893cb3fadc559789d1d8e Mon Sep 17 00:00:00 2001 From: FalkWolsky Date: Tue, 21 Nov 2023 13:17:09 +0100 Subject: [PATCH 2/2] Bunch of Frontend Fixes --- .../src/icons/icon-autocomplete-comp.svg | 21 +++++++++++++++- .../src/icons/icon-comment-comp.svg | 14 ++++++++++- .../src/icons/icon-mention-comp.svg | 21 +++++++++++++++- .../src/icons/icon-timeline-comp.svg | 24 ++++++++++++++++++- .../lowcoder-design/src/icons/icon-undo.svg | 13 +++++++--- .../packages/lowcoder/src/i18n/locales/en.ts | 18 +++++++------- .../src/pages/setting/idSource/list.tsx | 19 +++++++++++++++ 7 files changed, 115 insertions(+), 15 deletions(-) diff --git a/client/packages/lowcoder-design/src/icons/icon-autocomplete-comp.svg b/client/packages/lowcoder-design/src/icons/icon-autocomplete-comp.svg index dd882963a..505c59adb 100644 --- a/client/packages/lowcoder-design/src/icons/icon-autocomplete-comp.svg +++ b/client/packages/lowcoder-design/src/icons/icon-autocomplete-comp.svg @@ -1 +1,20 @@ - \ No newline at end of file + + + + + + + + + diff --git a/client/packages/lowcoder-design/src/icons/icon-comment-comp.svg b/client/packages/lowcoder-design/src/icons/icon-comment-comp.svg index b6828e6a0..5a737ee86 100644 --- a/client/packages/lowcoder-design/src/icons/icon-comment-comp.svg +++ b/client/packages/lowcoder-design/src/icons/icon-comment-comp.svg @@ -1 +1,13 @@ - \ No newline at end of file + + + + + + diff --git a/client/packages/lowcoder-design/src/icons/icon-mention-comp.svg b/client/packages/lowcoder-design/src/icons/icon-mention-comp.svg index 4c04c61e2..5b311e0b4 100644 --- a/client/packages/lowcoder-design/src/icons/icon-mention-comp.svg +++ b/client/packages/lowcoder-design/src/icons/icon-mention-comp.svg @@ -1 +1,20 @@ - \ No newline at end of file + + + + + + + + diff --git a/client/packages/lowcoder-design/src/icons/icon-timeline-comp.svg b/client/packages/lowcoder-design/src/icons/icon-timeline-comp.svg index 329690d6d..e47f5fc79 100644 --- a/client/packages/lowcoder-design/src/icons/icon-timeline-comp.svg +++ b/client/packages/lowcoder-design/src/icons/icon-timeline-comp.svg @@ -1 +1,23 @@ - \ No newline at end of file + + + + + + + + + + + + diff --git a/client/packages/lowcoder-design/src/icons/icon-undo.svg b/client/packages/lowcoder-design/src/icons/icon-undo.svg index e7296453f..a1199d1bb 100644 --- a/client/packages/lowcoder-design/src/icons/icon-undo.svg +++ b/client/packages/lowcoder-design/src/icons/icon-undo.svg @@ -1,3 +1,10 @@ - - - \ No newline at end of file + + + + + + diff --git a/client/packages/lowcoder/src/i18n/locales/en.ts b/client/packages/lowcoder/src/i18n/locales/en.ts index dd94e3b2b..d27c93108 100644 --- a/client/packages/lowcoder/src/i18n/locales/en.ts +++ b/client/packages/lowcoder/src/i18n/locales/en.ts @@ -1484,14 +1484,14 @@ export const en = { broadCast: "BroadCast Messages", title: "Meeting Title", //ADDED BY FRED - meetingCompName: "Meeting Controller", - sharingCompName: "Video Share", - videoCompName: "Video Stream", - videoSharingCompName: "Screen Sharing", - meetingControlCompName: "Controls Buttons", - meetingCompDesc: "Meeting component", - meetingCompControls: "Meeting control", - meetingCompKeywords: "", + meetingCompName: "Agora Meeting Controller", + sharingCompName: "Screen share Stream", + videoCompName: "Camera Stream", + videoSharingCompName: "Screen share Stream", + meetingControlCompName: "Control Button", + meetingCompDesc: "Meeting Component", + meetingCompControls: "Meeting Control", + meetingCompKeywords: "Agora Meeting, Web Meeting, Collaboration", //END iconSize: "Icon Size", userId: "userId", @@ -1846,6 +1846,8 @@ export const en = { preloadLibsEmpty: "No JavaScript libraries were added", preloadLibsAddBtn: "Add a library", saveSuccess: "Saved successfully", + AuthOrgTitle: "Workspace welcome Screen", + AuthOrgDescrition: "The URL for your users to Sign in to the current workspace.", }, branding: { title: "Branding", diff --git a/client/packages/lowcoder/src/pages/setting/idSource/list.tsx b/client/packages/lowcoder/src/pages/setting/idSource/list.tsx index 62f121ac0..353fba1a4 100644 --- a/client/packages/lowcoder/src/pages/setting/idSource/list.tsx +++ b/client/packages/lowcoder/src/pages/setting/idSource/list.tsx @@ -34,6 +34,7 @@ import { messageInstance, AddIcon } from "lowcoder-design"; import { currentOrgAdmin } from "../../../util/permissionUtils"; import CreateModal from "./createModal"; import _ from "lodash"; +import { HelpText } from "components/HelpText"; export const IdSourceList = (props: any) => { const user = useSelector(getUser); @@ -44,6 +45,18 @@ export const IdSourceList = (props: any) => { const [modalVisible, setModalVisible] = useState(false); const enableEnterpriseLogin = useSelector(selectSystemConfig)?.featureFlag?.enableEnterpriseLogin; + let protocol = window.location.protocol; + const port = window.location.port; + let currentDomain = window.location.hostname; + + // Show port only if it is not a standard port + if (port && port !== '80' && port !== '443') { + currentDomain += `:${port}`; + } + + const redirectUrl = encodeURIComponent(`${protocol}//${currentDomain}/apps`); + const loginUrl = `${protocol}//${currentDomain}/org/${currentOrgId}/auth/login?redirectUrl=${encodeURIComponent(redirectUrl)}`; + useEffect(() => { if (!currentOrgId) { return; @@ -154,6 +167,11 @@ export const IdSourceList = (props: any) => { )} /> + +
{trans("advanced.AuthOrgTitle")}
+ {trans("advanced.AuthOrgDescrition") + ": "} + {loginUrl} + { ); }; +