rm ai chat
|
@ -0,0 +1,32 @@
|
|||
npm run build
|
||||
|
||||
# create zip file of build folder
|
||||
|
||||
zip -r build.zip build
|
||||
|
||||
# connect to server to clear folder
|
||||
|
||||
ssh root@93.177.67.38 << EOF
|
||||
cd /var/www/html/navilearn-dashboard-web/
|
||||
rm -rf *
|
||||
exit
|
||||
EOF
|
||||
|
||||
# copy zip file to server
|
||||
|
||||
scp build.zip root@93.177.67.38:/var/www/html/navilearn-dashboard-web/
|
||||
|
||||
# connect to server
|
||||
|
||||
ssh root@93.177.67.38 << EOF
|
||||
cd /var/www/html/navilearn-dashboard-web/
|
||||
unzip build.zip
|
||||
mv /var/www/html/navilearn-dashboard-web/build/* /var/www/html/navilearn-dashboard-web/
|
||||
rm -rf /var/www/html/navilearn-dashboard-web/build
|
||||
rm build.zip
|
||||
exit
|
||||
EOF
|
||||
|
||||
# remove zip file from local machine
|
||||
|
||||
rm build.zip
|
After Width: | Height: | Size: 16 KiB |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 2.0 KiB |
Before Width: | Height: | Size: 3.8 KiB After Width: | Height: | Size: 15 KiB |
|
@ -5,39 +5,43 @@
|
|||
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<meta name="theme-color" content="#000000" />
|
||||
<meta
|
||||
name="description"
|
||||
content="Web site created using create-react-app"
|
||||
/>
|
||||
<meta name="description" content="Dashboard for NaviLearn" />
|
||||
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
|
||||
<!--
|
||||
manifest.json provides metadata used when your web app is installed on a
|
||||
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
|
||||
-->
|
||||
<link
|
||||
rel="apple-touch-icon"
|
||||
sizes="180x180"
|
||||
href="%PUBLIC_URL%/apple-touch-icon.png"
|
||||
/>
|
||||
<link
|
||||
rel="icon"
|
||||
type="image/png"
|
||||
sizes="32x32"
|
||||
href="%PUBLIC_URL%/favicon-32x32.png"
|
||||
/>
|
||||
<link rel="icon" type="image/png" sizes="16x16"
|
||||
href=%PUBLIC_URL%"/favicon-16x16.png">
|
||||
<meta name="msapplication-TileColor" content="#da532c" />
|
||||
<meta name="theme-color" content="#ffffff" />
|
||||
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
|
||||
<!--
|
||||
Notice the use of %PUBLIC_URL% in the tags above.
|
||||
It will be replaced with the URL of the `public` folder during the build.
|
||||
Only files inside the `public` folder can be referenced from the HTML.
|
||||
<title>NaviLearn</title>
|
||||
|
||||
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
|
||||
work correctly both with client-side routing and a non-root public URL.
|
||||
Learn how to configure a non-root public URL by running `npm run build`.
|
||||
-->
|
||||
<title>App</title>
|
||||
<script type="text/javascript">
|
||||
(function (c, l, a, r, i, t, y) {
|
||||
c[a] =
|
||||
c[a] ||
|
||||
function () {
|
||||
(c[a].q = c[a].q || []).push(arguments);
|
||||
};
|
||||
t = l.createElement(r);
|
||||
t.async = 1;
|
||||
t.src = "https://www.clarity.ms/tag/" + i;
|
||||
y = l.getElementsByTagName(r)[0];
|
||||
y.parentNode.insertBefore(t, y);
|
||||
})(window, document, "clarity", "script", "o4tg2haxvt");
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<noscript>You need to enable JavaScript to run this app.</noscript>
|
||||
<div id="root"></div>
|
||||
<!--
|
||||
This HTML file is a template.
|
||||
If you open it directly in the browser, you will see an empty page.
|
||||
|
||||
You can add webfonts, meta tags, or analytics to this file.
|
||||
The build step will place the bundled scripts into the <body> tag.
|
||||
|
||||
To begin the development, run `npm start` or `yarn start`.
|
||||
To create a production bundle, use `npm run build` or `yarn build`.
|
||||
-->
|
||||
</body>
|
||||
</html>
|
||||
|
|
Before Width: | Height: | Size: 5.2 KiB After Width: | Height: | Size: 18 KiB |
Before Width: | Height: | Size: 9.4 KiB After Width: | Height: | Size: 103 KiB |
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"short_name": "React App",
|
||||
"name": "Create React App Sample",
|
||||
"short_name": "NaviLearn",
|
||||
"name": "NaviLearn",
|
||||
"icons": [
|
||||
{
|
||||
"src": "favicon.ico",
|
||||
|
|
After Width: | Height: | Size: 12 KiB |
180
src/App.tsx
|
@ -1,78 +1,124 @@
|
|||
import { ConfigProvider, Layout, theme } from 'antd';
|
||||
import DashboardLayout from './core/components/DashboardLayout';
|
||||
import { darkMode, primaryColor, setBannerUrl, setLogoUrl, setPrimaryColor, setUserAuthenticated, userAuthenticated, setUserProfilePictureUrl } from './core/reducers/appSlice';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import SignIn from './features/Auth/SignIn';
|
||||
import { useEffect } from 'react';
|
||||
import { myFetch } from './core/utils/utils';
|
||||
import MyCenteredSpin from './shared/components/MyCenteredSpin';
|
||||
import webSocketService, { WebSocketMessageHandler } from 'core/services/websocketService';
|
||||
import { MessageProvider } from 'core/context/MessageContext';
|
||||
import { ConfigProvider, Layout, theme } from "antd";
|
||||
import DashboardLayout from "./core/components/DashboardLayout";
|
||||
import {
|
||||
darkMode,
|
||||
primaryColor,
|
||||
setBannerUrl,
|
||||
setLogoUrl,
|
||||
setPrimaryColor,
|
||||
setUserAuthenticated,
|
||||
userAuthenticated,
|
||||
setUserProfilePictureUrl,
|
||||
} from "./core/reducers/appSlice";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import SignIn from "./features/Auth/SignIn";
|
||||
import { useEffect } from "react";
|
||||
import { myFetch } from "./core/utils/utils";
|
||||
import MyCenteredSpin from "./shared/components/MyCenteredSpin";
|
||||
import webSocketService, {
|
||||
WebSocketMessageHandler,
|
||||
} from "core/services/websocketService";
|
||||
import { MessageProvider } from "core/context/MessageContext";
|
||||
|
||||
const { defaultAlgorithm, darkAlgorithm } = theme;
|
||||
|
||||
export default function App() {
|
||||
const dispatch = useDispatch();
|
||||
const dispatch = useDispatch();
|
||||
|
||||
const isDarkMode = useSelector(darkMode);
|
||||
const uAuthenticated = useSelector(userAuthenticated);
|
||||
const primColor = useSelector(primaryColor);
|
||||
const isDarkMode = useSelector(darkMode);
|
||||
const uAuthenticated = useSelector(userAuthenticated);
|
||||
const primColor = useSelector(primaryColor);
|
||||
|
||||
console.info(
|
||||
'\n %c LMS %c v1.0.0 %c \n',
|
||||
'background-color: #555;color: #fff;padding: 3px 2px 3px 3px;border-radius: 3px 0 0 3px;font-family: DejaVu Sans,Verdana,Geneva,sans-serif;text-shadow: 0 1px 0 rgba(1, 1, 1, 0.3)',
|
||||
'background-color: #bc81e0;background-image: linear-gradient(90deg, #e67e22, #9b59b6);color: #fff;padding: 3px 3px 3px 2px;border-radius: 0 3px 3px 0;font-family: DejaVu Sans,Verdana,Geneva,sans-serif;text-shadow: 0 1px 0 rgba(1, 1, 1, 0.3)',
|
||||
'background-color: transparent'
|
||||
);
|
||||
console.info(
|
||||
"\n %c LMS %c v1.0.0 %c \n",
|
||||
"background-color: #555;color: #fff;padding: 3px 2px 3px 3px;border-radius: 3px 0 0 3px;font-family: DejaVu Sans,Verdana,Geneva,sans-serif;text-shadow: 0 1px 0 rgba(1, 1, 1, 0.3)",
|
||||
"background-color: #bc81e0;background-image: linear-gradient(90deg, #e67e22, #9b59b6);color: #fff;padding: 3px 3px 3px 2px;border-radius: 0 3px 3px 0;font-family: DejaVu Sans,Verdana,Geneva,sans-serif;text-shadow: 0 1px 0 rgba(1, 1, 1, 0.3)",
|
||||
"background-color: transparent"
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (uAuthenticated) {
|
||||
(async () => {
|
||||
try {
|
||||
const response = await myFetch({
|
||||
url: '/app',
|
||||
method: 'GET',
|
||||
});
|
||||
useEffect(() => {
|
||||
if (uAuthenticated) {
|
||||
(async () => {
|
||||
try {
|
||||
const response = await myFetch({
|
||||
url: "/app",
|
||||
method: "GET",
|
||||
});
|
||||
|
||||
if (response) {
|
||||
dispatch(setPrimaryColor(`#${response.Organization.PrimaryColor}`));
|
||||
dispatch(setLogoUrl(response.Organization.LogoUrl));
|
||||
dispatch(setBannerUrl(response.Organization.BannerUrl));
|
||||
dispatch(setUserProfilePictureUrl(response.User.ProfilePictureUrl));
|
||||
dispatch(setUserAuthenticated(true));
|
||||
|
||||
webSocketService.connect();
|
||||
webSocketService.setHandler(WebSocketMessageHandler, dispatch);
|
||||
}
|
||||
} catch (error) {}
|
||||
})();
|
||||
|
||||
return () => {
|
||||
webSocketService.disconnect();
|
||||
};
|
||||
}
|
||||
}, [uAuthenticated]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!localStorage.getItem('session')) {
|
||||
dispatch(setUserAuthenticated(false));
|
||||
} else {
|
||||
if (response) {
|
||||
dispatch(setPrimaryColor(`#${response.Organization.PrimaryColor}`));
|
||||
dispatch(setLogoUrl(response.Organization.LogoUrl));
|
||||
dispatch(setBannerUrl(response.Organization.BannerUrl));
|
||||
dispatch(setUserProfilePictureUrl(response.User.ProfilePictureUrl));
|
||||
dispatch(setUserAuthenticated(true));
|
||||
}
|
||||
}, [dispatch]);
|
||||
|
||||
return (
|
||||
<Layout style={{ minHeight: '100vh' }}>
|
||||
<ConfigProvider
|
||||
theme={{
|
||||
algorithm: isDarkMode ? darkAlgorithm : defaultAlgorithm,
|
||||
token: {
|
||||
colorPrimary: primColor,
|
||||
},
|
||||
}}
|
||||
>
|
||||
<MessageProvider>{uAuthenticated == null ? <MyCenteredSpin /> : uAuthenticated ? <DashboardLayout /> : <SignIn />}</MessageProvider>
|
||||
</ConfigProvider>
|
||||
</Layout>
|
||||
);
|
||||
webSocketService.connect();
|
||||
webSocketService.setHandler(WebSocketMessageHandler, dispatch);
|
||||
}
|
||||
} catch (error) {}
|
||||
})();
|
||||
|
||||
return () => {
|
||||
webSocketService.disconnect();
|
||||
};
|
||||
}
|
||||
}, [uAuthenticated]);
|
||||
|
||||
useEffect(() => {
|
||||
const query = new URLSearchParams(window.location.search);
|
||||
|
||||
if (!localStorage.getItem("session") && !query.has("s")) {
|
||||
dispatch(setUserAuthenticated(false));
|
||||
} else if (query.has("s")) {
|
||||
const searchParam = query.get("s");
|
||||
|
||||
if (searchParam) {
|
||||
localStorage.setItem("session", searchParam);
|
||||
|
||||
window.history.replaceState(
|
||||
{},
|
||||
document.title,
|
||||
window.location.pathname
|
||||
);
|
||||
|
||||
dispatch(setUserAuthenticated(true));
|
||||
} else {
|
||||
dispatch(setUserAuthenticated(false));
|
||||
}
|
||||
} else {
|
||||
dispatch(setUserAuthenticated(true));
|
||||
}
|
||||
}, [dispatch]);
|
||||
|
||||
useEffect(() => {
|
||||
const plScript = document.createElement("script");
|
||||
plScript.src = "https://anal.jannex.de/js/script.js";
|
||||
plScript.async = true;
|
||||
plScript.defer = true;
|
||||
plScript.setAttribute("data-domain", "dashboard.navilearn.io");
|
||||
document.head.appendChild(plScript);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<Layout style={{ minHeight: "100vh" }}>
|
||||
<ConfigProvider
|
||||
theme={{
|
||||
algorithm: isDarkMode ? darkAlgorithm : defaultAlgorithm,
|
||||
token: {
|
||||
colorPrimary: primColor,
|
||||
},
|
||||
}}
|
||||
>
|
||||
<MessageProvider>
|
||||
{uAuthenticated == null ? (
|
||||
<MyCenteredSpin />
|
||||
) : uAuthenticated ? (
|
||||
<DashboardLayout />
|
||||
) : (
|
||||
<SignIn />
|
||||
)}
|
||||
</MessageProvider>
|
||||
</ConfigProvider>
|
||||
</Layout>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -51,7 +51,7 @@ export default function DashboardLayout() {
|
|||
|
||||
<PageContent />
|
||||
|
||||
<AiChat />
|
||||
{/* <AiChat /> */}
|
||||
</Layout>
|
||||
</Layout>
|
||||
</MyDndContext>
|
||||
|
|
|
@ -7,9 +7,25 @@ import { getUserSessionFromLocalStorage } from 'core/utils/utils';
|
|||
import { Marked, marked } from 'marked';
|
||||
import { createDirectives, presetDirectiveConfigs } from 'marked-directive';
|
||||
|
||||
interface MessageContent {
|
||||
role?: string;
|
||||
text?: string;
|
||||
files?: any[];
|
||||
html?: string;
|
||||
}
|
||||
|
||||
let chatHistory: MessageContent[] = [
|
||||
{
|
||||
text: 'Hallo! Ich bin ein Chatbot. Stell mir Fragen :)',
|
||||
role: 'ai',
|
||||
},
|
||||
];
|
||||
|
||||
function AiChat() {
|
||||
const [visible, setVisible] = React.useState(false);
|
||||
|
||||
//const [chatHistory, setChatHistory] = React.useState<MessageContent[]>([{ text: 'Stell mir Fragen :)', role: 'ai' }]);
|
||||
|
||||
return (
|
||||
<>
|
||||
{visible ? (
|
||||
|
@ -35,7 +51,13 @@ function AiChat() {
|
|||
position: 'absolute',
|
||||
}}
|
||||
avatars={true}
|
||||
history={[{ text: 'Stell mir Fragen :)', role: 'ai' }]}
|
||||
history={chatHistory}
|
||||
onMessage={(message) => {
|
||||
if (message.isHistory) return;
|
||||
|
||||
//setChatHistory([...chatHistory, message.message]);
|
||||
chatHistory.push(message.message);
|
||||
}}
|
||||
connect={{
|
||||
url: '/api/chat/v1/prompt/',
|
||||
method: 'POST',
|
||||
|
@ -63,6 +85,11 @@ function AiChat() {
|
|||
},
|
||||
},
|
||||
}}
|
||||
requestInterceptor={async (requestDetails) => {
|
||||
console.log(requestDetails); // printed above
|
||||
requestDetails.body.isFirstMessage = chatHistory.length <= 1;
|
||||
return requestDetails;
|
||||
}}
|
||||
responseInterceptor={async (response: any) => {
|
||||
let _response = { ...response };
|
||||
|
||||
|
|
|
@ -6,13 +6,13 @@
|
|||
background-position: center;
|
||||
background-repeat: no-repeat;
|
||||
background-size: cover;
|
||||
height: 100%;
|
||||
height: 100vh;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.darkenBackground {
|
||||
position: absolute;
|
||||
background-color: rgba(0, 0, 0, 0.5);
|
||||
height: 100%;
|
||||
height: 100vh;
|
||||
width: 100%;
|
||||
}
|
||||
|
|
|
@ -412,7 +412,7 @@ function SubdomainCard({
|
|||
message: t(
|
||||
"organizationSettings.subdomainCard.rules.minLength",
|
||||
{
|
||||
min: Constants.GLOBALS.MIN_SUBDOMAIN_LENGTH,
|
||||
minLength: Constants.GLOBALS.MIN_SUBDOMAIN_LENGTH,
|
||||
}
|
||||
),
|
||||
},
|
||||
|
@ -421,7 +421,7 @@ function SubdomainCard({
|
|||
message: t(
|
||||
"organizationSettings.subdomainCard.rules.maxLength",
|
||||
{
|
||||
max: Constants.GLOBALS.MAX_SUBDOMAIN_LENGTH,
|
||||
maxLength: Constants.GLOBALS.MAX_SUBDOMAIN_LENGTH,
|
||||
}
|
||||
),
|
||||
},
|
||||
|
|