From a23f20400876acb74c4b4d34ae6848fbfdf1ceba Mon Sep 17 00:00:00 2001 From: kanak8278 Date: Sun, 4 Aug 2024 11:01:14 +0530 Subject: [PATCH 1/6] feat: Add i18n support for DevBotFooter component --- studio/src/components/Chat/DevBotFooter.tsx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/studio/src/components/Chat/DevBotFooter.tsx b/studio/src/components/Chat/DevBotFooter.tsx index 27db682..68148d3 100644 --- a/studio/src/components/Chat/DevBotFooter.tsx +++ b/studio/src/components/Chat/DevBotFooter.tsx @@ -1,5 +1,6 @@ import '@/styles/components/DevBotFooter.scss'; import { DefaultButton, IconButton, Stack, TextField, makeStyles } from "@fluentui/react"; +import { useTranslation } from 'react-i18next'; import React from "react"; @@ -20,6 +21,7 @@ const devbotfooterStyles = makeStyles(theme => ({ export const DevBotFooter = (props: props) => { const fileInput = React.createRef(); const classStyles = devbotfooterStyles(); + const { t, i18n} = useTranslation(); const [message, setMessage] = React.useState(''); React.useEffect(() => { @@ -42,10 +44,10 @@ export const DevBotFooter = (props: props) => { - { window.event?.stopImmediatePropagation(); fileInput?.current?.click(); }} className='primary-button'>Upload Files + { window.event?.stopImmediatePropagation(); fileInput?.current?.click(); }} className='primary-button'>{t('devFooter.uploadFiles')} - props.pluginStoreToggle()} className='primary-button'>Add Plugin + props.pluginStoreToggle()} className='primary-button'>{t('devFooter.addPlugin')} From 3bbc554a6ddd7bdfdfadc4d9089bbe0eef507353 Mon Sep 17 00:00:00 2001 From: kanak8278 Date: Sun, 4 Aug 2024 11:02:11 +0530 Subject: [PATCH 2/6] feat: Add useConfig hook for retrieving configuration data to selectively render react components --- studio/src/hooks/useConfig.js | 14 ++ studio/src/locales/config.json | 17 +++ studio/src/locales/en.json | 8 +- studio/src/pages/editor-page.tsx | 232 +++++++++++++++++++++++++++++-- 4 files changed, 255 insertions(+), 16 deletions(-) create mode 100644 studio/src/hooks/useConfig.js create mode 100644 studio/src/locales/config.json diff --git a/studio/src/hooks/useConfig.js b/studio/src/hooks/useConfig.js new file mode 100644 index 0000000..e8106ee --- /dev/null +++ b/studio/src/hooks/useConfig.js @@ -0,0 +1,14 @@ +import { useState, useEffect } from 'react'; +import config from '../locales/config.json'; + +const useConfig = () => { + const [configData, setConfigData] = useState(null); + + useEffect(() => { + setConfigData(config); + }, []); + + return configData; +}; + +export default useConfig; diff --git a/studio/src/locales/config.json b/studio/src/locales/config.json new file mode 100644 index 0000000..3d521dd --- /dev/null +++ b/studio/src/locales/config.json @@ -0,0 +1,17 @@ +{ + "features":{ + "dslFileUpload": false, + "publishModal.publishButton": true, + "devFooter.uploadFiles": false, + "editorPage.devModeHeader": false, + "representations.nlr":true, + "representations.chart": true, + "representations.dsl": false, + "representations.code": false, + "error.errors": true, + "error.warnings": true, + "error.optimizations": false, + "error.botExperience": false + + } +} \ No newline at end of file diff --git a/studio/src/locales/en.json b/studio/src/locales/en.json index 9199e2b..9f5caab 100644 --- a/studio/src/locales/en.json +++ b/studio/src/locales/en.json @@ -29,5 +29,11 @@ "publishModal.installationURL": "Get your project online", "publishModal.installationSecret": "Secret Key", "representations.editModeAlert": "Please submit or discard your changes before switching representations.", - "representations.title": "Representations" + "representations.title": "Representations", + "devFooter.addPlugin": "Add Plugins", + "devFooter.uploadFiles": "Upload Files", + "errors.errors": "Error", + "errors.warnings": "Warnings", + "errors.optimizations": "Optimize", + "errors.botExperience": "Bot Experience" } \ No newline at end of file diff --git a/studio/src/pages/editor-page.tsx b/studio/src/pages/editor-page.tsx index bfb6068..60ce880 100644 --- a/studio/src/pages/editor-page.tsx +++ b/studio/src/pages/editor-page.tsx @@ -14,6 +14,7 @@ import RepView from '../components/Representations/RepView'; import TestBot from '../components/Chat/TestBot'; import { useTranslation } from 'react-i18next'; import PublishModal from '../components/PublishModal'; +import useConfig from '../hooks/useConfig'; const boldHeaderStyle: Partial = { root: { fontWeight: FontWeights.semibold, color: '#696969' } }; @@ -79,6 +80,7 @@ export const EditorPage: React.FunctionComponent = () => { const fileInput = React.createRef(); const [dslImportLoader, setDslImportLoader] = React.useState(false); const [resetTestChat, setResetTestChat] = React.useState(false); + const config = useConfig(); React.useEffect(() => { if (token && params.id) { @@ -91,7 +93,7 @@ export const EditorPage: React.FunctionComponent = () => { }).catch((error) => { console.log(error) if (error?.status === 403) { - alert(t('unauthorizedAccess')); + alert(t("unauthorizedAccess")); window.location.href = `#/home`; } }) @@ -275,7 +277,194 @@ export const EditorPage: React.FunctionComponent = () => { ) } } - + if (!config){ + return ( + + + + + + + + + Features + + + hidePluginStore()} + /> + + + + + + + + + + + window.location.href = '/#/home' }> + {t('appName')} + + + {projectDetails?.name} + + + + + { window.event?.stopImmediatePropagation(); fileInput?.current?.click(); }}>{t("dslFileUpload")}  {dslImportLoader && } + + + + {t('publishModal.publishButton')} + + + + + + + + + + {representations && representations.map((item: any, index: number) => { + return renderRep(item, index) + + }) + } + + { instance.logoutPopup(); window.location.href = `#/` } } iconProps={{ iconName: 'PowerButton' }} title={t('logout')} ariaLabel={t('logout')} /> + + + + + + + + + + + + + + {t("errors.errors")} + + + {programState?.errors || 0} + + + + + + + {t("errors.warnings")} + + + {programState?.warnings || 0} + + + + + + + {t("errors.optimizations")} + + + {programState?.optimizations || 0} + + + + + + + {t("errors.botExperience")} + + + {programState?.botExperience || 0} + + + + + + + + + + + + + + + { + setChatMode(item?.props.itemKey || 'DevMode') + }} + className={chatModeClass()} styles={chatModePivotStyle}> + {chatModes.map((item, index) => { + return ( + + ) + })} + + + + {}, + }, + { + key: 'callbackFrom', + name: t('callbackFrom'), + iconProps: { iconName: 'FormLibrary' }, + onclick: () => {} + }, + { + key: 'clearData', + name: t('resetChat'), + iconProps: { iconName: 'Rerun' }, + onClick: () => { + setResetTestChat(true); + }, + } + ]} + onRenderOverflowButton={onRenderOverflowButton} + onRenderItem={() => {}} + /> + + + + +
+ setRefreshIR(refreshIR + 1) } pluginStoreToggle={showPluginStore} userId={userId} setOnlineState={setDevChatStatus} id={params.id} token={token} /> +
+
+ +
+
+
+
+
+
+
+ ) + + } return ( @@ -291,7 +480,7 @@ export const EditorPage: React.FunctionComponent = () => { - Features + Features { window.location.href = '/#/home' }> - PwR Studio + {t('appName')} {projectDetails?.name} + {config.features['dslFileUpload'] && { window.event?.stopImmediatePropagation(); fileInput?.current?.click(); }}>{t("dslFileUpload")}  {dslImportLoader && } + } + { + config.features["publishModal.publishButton"] && - Publish + {t('publishModal.publishButton')} + } @@ -348,50 +542,57 @@ export const EditorPage: React.FunctionComponent = () => { - + { config.features["error.errors"] && - Errors + {t("errors.errors")} {programState?.errors || 0} + {config.features["error.warnings"] && - Warnings + {t("errors.warnings")} {programState?.warnings || 0} - + } + {config.features["error.optimizations"] && + - Optimize + {t("errors.optimizations")} {programState?.optimizations || 0} - - + + } + {config.features["error.botExperience"] && + - Bot Experience + {t("errors.botExperience")} {programState?.botExperience || 0} - + + } - + + } @@ -460,6 +661,7 @@ export const EditorPage: React.FunctionComponent = () => { ) + } export default EditorPage; \ No newline at end of file From ab8026faf7028d50bbc64ea99dde53ee346d6764 Mon Sep 17 00:00:00 2001 From: kanak8278 Date: Sun, 4 Aug 2024 11:04:33 +0530 Subject: [PATCH 3/6] feat: Enable DSL file upload, dev mode header, and code representations --- studio/src/locales/config.json | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/studio/src/locales/config.json b/studio/src/locales/config.json index 3d521dd..bbce9b9 100644 --- a/studio/src/locales/config.json +++ b/studio/src/locales/config.json @@ -1,17 +1,17 @@ { "features":{ - "dslFileUpload": false, + "dslFileUpload": true, "publishModal.publishButton": true, - "devFooter.uploadFiles": false, - "editorPage.devModeHeader": false, + "devFooter.uploadFiles": true, + "editorPage.devModeHeader": true, "representations.nlr":true, "representations.chart": true, - "representations.dsl": false, - "representations.code": false, + "representations.dsl": true, + "representations.code": true, "error.errors": true, "error.warnings": true, - "error.optimizations": false, - "error.botExperience": false + "error.optimizations": true, + "error.botExperience": true } } \ No newline at end of file From fc9117be9116d267a3be7ba43cfdc4ee2e4e6f27 Mon Sep 17 00:00:00 2001 From: kanak8278 Date: Sun, 4 Aug 2024 11:16:31 +0530 Subject: [PATCH 4/6] feat: DSL file upload button in editor page --- studio/src/pages/editor-page.tsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/studio/src/pages/editor-page.tsx b/studio/src/pages/editor-page.tsx index 60ce880..1445bd6 100644 --- a/studio/src/pages/editor-page.tsx +++ b/studio/src/pages/editor-page.tsx @@ -507,8 +507,7 @@ export const EditorPage: React.FunctionComponent = () => { - {config.features['dslFileUpload'] && - + {config.features["dslFileUpload"] && { window.event?.stopImmediatePropagation(); fileInput?.current?.click(); }}>{t("dslFileUpload")}  {dslImportLoader && } From c83e120914e49ffe60823baab3956d64518163a0 Mon Sep 17 00:00:00 2001 From: kanak8278 Date: Mon, 5 Aug 2024 10:29:34 +0530 Subject: [PATCH 5/6] Updated config.json --- studio/src/components/Representations/RepView.tsx | 6 +++++- studio/src/locales/config.json | 8 ++++---- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/studio/src/components/Representations/RepView.tsx b/studio/src/components/Representations/RepView.tsx index 1fcfc89..acf5dd8 100644 --- a/studio/src/components/Representations/RepView.tsx +++ b/studio/src/components/Representations/RepView.tsx @@ -6,13 +6,14 @@ import ReactMarkdown from 'react-markdown'; import gfm from 'remark-gfm'; import MermaidChart from "../Mermaid"; import '../../styles/markdownStyles.css'; +import useConfig from "../../hooks/useConfig"; interface props { representation: any; token: string; } export const RepView = (props: props) => { - + const config = useConfig(); const stackStyle: IStackStyles = { root: { paddingLeft: '10px', @@ -39,6 +40,9 @@ export const RepView = (props: props) => { }; const renderRepresentation = (representation: any) => { + if (!config){ + return null; + } if (representation?.name === 'code') { return ( ) diff --git a/studio/src/locales/config.json b/studio/src/locales/config.json index bbce9b9..ad734ad 100644 --- a/studio/src/locales/config.json +++ b/studio/src/locales/config.json @@ -4,10 +4,10 @@ "publishModal.publishButton": true, "devFooter.uploadFiles": true, "editorPage.devModeHeader": true, - "representations.nlr":true, - "representations.chart": true, - "representations.dsl": true, - "representations.code": true, + "representation.nlr":true, + "representation.chart": true, + "representation.dsl": true, + "representation.code": false, "error.errors": true, "error.warnings": true, "error.optimizations": true, From aca8616418b65801966090ff06ae7731ebfc2a2f Mon Sep 17 00:00:00 2001 From: kanak8278 Date: Tue, 6 Aug 2024 15:42:53 +0530 Subject: [PATCH 6/6] feat: Add lazy loading for images in DevBotFooter component --- studio/src/components/Chat/DevBotFooter.tsx | 58 +++++- studio/src/pages/home-page.tsx | 208 ++++++++++++++++++-- 2 files changed, 250 insertions(+), 16 deletions(-) diff --git a/studio/src/components/Chat/DevBotFooter.tsx b/studio/src/components/Chat/DevBotFooter.tsx index 68148d3..44512a1 100644 --- a/studio/src/components/Chat/DevBotFooter.tsx +++ b/studio/src/components/Chat/DevBotFooter.tsx @@ -2,6 +2,7 @@ import '@/styles/components/DevBotFooter.scss'; import { DefaultButton, IconButton, Stack, TextField, makeStyles } from "@fluentui/react"; import { useTranslation } from 'react-i18next'; import React from "react"; +import useConfig from '../../hooks/useConfig'; interface props { @@ -23,6 +24,7 @@ export const DevBotFooter = (props: props) => { const classStyles = devbotfooterStyles(); const { t, i18n} = useTranslation(); const [message, setMessage] = React.useState(''); + const config = useConfig(); React.useEffect(() => { if (props.inputText) { @@ -37,15 +39,63 @@ export const DevBotFooter = (props: props) => { } }, [props.inputText]); + if (!config) { + return ( + + + + + + { window.event?.stopImmediatePropagation(); fileInput?.current?.click(); }} className='primary-button'>{t('devFooter.uploadFiles')} + + + props.pluginStoreToggle()} className='primary-button'>{t('devFooter.addPlugin')} + + + + + + + { + if (props.disableSend) { return; } + if (e.key === 'Enter') { + props.sendMessageToWss(message); + setMessage(''); + } + } + } + onChange={(e, value) => { setMessage(value || '') }} + type="text" + placeholder="Type your message here..." + multiline={true} + resizable={false} + onRenderSuffix={() => { + return ( { if (props.disableSend) { return; } props.sendMessageToWss(message); setMessage('') }} + iconProps={{'iconName': 'Send'}} title="Emoji" ariaLabel="Emoji" />) + }} + /> + + + + + + ) + } return ( - - - { window.event?.stopImmediatePropagation(); fileInput?.current?.click(); }} className='primary-button'>{t('devFooter.uploadFiles')} - + {config.features["devFooter.uploadFiles"] && + + { window.event?.stopImmediatePropagation(); fileInput?.current?.click(); }} className='primary-button'>{t('devFooter.uploadFiles')} + + } props.pluginStoreToggle()} className='primary-button'>{t('devFooter.addPlugin')} diff --git a/studio/src/pages/home-page.tsx b/studio/src/pages/home-page.tsx index 1b52cf3..3f3c763 100644 --- a/studio/src/pages/home-page.tsx +++ b/studio/src/pages/home-page.tsx @@ -11,6 +11,7 @@ import { APIHost } from '../constants'; import moment from 'moment'; import { appInsights } from '../applicationInsightsService'; import logo from './images/logo.png'; +import useConfig from '../hooks/useConfig'; export const HomePage: React.FunctionComponent = () => { @@ -38,6 +39,7 @@ export const HomePage: React.FunctionComponent = () => { const [token, setToken] = React.useState(null); const [shareProjectId, setProjectId] = React.useState(''); const fileInput = React.createRef(); + const config = useConfig(); const onSearch = (query:string) => { const filtered = projects.filter((item:any) => @@ -293,6 +295,186 @@ export const HomePage: React.FunctionComponent = () => { copyTemplateValues.dsl.name = file.name; } } + if (!config){ + return ( + + { toggleModal(null) }} + isBlocking={false} + containerClassName={'modal-container'} + > +
+
+ {t('createNewProject')} +
+ { toggleModal(null) }} + /> +
+
+ {serverMessage.message && + { setServerMessage({ message: '', type: '' }) }} + isMultiline={false} + dismissButtonAriaLabel="Close" + > + {serverMessage.message} + + } + { copyTemplateValues.name = value || '' }} defaultValue={copyTemplateValues.name} /> + { copyTemplateValues.description = value || '' }} defaultValue={copyTemplateValues.description} multiline resizable={false} /> + +
 
+ + {t('homePage.dslFileUploadMessage')} + + + + +
+
+ copyTemplate(copyTemplateValues)}> + Create + + { toggleModal(null) }} /> +
+ +
+ { toggleModal(null) }} + isBlocking={false} + containerClassName="modal-container" + > +
+
+ {t('shareProject')} +
+ { toggleModal(null) }} + /> +
+
+ {serverMessage.message && + { setServerMessage({ message: '', type: '' }) }} + isMultiline={false} + dismissButtonAriaLabel="Close" + > + {serverMessage.message} + + } + { setEmail(value || '') }} /> +
+
+ shareProject()}> + Share Project + + { toggleModal(null) }} /> +
+
+ + + + {t('appName')} + + + + + + + + + { instance.logoutPopup(); window.location.href = `#/` } } iconProps={{ iconName: 'SignOut' }} title={t('logout')} ariaLabel={t('logout')} /> + + + + + + + + + onSearch(newValue || '')} + onSearch={onSearch} + onClear={() => onSearch('')} + /> + + + { onActionClick(ev) }} className={'secondary-button'}>{t('createNewProject')} + + + + + {filteredProjects.map((project: any, index: number) => { + return ( + clickAction(project)} className={'project-item'} key={index}> + + + + + + {project.name}
+
+ + Created on {moment(project.created_at).format("Do MMM YY")} + +
+
+ + + + openShareProject(project, ev)} + /> + + + { deleteProject(project, ev); } } title={t("delete")} ariaLabel={t("delete")} /> + + + +
+
+ +
{project.description}
+
+
+ ) + })} +
+
+
+
+
+
+ ) + + } return ( @@ -329,20 +511,22 @@ export const HomePage: React.FunctionComponent = () => { { copyTemplateValues.description = value || '' }} defaultValue={copyTemplateValues.description} multiline resizable={false} />
 
- + {config.features["dslFileUpload"] && {t('homePage.dslFileUploadMessage')} - - - } + {config.features["dslFileUpload"] && } + {config.features["dslFileUpload"] && + + + }
copyTemplate(copyTemplateValues)}> @@ -393,7 +577,7 @@ export const HomePage: React.FunctionComponent = () => { - PwR Studio + {t('appName')}