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" />
|
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
<meta name="theme-color" content="#000000" />
|
<meta name="theme-color" content="#000000" />
|
||||||
<meta
|
<meta name="description" content="Dashboard for NaviLearn" />
|
||||||
name="description"
|
|
||||||
content="Web site created using create-react-app"
|
|
||||||
/>
|
|
||||||
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
|
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
|
||||||
<!--
|
<link
|
||||||
manifest.json provides metadata used when your web app is installed on a
|
rel="apple-touch-icon"
|
||||||
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
|
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" />
|
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
|
||||||
<!--
|
<title>NaviLearn</title>
|
||||||
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.
|
|
||||||
|
|
||||||
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
|
<script type="text/javascript">
|
||||||
work correctly both with client-side routing and a non-root public URL.
|
(function (c, l, a, r, i, t, y) {
|
||||||
Learn how to configure a non-root public URL by running `npm run build`.
|
c[a] =
|
||||||
-->
|
c[a] ||
|
||||||
<title>App</title>
|
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>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<noscript>You need to enable JavaScript to run this app.</noscript>
|
<noscript>You need to enable JavaScript to run this app.</noscript>
|
||||||
<div id="root"></div>
|
<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>
|
</body>
|
||||||
</html>
|
</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",
|
"short_name": "NaviLearn",
|
||||||
"name": "Create React App Sample",
|
"name": "NaviLearn",
|
||||||
"icons": [
|
"icons": [
|
||||||
{
|
{
|
||||||
"src": "favicon.ico",
|
"src": "favicon.ico",
|
||||||
|
|
After Width: | Height: | Size: 12 KiB |
180
src/App.tsx
|
@ -1,78 +1,124 @@
|
||||||
import { ConfigProvider, Layout, theme } from 'antd';
|
import { ConfigProvider, Layout, theme } from "antd";
|
||||||
import DashboardLayout from './core/components/DashboardLayout';
|
import DashboardLayout from "./core/components/DashboardLayout";
|
||||||
import { darkMode, primaryColor, setBannerUrl, setLogoUrl, setPrimaryColor, setUserAuthenticated, userAuthenticated, setUserProfilePictureUrl } from './core/reducers/appSlice';
|
import {
|
||||||
import { useDispatch, useSelector } from 'react-redux';
|
darkMode,
|
||||||
import SignIn from './features/Auth/SignIn';
|
primaryColor,
|
||||||
import { useEffect } from 'react';
|
setBannerUrl,
|
||||||
import { myFetch } from './core/utils/utils';
|
setLogoUrl,
|
||||||
import MyCenteredSpin from './shared/components/MyCenteredSpin';
|
setPrimaryColor,
|
||||||
import webSocketService, { WebSocketMessageHandler } from 'core/services/websocketService';
|
setUserAuthenticated,
|
||||||
import { MessageProvider } from 'core/context/MessageContext';
|
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;
|
const { defaultAlgorithm, darkAlgorithm } = theme;
|
||||||
|
|
||||||
export default function App() {
|
export default function App() {
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
|
|
||||||
const isDarkMode = useSelector(darkMode);
|
const isDarkMode = useSelector(darkMode);
|
||||||
const uAuthenticated = useSelector(userAuthenticated);
|
const uAuthenticated = useSelector(userAuthenticated);
|
||||||
const primColor = useSelector(primaryColor);
|
const primColor = useSelector(primaryColor);
|
||||||
|
|
||||||
console.info(
|
console.info(
|
||||||
'\n %c LMS %c v1.0.0 %c \n',
|
"\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: #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: #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'
|
"background-color: transparent"
|
||||||
);
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (uAuthenticated) {
|
if (uAuthenticated) {
|
||||||
(async () => {
|
(async () => {
|
||||||
try {
|
try {
|
||||||
const response = await myFetch({
|
const response = await myFetch({
|
||||||
url: '/app',
|
url: "/app",
|
||||||
method: 'GET',
|
method: "GET",
|
||||||
});
|
});
|
||||||
|
|
||||||
if (response) {
|
if (response) {
|
||||||
dispatch(setPrimaryColor(`#${response.Organization.PrimaryColor}`));
|
dispatch(setPrimaryColor(`#${response.Organization.PrimaryColor}`));
|
||||||
dispatch(setLogoUrl(response.Organization.LogoUrl));
|
dispatch(setLogoUrl(response.Organization.LogoUrl));
|
||||||
dispatch(setBannerUrl(response.Organization.BannerUrl));
|
dispatch(setBannerUrl(response.Organization.BannerUrl));
|
||||||
dispatch(setUserProfilePictureUrl(response.User.ProfilePictureUrl));
|
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 {
|
|
||||||
dispatch(setUserAuthenticated(true));
|
dispatch(setUserAuthenticated(true));
|
||||||
}
|
|
||||||
}, [dispatch]);
|
|
||||||
|
|
||||||
return (
|
webSocketService.connect();
|
||||||
<Layout style={{ minHeight: '100vh' }}>
|
webSocketService.setHandler(WebSocketMessageHandler, dispatch);
|
||||||
<ConfigProvider
|
}
|
||||||
theme={{
|
} catch (error) {}
|
||||||
algorithm: isDarkMode ? darkAlgorithm : defaultAlgorithm,
|
})();
|
||||||
token: {
|
|
||||||
colorPrimary: primColor,
|
return () => {
|
||||||
},
|
webSocketService.disconnect();
|
||||||
}}
|
};
|
||||||
>
|
}
|
||||||
<MessageProvider>{uAuthenticated == null ? <MyCenteredSpin /> : uAuthenticated ? <DashboardLayout /> : <SignIn />}</MessageProvider>
|
}, [uAuthenticated]);
|
||||||
</ConfigProvider>
|
|
||||||
</Layout>
|
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 />
|
<PageContent />
|
||||||
|
|
||||||
<AiChat />
|
{/* <AiChat /> */}
|
||||||
</Layout>
|
</Layout>
|
||||||
</Layout>
|
</Layout>
|
||||||
</MyDndContext>
|
</MyDndContext>
|
||||||
|
|
|
@ -7,9 +7,25 @@ import { getUserSessionFromLocalStorage } from 'core/utils/utils';
|
||||||
import { Marked, marked } from 'marked';
|
import { Marked, marked } from 'marked';
|
||||||
import { createDirectives, presetDirectiveConfigs } from 'marked-directive';
|
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() {
|
function AiChat() {
|
||||||
const [visible, setVisible] = React.useState(false);
|
const [visible, setVisible] = React.useState(false);
|
||||||
|
|
||||||
|
//const [chatHistory, setChatHistory] = React.useState<MessageContent[]>([{ text: 'Stell mir Fragen :)', role: 'ai' }]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{visible ? (
|
{visible ? (
|
||||||
|
@ -35,7 +51,13 @@ function AiChat() {
|
||||||
position: 'absolute',
|
position: 'absolute',
|
||||||
}}
|
}}
|
||||||
avatars={true}
|
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={{
|
connect={{
|
||||||
url: '/api/chat/v1/prompt/',
|
url: '/api/chat/v1/prompt/',
|
||||||
method: 'POST',
|
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) => {
|
responseInterceptor={async (response: any) => {
|
||||||
let _response = { ...response };
|
let _response = { ...response };
|
||||||
|
|
||||||
|
|
|
@ -6,13 +6,13 @@
|
||||||
background-position: center;
|
background-position: center;
|
||||||
background-repeat: no-repeat;
|
background-repeat: no-repeat;
|
||||||
background-size: cover;
|
background-size: cover;
|
||||||
height: 100%;
|
height: 100vh;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.darkenBackground {
|
.darkenBackground {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
background-color: rgba(0, 0, 0, 0.5);
|
background-color: rgba(0, 0, 0, 0.5);
|
||||||
height: 100%;
|
height: 100vh;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
|
@ -412,7 +412,7 @@ function SubdomainCard({
|
||||||
message: t(
|
message: t(
|
||||||
"organizationSettings.subdomainCard.rules.minLength",
|
"organizationSettings.subdomainCard.rules.minLength",
|
||||||
{
|
{
|
||||||
min: Constants.GLOBALS.MIN_SUBDOMAIN_LENGTH,
|
minLength: Constants.GLOBALS.MIN_SUBDOMAIN_LENGTH,
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
|
@ -421,7 +421,7 @@ function SubdomainCard({
|
||||||
message: t(
|
message: t(
|
||||||
"organizationSettings.subdomainCard.rules.maxLength",
|
"organizationSettings.subdomainCard.rules.maxLength",
|
||||||
{
|
{
|
||||||
max: Constants.GLOBALS.MAX_SUBDOMAIN_LENGTH,
|
maxLength: Constants.GLOBALS.MAX_SUBDOMAIN_LENGTH,
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
|
|