diff --git a/studio/src/components/Chat/DevBotFooter.tsx b/studio/src/components/Chat/DevBotFooter.tsx index 27db682..44512a1 100644 --- a/studio/src/components/Chat/DevBotFooter.tsx +++ b/studio/src/components/Chat/DevBotFooter.tsx @@ -1,6 +1,8 @@ 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 { @@ -20,7 +22,9 @@ 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(''); + const config = useConfig(); React.useEffect(() => { if (props.inputText) { @@ -35,17 +39,65 @@ 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 ( + {config.features["devFooter.uploadFiles"] && + + { window.event?.stopImmediatePropagation(); fileInput?.current?.click(); }} className='primary-button'>{t('devFooter.uploadFiles')} + + } - - { window.event?.stopImmediatePropagation(); fileInput?.current?.click(); }} className='primary-button'>Upload Files - - - props.pluginStoreToggle()} className='primary-button'>Add Plugin + props.pluginStoreToggle()} className='primary-button'>{t('devFooter.addPlugin')} 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/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..ad734ad --- /dev/null +++ b/studio/src/locales/config.json @@ -0,0 +1,17 @@ +{ + "features":{ + "dslFileUpload": true, + "publishModal.publishButton": true, + "devFooter.uploadFiles": true, + "editorPage.devModeHeader": true, + "representation.nlr":true, + "representation.chart": true, + "representation.dsl": true, + "representation.code": false, + "error.errors": true, + "error.warnings": true, + "error.optimizations": true, + "error.botExperience": true + + } +} \ 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..1445bd6 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 +541,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 +660,7 @@ export const EditorPage: React.FunctionComponent = () => { ) + } export default EditorPage; \ No newline at end of file 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')}